How to...
-
I'm trying to access some methods from my MainClass (class MainWindow : public QMainWindow) from a child called "WidgetMCI" (class WidgetMCI : public QWidget).
I couldn't do that because I don't have any reference to the WidgetMCI Parent!
I try some things to fix it problem, but I couldn't find a good way to resolve my problem.Some explanations:
- In MainWindow I have the object to use the serial port, and need be a unique object over all applicaton;
- I need to access the MainWindow to get this "serial port" object on the childs, Some QWidgets...
-
If it's an object unique in the entire application (in your case probably a serial port handler that for example handles queued commands/replies), then don't make it MainWindow-Local but a singleton (google that if you're not familiar with the pattern).
With the singleton, you will have access to it from all places that see the class definition. Your case is one of the few where a singleton is appropriate.
-
A Singleton is one possibility...
But why don't you just give WidgetMCI the reference to MainWindow?
I guess you are creating the WidgetMCI-object from inside MainWindow, so you could just set MainWindow as parent in the WidgetMCI-constructor, and inside WidgetMCI cast it back to QMainWindow... -
Hello.
I have two suggestions:If your WidgetMCI is a child of MainWindow then just use "QObject::parent":http://qt-project.org/doc/qt-4.8/qobject.html with futher cast to MainWindow*.
If you don't use this feature of QObject then just add some method which sets parent to your WidgetMCI class. If you use Designer to design your UI, then you might not have any "direct" reference to you WidgetMCI object. But you may use "QObject::findChild":http://qt-project.org/doc/qt-4.8/qobject.html#findChild method. Of cause if you have multiple WidgetMCI objects and multiple ports then you have to give each WidgetMCI object an unique name to use with QObject::findChild.
Also I think that using of singleton is not a good idea just because it's not the simplest way. But I may be wrong.
-
[quote author="Wilk" date="1343032340"]
Also I think that using of singleton is not a good idea just because it's not the simplest way. But I may be wrong.[/quote]
Don't confuse simplicity with less lines of code. If it is done like you say you create a dependence of WidgetMCI on the whole MainWindow class and all that's associated with it. This is actually not simplicity. Simplicity is decoupling the serial port handler and have all objects who need it, access it either by a static singleton function or by direct dependency injection of the handler, not its parent QMainWindow. This way you can change MainWindow later, or even reuse WidgetMCI with a completely different MainWindow, without breaking it. -
AFAIK usualy you won't reuse your WidgetMCI class. Just because such classes are rarely reused. Furthermore, if you will ever need class with such functionality you'd better create a new one class that is targeting general purpose instead of creating such general purpose class each time. I understand that OOP aims to make code reusable, but in this case it's OOP for OOP, nothing more. I found out it from my own experience: when you create a concrete system for concrete purpose it's difficult to make it's components independent from each other. Just because they are strongly connected within the system. So the best decision to create some no-reusable classes at least for the first time just to understand what should be reused and what should not.
Another way is to make this (probably small) system independent instead of creating a group of very flexible but difficult to use classes. For example in this case with WidgetMCI and MainWindow I can see a little bit better solution: create a small class PortServer which opens port and do whatever is needed and PortClient, which "asks" PortServer for opened port. And then you make MainWindow derived from PortServer and WidgetMCI derived from PortClient. This way both of your classes are independent from each other while you have a very reusable part of code. Furthermore, this approach let's you make PortServer and PortClient abstract so that you may use any kind of port, not just serial port.
And I don't confuse simplicity with less lines of code. I'm just not sure about singleton patern. At least in this case. -
Binding that port server to the MainWindow still is bad. What if you want other windows derived from QMainWindow to be able to use that port? Or provide a non-GUI mode in your application logic? You'd duplicate two servers and the second one would fail to connect to the port. No, the serial port is a resource and shouldn't be bound to your main window, even if some people mistake a main window with "the application". So when you say
"I have the object to use the serial port, and need be a unique object over all applicaton;" like in the very first post, you are asking for a singleton, and it's the right thing to use here. -
bq. What if you want other windows derived from QMainWindow to be able to use that port?
I won't inherit it from PortServer, I'll inherit it from PortClient.
But yes, I was wrong and now agree with you thatbq. the serial port is a resource and shouldn’t be bound to your main window
However I still think that this singleton should not be explicit because it may be less flexible. I guess possible approach is to hide such singleton resource within Server and provide an interface to work with it. The reason I see for it is that you may work with multiple ports and it might be difficult to add new ports in our application, while if you have some common access point for all resources you may use them more easily. Using this approach we may create as much PortServers as we need.
Obviously all this PortServer and PortClient represent a useless abstraction layer for a small educational or "just for fun" applications, but it may make some code simplier. For example you may process specific port errors inside PortServer, and give it's client a good error message. -
I prefer use the singleton way... always I use on Java and I would like to use on C++, but I could not do that, it's not easy to make that... I got some error, check out:
@
#ifndef SINGLETONPORTASERIAL_H
#define SINGLETONPORTASERIAL_H#include "qextserialport.h"
class SingletonPortaSerial
{
public:
static SingletonPortaSerial* getInstance();
QextSerialPort* getPortaSerial();private:
SingletonPortaSerial();
static SingletonPortaSerial* pSingleton;
static QextSerialPort* portaSerial;
};#endif // SINGLETONPORTASERIAL_H
@@
#include "singletonportaserial.h"SingletonPortaSerial::SingletonPortaSerial()
{}
SingletonPortaSerial* SingletonPortaSerial::getInstance()
{
if (pSingleton == NULL)
{
pSingleton = new SingletonPortaSerial();
}
return pSingleton;
}QextSerialPort* SingletonPortaSerial::getPortaSerial()
{
if (portaSerial == NULL)
{
portaSerial = new QextSerialPort();
}
return portaSerial;
}
@Error:
.../singletonportaserial.o:-1: In functionSingletonPortaSerial::getInstance()': .../singletonportaserial.cpp:-1: error: undefined reference to
SingletonPortaSerial::pSingleton'
.../singletonportaserial.cpp:-1: error: undefined reference toSingletonPortaSerial::pSingleton' .../singletonportaserial.o:-1: In function
SingletonPortaSerial::getPortaSerial()':
.../singletonportaserial.cpp:-1: error: undefined reference toSingletonPortaSerial::portaSerial' .../singletonportaserial.cpp:-1: error: undefined reference to
SingletonPortaSerial::portaSerial'
:-1: error: collect2: ld returned 1 exit status -
Hello.
You should add this:
@
SingletonPortaSerial* SingletonPortaSerial::pSingleton = NULL;
QextSerialPort* SingletonPortaSerial::portaSerial = NULL;
@
into your implementation file. -
I added to .cpp file and appers to fix the problem.
Why this is necessary?Thanks Wilk, DerManu and Mr.Universe! Thank you all!
-
Also I suggest you not to re-implement implementation of singleton and use one of provided "here":http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern.
-
[quote author="dcbasso" date="1343138037"]I added to .cpp file and appers to fix the problem.
Why this is necessary?Thanks Wilk, DerManu and Mr.Universe! Thank you all![/quote]
Actually I don't know how is it realy called, at least in English. Or don't remember. (Shame on me!) AFAIK it grows from old good C where you must not just declare static variable but also initialize it. (Probably it's called initialization?)