QObject generic interface in Qt - c++

I have an interface class in C++ that consists of pure virtual member functions, which I want to make parent of all the QWidgets in my app. It has lots of signals and slots, so it must inherit from QObject. The problem is that I can't make my other objects derive from this:
class Interface : public QObject {
public slots:
virtual void slotA() = 0;
signals:
void signalA();
};
Now if I want to create a widget implementing this interface I would need to do something like
class MyWidget : public QWidget, public Interface {
};
This however can't be done because it can't inherit twice from QObject. How can I do this?
Note: QObject Multiple Inheritance does not answer to this as it does not post a satisfatory answer in my opinion

Related

Qt signal-slot duplication code avoidance

I would like to share signals and possibly slot implementations among different classes, but it seems Qt does not allow this.
Basically I would like to have something like:
class CommonSignals
{
signals:
void mysignal();
};
class A :
public QObject,
public CommonSignals
{
Q_OBJECT
public:
void doSomething()
{
emit mysignal();
}
};
class B :
public QObject,
public CommonSignals
{
Q_OBJECT
public:
B()
{
connect(&a, &A::mysignal, this, &B::mysignal);
}
A a;
};
So that when for some reason A emits a signal B emits the same signal too. This to avoid useless code replication and improve maintainability.
Any ideas?
PS I've tried also with virtual inheritance but I've got classical qmake problems
You cannot do this. QObject cannot be used with multiple inheritance of multiple QObject bases. Only the first inherited class can be a QObject. See:
https://doc.qt.io/qt-5/moc.html#multiple-inheritance-requires-qobject-to-be-first
Since you need both base classes to be a QObject (CommonSignals provides signals, it would need to be a QObject), you're out of luck. Your only option here is using plain old macros:
#define COMMON_SIGNALS \
void signal1(); \
void signal2();
class A: public QObject
{
Q_OBJECT
public:
// ...
signals:
COMMON_SIGNALS
};
class B: public QObject
{
Q_OBJECT
public:
// ...
signals:
COMMON_SIGNALS
};
The core issue with all this is that Qt uses moc to generate the underlying code for signals and slots. However, moc is just a simple preprocessor that doesn't understand most of C++.
You could use Verdigris to get rid of moc:
https://github.com/woboq/verdigris
This allows you to have templated QObject classes, for example. I have not tried it myself and thus don't know if it actually allows multiple inheritance. Might be worth looking into.
Why not just move the inheritance from QObject away from the derived classes A and B and into CommonSignals...
class CommonSignals: public QObject {
Q_OBJECT;
signals:
void mysignal();
};
class A: public CommonSignals {
Q_OBJECT;
public:
void doSomething ()
{
emit mysignal();
}
};
class B: public CommonSignals {
Q_OBJECT;
public:
B ()
{
connect(&a, &A::mysignal, this, &B::mysignal);
}
A a;
};
Will that not work for you?

Why does Qt default signals to be public?

I've realized today that if you have 3 classes like so:
class 1 has a signal
class 2 has a signal that connects to class 3's private slot
class 3 has a private slot and class 2 is a friend of class 3
If I connect class 1's signal to class 2's signal, I can essentially call class 3's private slot by emitting class 1's signal.
If signals were private or protected this wouldn't occur.
There's another scenario where this can be bad, imagine we have this setup:
class 1 has a signal
class 2 has a signal that connects into it's base classes protected slot
class 3 is the base class with a protected slot
Doesn't this break Object Oriented Principles?
woboq mentions this:
Signals were protected in Qt4 and before. They are becoming public in Qt5 in order to enable the new syntax.
You can create a private / protected helper object with the 'private' signal:
class Helper : public QObject
{
Q_OBJECT
public:
Helper(QObject *parent) : QObject(parent) { }
signals:
void MyPrivateSignal();
};
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass()
: QObject(),
helper(new Helper(this))
{
connect(helper, &Helper::MyPrivateSignal, this, &MyClass::MyPrivateSlot);
}
private slots:
void MyPrivateSlot();
private:
void InvokeMyPrivateSignal()
{
emit helper->MyPrivateSignal();
}
private: // or protected:
Helper *helper;
};
Anyone can connect to Helper::MyPrivateSignal() of a Helper instance, but not to your Helper instance, because only you know that one.

automatic call of retranslateUi

I have a base myClass class which inherits QMainWindow
class myClass : public QMainWindow {
Q_OBJECT
public:
myClass(QWidget *par):QMainWindow(par);
~myClass(){};
}
and a bunch of subclasses which inherits from and are private members of their corresponding ui e.g.:
#include "ui_myPluginUi.h"
class myPlugin : public myClass, private Ui::myPluginUi {
Q_OBJECT
public:
Q_INVOKABLE myPlugin(QWidget *par): myClass(par), ;
~myPlugin(){};
}
So that I cas access my Ui widget easily.
My base class myClass has a lot of methods that load/save window preferences, do some connection on special widgets, decorate windows, load help pages for that window etc...
Most of them uses the wonderful retrospection of the qt-metasystem. One thing that I didn't succeed if to call retranslateUi from the base class.
I started reimplementing the changeEvent:
void myClass::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
for(int i = 0; i < metaObject()->methodCount(); ++i)
qDebug() << i << metaObject()->method(i).methodSignature();
break;
default:
break;
}
}
but retranslateUi is not part of the methods...
I've seen that the UI class which implements retranslateUi is not a QObject and retranslateUi is not a public slot so I doubt there is a way unless there is a super-magical-qt-guru-move to do.
Edited after #Kevin-Kremmer answer below:
If I add
private slots:
virtual void retranslateUi(QMainWindow*) = 0;
I get a couple of errors error: allocating an object of abstract class type 'myClass' since I'm also able to create pure MyClass objects and decorate them via plain ui file via QUiLoader ...
and if I define a
private slots:
virtual void retranslateUi(QMainWindow*) {};
that is the only one that the metasystem sees and calls...
(hope to be clear enough)
You could try this
// in myClass
private slots:
virtual void retranslateUi(QMainWindow*) = 0;

Q_OBJECT generates many errors

This class no problem:
#include <QThread>
class LiveImageItem : public QThread
{
Q_OBJECT
public:
LiveImageItem(QPixmap pimg);
signals:
public slots:
};
BUT this class get problem associated with "Q_OBJECT" macro defined in header file
#include <QGraphicsPixmapItem>
class LiveImageItem : public QGraphicsPixmapItem
{
Q_OBJECT //this line will generate many errors in compiling
public:
LiveImageItem(QPixmap pimg);
signals:
public slots:
};
both their cpp file is the same:
#include "LiveImageItem.h"
LiveImageItem::LiveImageItem(QPixmap pimg)
{
}
I thought every QT object essentially inherited from QObject so if I inherit any of the subclass of QObject, I could have all the magics QObject offers. The 2nd version of the above (which is inherited from, say, QGraphicsPixmapItem) seems proved I was wrong. It turns out to be having lots of errors while compiling, all from moc files(automatically generated by QT). What happens?
Some of these errors are:
[qobject.h] error: 'QScopedPointer QObject::d_ptr' is
protected
[moc_LiveImageItem.cpp] error: within this context
...
According to the documentation QGraphicsPixmapItem is not a QObject, thus you cannot treat it as if it is. I would try to extend your class inheritance and do:
class LiveImageItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT //this line will generate many errors in compiling
[..]
As #vahancho said, QGraphicsPixmapItem is not a QObject. In fact, that can be said of most of the QGraphics*Item classes.
However, if you want to use signals and slots with QGraphicsSystem classes, you can inherit from QGraphicsObject: -
class LiveImageItem : public QGraphicsObject
{
Q_OBJECT
public:
private:
QPixmap m_pixmap;
};
You would then override the paint function in this class and draw the pixmap from there.

How do I share code via class structure in C++?

I am writing for the Qt framework and I want to create a QWidget. QWidget exposes some interfaces such as mousePressEvent and mouseReleaseEvent. I want to extend this class to allow mouseClickEvent and mouseDoubleClickEvent. Normally, you would think to extend QWidget and implement those functions. The problem is that there are other classes (QPushButton for example) provided as part of the library which extend QWidget. Therefore, how do I get that added functionality into those classes without having to extend each one and copy the code?
class ClickHandeler : public QWidget {
virtual void mouseClickEvent();
virtual void mouseDoubleClickEvent();
int clickCount; //initialized to 0;
void mouseReleaseEvent(QEvent *event){
clickCount++;
QTimer::singleShot(500, this, SLOT(checkClick()));
}
void checkClick(){
if (clickCount == 2){
this->mouseDoubleClickEvent();
clickCount = clickCount-2;
} else {
this->mouseDoubleEvent()
clickCount--;
}
}
}
// QPushButton inherits QWidget too! Yikes!
class MyPushButton : public QPushButton, public ClickHandeler {
void mouseClickEvent(){
alert("i have been clicked");
}
void mouseDoubleClickEvent(){
alert("i have been double clicked");
}
}
I want something like MyPushButton, but I am worried that the function overriding will not work as expected.
Im sorry if this question is obvious to people, but I do not know what the terminology is. I have googled interfaces for c++ and I get abstract interfaces (which doesnt properly solve this problem). If I'm just being stupid and need to know a better term for google, let me know in the comments and Ill remove the question.
I think you just need to extend the QWidget and call the QWidget same functions.
For example:
class QWidget {
public:
void mouseClickEvent();
};
class QPushButton {
public:
void mouseClickEvent();
};
class MyWidget : public QWidget, public QPushButton {
public:
void mouseClickEvent()
{
//base::mouseClickEvent();// ambiguous
QWidget::mouseClickEvent();
QPushButton::mouseClickEvent();
/* Do your own code here */
}
};