Multiple inheritance of QObject because of access to deleteLater() method - qt

I use observer-observable pattern in my program. Everything worked before I had to change the code a little. If to be exact I changed the inheritance of IObserver class - right now it inherits QObject:
class IObserver : public QObject
{
...
I did it because of only one thing - I need deleteLater() method to be used in an observer, so I would be able to call implementation of virtual function deinitialization() of IObserver. Thus I could standardize every IObserver message handler.
The problem is, I already inherited QObject (indirectly) in some Observer classes. Like MainForm or AboutDialog. Everything is going fine until I try to call "connect" method in AboutDialog class.
What can I do? I really need this deleteLater() method since I can't use "delete this" in IObserver code - this will call IObserver destructor, not the MainForm or Storage classes for instance.
Thank you.

I really need this deleteLater() method since I can't use "delete this" in IObserver code - this will call IObserver destructor, not the MainForm or Storage classes for instance.
If you make your destructor virtual (and you should!) it will call the derived destructor just fine. But a problem is that destructing a object while it is handling some signal/slot might cause problems with the event loop. You would have to be very careful with delete this anyway.
The problem is, I already inherited QObject (indirectly) in some Observer classes.
One way you could implement this, not sure if the best thought:
template <typename Derived>
class IObserver
{
// Just to be sure: (C++11)
static_assert(is_base_of<Derived, QObject>::value,
"must inherit from QObject when using IObserver");
void deleteMe()
{
QObject* thisObject = dynamic_cast<QObject*>(this);
// no need for check if thisObject equals null. static assert does this.
thisObject->deleteLater();
}
};
class MainForm : public IObserver<MainForm>, public QMainWindow
{
// ...
};
I believe this pattern is called static polymorphism.

Abandon inheritance of QObject for IObserver. Instead of that add such method to interface.
class IObserver : public QObject {
public:
QObject *object() const = 0;
...
Then if implementation of interface inherits the QObject you will return this pointer from object() method. If implementation of interface doesn't inherit QObject you can simply return pointer to some simple QObject which will handle destruction of this object.
Then you can simply connect deleteLater for object returned by this method.
Off topic
Use of interfaces for observing in Qt usually is obsolete, slots and signals do this job perfectly and this is more flexible approach.

Related

No such slot when connecting widget signal with parent widget slot

I have the following classes:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QStringList pluginsToStart, QWidget *parent = 0);
~MainWindow();
// some other stuff
public slots:
void on_timeDataChanged(logging::TimeValueVector<bool>& aData);
void on_importStarted();
}
and
class DataImporterWidget : public PluginWidget
{
Q_OBJECT
public:
explicit DataImporterWidget(QWidget *parent = 0);
~DataImporterWidget();
void initConnections(QMap<QString, PluginWidget*> pluginWidgetMap);
in the method initConnections, I want the widget to init the signal-slot connections like so:
void DataImporterWidget::initConnections(QMap<QString, PluginWidget*> pluginWidgetMap)
{
for(Importer* importer : this->getImporterMap().values())
{
connect(importer, SIGNAL(signal_timeDataChanged(logging::TimeValueVector<bool>&)),
parentWidget(), SLOT(on_timeDataChanged(logging::TimeValueVector<bool>&)));
}
connect(this, SIGNAL(signal_importStarted()), parentWidget(), SLOT(on_importStarted()));
}
Importer is a QGroupBox and a base class for derived sub classes specifying concrete data importer types.
It works like so: If I press a button, an DataImporterWidget is created and added to a QMdiArea as a QMdiSubWindow. When creating the DataImporterWidget I call the initConnections() method which sets up the signal-slot connections.
Now, when I run the program, I get the following message:
QObject::connect: No such slot
QMdiSubWindow::on_timeDataChanged(logging::TimeValueVector<bool>&) in src/dataimporter/DataImporterWidget.cpp:81
QObject::connect: No such slot QMdiSubWindow::on_importStarted() in src/dataimporter/DataImporterWidget.cpp:85
QObject::connect: (sender name: 'DataImporterWidget')
I do not understand why I get it because the slot is there. Even if I cast the parentWidget to the MainWindow, I get the same error.
PluginWidget is just a base class deriving from QWidget that holds some common functionality for my used plugins.
I put Q_OBJECT on each base and derived class but still get this error. However, if I set up the connections in the MainWindow, it works just fine, but I wonder why the above solution won't work.
Don't create the connection from child object, instead create it from parent object code after creating the child object.
This way you won't need to cast any type.
You did not shown a huge chunk of important code (like creating DataImporterWidget, setting MainWindow as its parent, the place where you call initConnections...). However, you said
If I use the new signal slot syntax, my program crashes with a
segmentation fault...
If it crashes, than you have to find a reason why. Using old signal-slot connect syntax does not cure the disease, it just delay its manifestation. According to this, the reason why you get a segfault can be parentWidget() == nullptr or parent is not initialized yet.
My advice, check your code, and make user the parent of DataImporterWidget is created and specified before your call initConnections().
I've found the problem. The reason is, that the MainWidget class holds a QMdiArea where I add my PluginWidgets. So, when I create the PluginWidget, I set the MainWidget as its parent, but as soon as I add it to the QMdiArea, it also becomes a child of QMdiSubWindow. The parentWidget was never null but it was the wrong one ...

compiler error C2248:'QObject::Qobject':cannot access private member declared in class 'QObject'

Hi Everyone i have a foo class
Code in foo.h
namespace GUI
{
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo(QObject *parent = 0);
virtual ~Foo();
....
};
}
Now this is working and compiling fine but i want to save this custom c++ class using QSettings and one of the step is registering your class with Q_DECLARE_METATYPE
and therefore as soon as i put this line
Q_DECLARE_METATYPE(Foo)
at the end of my foo.h file i get these compiler error C2248:'QObject::Qobject':cannot access private member declared in class 'QObject' and which when clicked only takes me to last line of my connection.h header file and gives no other information as to what might be wrong i,e the error point me to
Class Foo
{
};<---- point me here
Q_DECLARE_METATYPE(Foo)
I know that QObject cannot be copied and this is related to it but i have no idea what maybe wrong here and how can i rectify it.
Thanks in advance
I know that QObject cannot be copied and this is related to it but i have no idea what maybe wrong here and how can i rectify it.
It is related. Q_DECLARE_METATYPE requires your type to be copiable, but your type inherits from QObject, so you can't do that. Sure, you could instead Q_DECLARE_METATYPE(Foo*), but I think you should instead move the settings into a separate value class, which then you can save using QSettings.
Make sure your Q_DECLARE_METATYPE statement is outside of your namespace and that you fully qualify your class name. See the Q_DECLARE_METATYPE doc for more detail.
namespace GUI
{
class Connection : public QObject
{
...
};
}
Q_DECLARE_METATYPE(GUI::Connection)
I know that QObject cannot be copied and this is related to it but i
have no idea what maybe wrong here and how can i rectify it.
So declare a copy constructor, then it will be ok.
...
Foo(const Foo &_other);
...

Q_OBJECT "copying" - copy all properties instead

As we all know, Q_OBJECTs are instances and are not copyable.
Is there any kind of syntactic sugar to copy all static and dynamic properties of an arbitrary QObject derived class?
It seems such a nobrainer, but I can't find any reference to such - obviously implementing one myself should be quite trivial - loop over metaObject(), loop over dynamicPropertyNames(), set accordingly.
You could implement a copy helper class as follows.
/** Enable QObjects to be explicitly copyable by copying property values. */
template<class T>
class QObjectCopyHelper<T>
{
protected:
explicit QObjectCopyHelper(T *client) : m_client(client) {}
public:
T *clone(QObject *parent = 0) {
T *copy = new T(parent);
// loop over and copy properties from m_client to copy
// (both from T::staticMetaObject and dynamic ones)
return copy;
}
private:
T *m_client; // <-- I think we need this, but I might be wrong
};
Then you can use this in any QObject subclass with very low work needed to be done:
class MyClass : public QObject, public QObjectCopyHelper<MyClass>
{
Q_OBJECT
...
};
However, this still needs clone() to be called (the ugly "Java-style"). So we can additionally define a copy constructor just calling clone() and you also might think of a assign() method called within the assignment operator.
Please note that this really copies the properties only! There are a lot of other things being tracked in QObject, like the current connections. They explicitly forbid copying QObjects because it would be very difficult to define rules on how this should be done, and these rules would be the correct ones for some use cases only, while in others you want other rules...
A solution is discussed here, where they take the loop-over-the-properties approach. There seems to be no "syntactic sugar" here.

Connect function to an event

I am trying to create an event handler that executes a function when the page load is done in the QWebView, the syntax i'm using is as follows:
webview->connect(webview,SIGNAL(loadFinished(bool)),this,SLOT(Load_Done()));
This function is created and implemented in a class that i'm using other than the main class if this helps.
The problem is that i'm getting the following:
No such slot QObject::Load_Finished()
It should be QObject::connect(...) not webview->connect. The rest looks fine as long as Load_Done() is defined.
Edit:
To make sure that signals and slots work properly, you need to declare your class that way:
class Facebook: QObject{
Q_OBJECT
public:
// ...
public slots:
void Load_Done();
}
The signal and the slot have to have the same signature, e.g.:
connect(webview,SIGNAL(loadFinished(bool)),this,SLOT(Load_Done(bool)));
Of course, LoadDone(bool) needs to exist in "this" and be a slot :)

Execute Slot in different class

I want to execute a slot in different class. Is it possible
UI_CDSK Obj;
connect(Obj.penDrive,SIGNAL(clicked()),this,SLOT( Obj.caller()));
This code is in different class and from this class i want to execute slot of different class(UI_CDSK )
Here penDrive and caller belongs to function UI_CDSK class and the mentioned code is in other class
It's a little difficult without knowing the internals of UI_CDSK, but the correct syntax should be:
connect( Obj.penDrive, SIGNAL(clicked()), Obj, SLOT(caller()) );
So long as caller() is a public slot in UI_CDSK.
The connect method takes a pointer as receiver object, so if Obj isn't a pointer to a UI_CDSK object :
connect(Obj.pendrive, SIGNAL(clicked()), &Obj, SLOT(caller()));
Also this is probably already done (otherwise your compiler would have complained), but to use Qt signal slots mechanism, your UI_CDSK class must inherit from QObject.
It looks like the slot doesn't need to be public.

Resources