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 */
}
};
Related
Goal
I want to benchmark some drawing libraries and gather diagnostics. I thought of implementing in each benchmark the same interface and then instantiating different classes in the main window.
The Challenge
The problem is that some benchmarks use QWidget and other QOpenGLWidget. So even if I implement the same functionality I can not use it, without dynamic casting to each possible instance.
What I tried so far
My first thought was to create an interface and use virtual multiple inheritance. But that doesn't seem to work and I am not sure if that's even the right solution.
I also thought of the Composite Pattern or Adapter Pattern, but seem some problems, as I want to override some functions of QWidget like resizeEvent in each benchmark. Of course I could duplicate that code or put it into some non-member function. But maybe there is something more elegant?
QWidgets Addin
class BenchmarkAddin : virtual public QWidget {
public:
BenchmarkAddin() {
connect(&timer_, SIGNAL(timeout()), this, SLOT(update()));
}
double get_fps() {
// use frames_ and time to estimate fps
}
void count_frame() {
++frames_;
}
void set_parameters(int param1_) {
param1_;
}
protected:
void resizeEvent(QResizeEvent* event) override {
init();
}
virtual void init() = 0;
int param1_;
private:
int frames_;
QTimer timer_;
}
Raster Benchmark
class RasterBenchmark : public BenchmarkAddin {
protected:
void init() override {
// create buffers
}
void paintEvent(QPaintEvent* event) override {
// do drawing using param1_
count_frame();
}
}
OpenGL benchmark
class OpenGLBenchmark : virtual public QOpenGLWidget, public BenchmarkAddin {
protected:
void paintGL() override {
// do GL drawing using param1_
count_frame();
}
}
Main Window Example Usage
BenchmarkAddin *widget;
if (benchmark == "raster") {
widget = new RasterBenchmark(this);
else
widget = new OpenGLBenchmark(this);
widget.set_parameters(100);
...
std::cout << widget.get_fps() << std::endl;
Obviously this doesn't work, as QOpenGLWidget doesn't use virtual inheritance for QWidget. Also there is a problem with Qt's object meta system.
Question:
Any idea how I could implement an interface that is both accessible within a subclass of QWidget and QOpenGLWidget?
I'm using QGraphicsScene and I would like to have some items which emit signals when they are moved around.
Unfortunately, QGraphicsPixmapItem doesn't have any signals, so I subclassed it:
class InteractiveGraphicsPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
InteractiveGraphicsPixmapItem();
InteractiveGraphicsPixmapItem(QPixmap pm) : QGraphicsPixmapItem(pm)
{
setFlag(QGraphicsItem::ItemIsMovable, true);
setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton);
}
private:
void mouseMoveEvent(QGraphicsSceneMouseEvent *);
signals:
void moved_by_mouse(QPointF newpos);
};
InteractiveGraphicsPixmapItem::InteractiveGraphicsPixmapItem()
{
}
void InteractiveGraphicsPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *)
{
emit moved_by_mouse(this->pos());
}
However, it is not movable.
If I change it back into a QGraphicsPixmapItem in the main program, and call item->setFlags(QGraphicsItem::ItemIsMovable); it becomes movable. For my custom class, it doesn't.
item = new InteractiveGraphicsPixmapItem(QPixmap(":/img/icon.png"));
scene->addItem(item);
item->setFlags(QGraphicsItem::ItemIsMovable);
A similar question was asked about selectability, and it was suggested that the setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton); must be added to the constructor. It didn't help in my case.
If you override the mouseMoveEvent, and don't call the base class's function, it won't move and you'll have to handle it yourself.
However, simply calling the base class function is all you need here
void InteractiveGraphicsPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent* evt)
{
QGraphicsPixmapItem::mouseMoveEvent(evt);
emit moved_by_mouse(this->pos());
}
Also note that if you override one of the mouse events (press / release / move) you should also handle the others too.
I think I've run into a kind of diamond inheritance problem here.
Qt provides a couple of spin boxes, for integer values, for doubles and also for dates/times. They all derive from QAbstractSpinBox:
#include <QtWidgets/QSpinBox>
class QSpinBox:
public QAbstractSpinBox {
};
#include <QtWidgets/QDoubleSpinBox>
class QDoubleSpinBox:
public QAbstractSpinBox {
};
Now I'd like to add some functionality common to all spin boxes, in this concrete example, a button to revert the spin box to its minimum (hence specialValueText).
So I also derived from QAbstractSpinBox and came up with something like this:
class AbstractRevertibleSpinBox:
public QAbstractSpinBox {
public:
RevertibleSpinBox() {
/* Use abstract base: */
QAction *revertAction = new QAction(this);
QAbstractSpinBox::lineEdit()->addAction(
revertAction, QLineEdit::TrailingAction);
/* ... */
}
public slots:
virtual void revert() = 0;
}
This containts the pure revert() that should implement how to revert the different spin boxes. For example, using setValue(double) for the QDoubleSpinBox or setDate(QDate) for the QDateEdit.
And then I went the obvious way and derived the appropriate classes for all the spin boxes I needed, like these:
class RevertibleSpinBox:
public QSpinBox,
public AbstractRevertibleSpinBox {
protected:
void revert() {
/* Revert 'int' */
setValue(0);
}
};
class RevertibleDoubleSpinBox:
public QDoubleSpinBox,
public AbstractRevertibleSpinBox {
protected:
void revert() {
/* Revert 'double' */
setValue(0.0);
}
};
This obviously does not work as anything in QAbstractSpinBox is ambiguous now. I thought I could resolve it using virtual inheritance and this would work if, e.g. QDoubleSpinBox would virtually derive from its own QAbstractSpinBox. But it doesn't. Also, it would fail with QObject because Qt seems to do a lot of static_cast upwarts there, which also does not work with virtual inheritance.
I also thought of resolving it by making the AbstractRevertibleSpinBox a template class that is passed the distinct spin box type as a template class parameter. The construction would then look like this:
template<class Base>
class AbstractRevertibleSpinBox:
public Base {};
class RevertibleSpinBox:
public AbstractRevertibleSpinBox<SpinBox> { };
This would work, however Qt's moc is very unhappy about template classes. So for example, I cannot connect any signals and slots from within the template class. At least not using the conventional string based SIGNAL()/SLOT() syntax.
Is there any other reasonably elegant way to overcome this problem..?
As indicated right upfront in my comment, I think this is a clear case for the Decorator Pattern if you want an easily extensible feature system, otherwise just inherit from QObject rather than from the base "interface" with pretty much the same code.
I will start with the IMHO worse approaches, supplied in the other answers given:
Subclassing each spin box
This is obviously tiresome and even more important, you will not be able to support any QSpinBox subclass with those as you would always need to create a new subclass for each addition. It is simply an unflexible approach.
Have a parent widget containing the button and spin box
This looks like an unnecessary coupling of two different things, and so you would not be able to reuse spin boxes easily should you trigger them any other way later than through buttons. I think the two concepts should remain distinct and separately managed.
Furthermore, dynamic_casting is wrong as suggested as you should use qobject_cast if any.
Let us have a closer look at the decorator approach:
This is not yet the solution for your case, but it shows pretty well how features can be added (i.e. "decorated") into existing hierarchies. To get a bit more concrete about your use case, let us see what would be what in your particular scenario:
Component: QAbstractSpinBox
Concrete components
QSpinBox
QDoubleSpinBox
QDateTimeEdit
QDateEdit
QTimeEdit
Decorator: AbstractSpinBoxDecorator (this step can be left out in your case)
Concrete Decorator: RevertibleSpinBoxDecorator
Let us get our hands dirty with implementing this design:
main.cpp
#include <QAbstractSpinBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QDateTimeEdit>
#include <QDateEdit>
#include <QTimeEdit>
#include <QPushButton>
#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QWidget>
#include <QShowEvent>
class RevertibleSpinBoxDecorator : public QAbstractSpinBox
{
Q_OBJECT
public:
explicit RevertibleSpinBoxDecorator(QAbstractSpinBox *abstractSpinBox, QAbstractSpinBox *parent = Q_NULLPTR)
: QAbstractSpinBox(parent)
, m_abstractSpinBox(abstractSpinBox)
{
}
public slots:
void revert(bool)
{
QSpinBox *spinBox = qobject_cast<QSpinBox*>(m_abstractSpinBox);
if (spinBox) {
spinBox->setValue(spinBox->minimum());
return;
}
QDoubleSpinBox *doubleSpinBox = qobject_cast<QDoubleSpinBox*>(m_abstractSpinBox);
if (doubleSpinBox) {
doubleSpinBox->setValue(doubleSpinBox->minimum());
return;
}
QDateEdit *dateEdit = qobject_cast<QDateEdit*>(m_abstractSpinBox);
if (dateEdit) {
dateEdit->setDate(dateEdit->minimumDate());
return;
}
QTimeEdit *timeEdit = qobject_cast<QTimeEdit*>(m_abstractSpinBox);
if (timeEdit) {
timeEdit->setTime(timeEdit->minimumTime());
return;
}
QDateTimeEdit *dateTimeEdit = qobject_cast<QDateTimeEdit*>(m_abstractSpinBox);
if (dateTimeEdit) {
dateTimeEdit->setDateTime(dateTimeEdit->minimumDateTime());
return;
}
Q_ASSERT_X(false, "decorator", "concrete component unimplemented");
}
protected:
void showEvent(QShowEvent *event) Q_DECL_OVERRIDE
{
m_abstractSpinBox->show();
event->ignore();
hide();
}
private:
QAbstractSpinBox *m_abstractSpinBox;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
connect(pushButton, &QPushButton::clicked, revertibleSpinBoxDecorator, &RevertibleSpinBoxDecorator::revert);
QHBoxLayout *layout = new QHBoxLayout(centralWidget);
layout->addWidget(revertibleSpinBoxDecorator);
layout->addWidget(pushButton);
setCentralWidget(centralWidget);
}
private:
QWidget *centralWidget{new QWidget(this)};
QDoubleSpinBox *doubleSpinBox{new QDoubleSpinBox(this)};
RevertibleSpinBoxDecorator *revertibleSpinBoxDecorator{new RevertibleSpinBoxDecorator(doubleSpinBox)};
QPushButton *pushButton{new QPushButton(this)};
};
#include "main.moc"
int main(int argc, char **argv)
{
QApplication application(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return application.exec();
}
If you want to get rid of the QAbstractSpinBox inheritance, you will need to apply a bit more glue and IMHO for not much gain, while losing the flexibility. You would start off with something like this:
Non-Decorator
#include <QAbstractSpinBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QDateTimeEdit>
#include <QDateEdit>
#include <QTimeEdit>
#include <QPushButton>
#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QWidget>
#include <QShowEvent>
class RevertibleSpinBoxDecorator : public QObject
{
Q_OBJECT
public:
explicit RevertibleSpinBoxDecorator(QAbstractSpinBox *abstractSpinBox, QObject *parent = Q_NULLPTR)
: QObject(parent)
, m_abstractSpinBox(abstractSpinBox)
{
}
public slots:
void revert(bool)
{
QSpinBox *spinBox = qobject_cast<QSpinBox*>(m_abstractSpinBox);
if (spinBox) {
spinBox->setValue(spinBox->minimum());
return;
}
QDoubleSpinBox *doubleSpinBox = qobject_cast<QDoubleSpinBox*>(m_abstractSpinBox);
if (doubleSpinBox) {
doubleSpinBox->setValue(doubleSpinBox->minimum());
return;
}
QDateEdit *dateEdit = qobject_cast<QDateEdit*>(m_abstractSpinBox);
if (dateEdit) {
dateEdit->setDate(dateEdit->minimumDate());
return;
}
QTimeEdit *timeEdit = qobject_cast<QTimeEdit*>(m_abstractSpinBox);
if (timeEdit) {
timeEdit->setTime(timeEdit->minimumTime());
return;
}
QDateTimeEdit *dateTimeEdit = qobject_cast<QDateTimeEdit*>(m_abstractSpinBox);
if (dateTimeEdit) {
dateTimeEdit->setDateTime(dateTimeEdit->minimumDateTime());
return;
}
Q_ASSERT_X(false, "strategy", "strategy not implemented");
}
private:
QAbstractSpinBox *m_abstractSpinBox;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = Q_NULLPTR) : QMainWindow(parent)
{
connect(pushButton, &QPushButton::clicked, revertibleSpinBoxDecorator, &RevertibleSpinBoxDecorator::revert);
QHBoxLayout *layout = new QHBoxLayout(centralWidget);
layout->addWidget(doubleSpinBox);
layout->addWidget(pushButton);
setCentralWidget(centralWidget);
}
private:
QWidget *centralWidget{new QWidget(this)};
QDoubleSpinBox *doubleSpinBox{new QDoubleSpinBox(this)};
RevertibleSpinBoxDecorator *revertibleSpinBoxDecorator{new RevertibleSpinBoxDecorator(doubleSpinBox)};
QPushButton *pushButton{new QPushButton(this)};
};
#include "main.moc"
int main(int argc, char **argv)
{
QApplication application(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return application.exec();
}
main.pro
TEMPLATE = app
TARGET = main
QT += widgets
CONIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
I don't think I would use inheritance here at all; instead I'd use composition: create an unrelated class (e.g. derived from QWidget) that uses a QBoxLayout (or similar) to arrange the spin-box and the button as child widgets. The appropriate spin-box object-pointer could be passed to the class's constructor, which would also do the necessary connect() commands to forward the various signals back and forth. You'd probably want to redeclare equivalents for the QAbstractSpinBox class's slots/signals/methods in your class, of course, but the upside is that it would work with any of the QAbstractSpinBox sub-classes.
(As for getting revert() to do the right thing, the easiest approach might be just some ugly special-case logic using dynamic_cast<> -- since there are only three QAbstractSpinBox subclasses you need to support, that will be manageable, and at least that way the ugliness is hidden inside a private method body rather than being exposed to the class's users)
One option to consider might be to simply create classes that derive from each of QSpinBox, QDoubleSpinBox and QDateEdit and then extract the common code into functions.
Using QSpinBox as an example:
class RevertibleSpinBox : public QSpinBox
{
public:
RevertibleSpinBox(QWidget* parent) : QSpinBox(parent)
{
RevertibleSpinBoxHelpers::installRevertAction(lineEdit(), this);
}
public slots:
void revert()
{
setValue(0);
}
// etc.
};
namespace RevertibleSpinBoxHelpers
{
void installRevertAction(QLineEdit* target, QObject* handler)
{
QAction* revertAction = new QAction(handler);
target->addAction(revertAction, QLineEdit::TrailingAction);
QObject::connect(revertAction, SIGNAL(triggered()), handler, SLOT(revert()));
}
}
Disclaimer: If your needs are more complicated than you alluded to in your question, then this might not be the best approach.
IMO you are complicating your life unnecessarily. Even the decorator pattern is overkill, much less all that needless inheritance and design woes. All you need is a nifty auxiliary function:
void revert(QAbstractSpinBox * box) {
QSpinBox * spin = qobject_cast<QSpinBox *>(box);
if (spin) { spin->setValue(spin->minimum()); return; }
QDateTimeEdit * dt = qobject_cast<QDateTimeEdit *>(box);
if (dt) { dt->setDateTime(dt->minimumDateTime()); return; }
// and so on...
qDebug() << "you should not be seeing this";
return;
}
Wrap that as a static method of a Reverter object if you want to have something to instantiate alongside the spinbox.
You could make that a slot if you put it in a QObject derived class, but that's really not neccesary, since in Qt you can connect to free functions and methods of non-QObject derived classes. Or you can simply call it from slots if you so choose:
public slots:
void revertSpinBoxA() { revert(spinBoxA); }
void revertSpinBoxB() { revert(spinBoxB); }
This is similar to the decorator pattern, but it does come with a few advantages:
it only provides the extra functionality for all objects of an inheritance hierarchy,
which means you can save yourself the effort of having to reimplement existing functionality, you can directly use that of the object passed
you only need one Reverter to revert any number of spinboxes, with the decorator you will need n number of decorators for n number of spinboxes, it will use up more memory, which might not be fatal but is needless overhead, since the type casting inside the revert method makes the actual decorator totally redundant. The difference is with the decorator, you will have the original object + a decorator for each one which you use as a controller for the object, while in this solution you still use the actual object, and only pass it through the Reverter for the extra functionality. Less work, less code, less complexity, less memory used.
I would like to derive all of my widgets from a base class widget that automatically establishes a signal/slot connection between a slot for the class and a (rarely called) signal.
The slot is a virtual function, so that any widgets for which I wish to implement custom functionality can derive from the virtual slot function. In the desired scenario, all my widgets would derive from this base class with the virtual slot, so that by default all of my widget instances would be connected to the desired signal with a slot defined for the object (with default behavior from the base class).
I know that virtual slots are allowed in Qt. However, deriving from two QObject classes is not supported, so that, for example, the following code is disallowed:
class MySignaler : public QObject
{
Q_OBJECT
public:
MySignaler : QObject(null_ptr) {}
signals:
void MySignal();
}
MySignaler signaler;
class MyBaseWidget: public QObject
{
Q_OBJECT
public:
MyBaseWidget() : QObject(null_ptr)
{
connect(&signaler, SIGNAL(MySignal()), this, SLOT(MySlot()));
}
public slots:
virtual void MySlot()
{
// Default behavior here
}
}
// Not allowed!
// Cannot derive from two different QObject-derived base classes.
// How to gain functionality of both QTabWidget and the MyBaseWidget base class?
class MyTabWidget : public QTabWidget, public MyBaseWidget
{
Q_OBJECT
public slots:
void MySlot()
{
// Decide to handle the signal for custom behavior
}
}
As the sample code demonstrates, it seems impossible to gain both the benefits of (in this example) the QTabWidget, and also the automatic connection from the desired signal function to the virtual slot function.
Is there some way, in Qt, to have all my application's widget classes share common base-class slot and connect() functionality while allowing my widgets to nonetheless derive from Qt widget classes such as QTabWidget, QMainWindow, etc.?
Sometimes when inheritance is problematic, one can replace it, or a part of it, with composition.
That's the approach needed in Qt 4: instead of deriving from a QObject, derive from a non-QObject class (MyObjectShared) that carries a helper QObject that is used as a proxy to connect the signal to its slot; the helper forwards that call to the non-QObject class.
In Qt 5, it is not necessary to derive from a QObject at all: signals can be connected to arbitrary functors. The MyObjectShared class remains the same.
Should Qt 4 compatibility be generally useful in other areas of the code, one can use a generic connect function that connects signals to functors in both Qt 4 and Qt 5 (in Qt 4, it would use an implicit helper QObject).
// https://github.com/KubaO/stackoverflown/tree/master/questions/main.cpp
#include <QtCore>
#include <functional>
#include <type_traits>
class MySignaler : public QObject {
Q_OBJECT
public:
Q_SIGNAL void mySignal();
} signaler;
#if QT_VERSION < 0x050000
class MyObjectShared;
class MyObjectHelper : public QObject {
Q_OBJECT
MyObjectShared *m_object;
void (MyObjectShared::*m_slot)();
public:
MyObjectHelper(MyObjectShared *object, void (MyObjectShared::*slot)())
: m_object(object), m_slot(slot) {
QObject::connect(&signaler, SIGNAL(mySignal()), this, SLOT(slot()));
}
Q_SLOT void slot() { (m_object->*m_slot)(); }
};
#endif
class MyObjectShared {
Q_DISABLE_COPY(MyObjectShared)
#if QT_VERSION < 0x050000
MyObjectHelper helper;
public:
template <typename Derived>
MyObjectShared(Derived *derived) : helper(derived, &MyObjectShared::mySlot) {}
#else
public:
template <typename Derived, typename = typename std::enable_if<
std::is_base_of<MyObjectShared, Derived>::value>::type>
MyObjectShared(Derived *derived) {
QObject::connect(&signaler, &MySignaler::mySignal,
std::bind(&MyObjectShared::mySlot, derived));
}
#endif
bool baseSlotCalled = false;
virtual void mySlot() { baseSlotCalled = true; }
};
class MyObject : public QObject, public MyObjectShared {
Q_OBJECT
public:
MyObject(QObject *parent = nullptr) : QObject(parent), MyObjectShared(this) {}
// optional, needed only in this immediately derived class if you want the slot to be a
// real slot instrumented by Qt
#ifdef Q_MOC_RUN
void mySlot();
#endif
};
class MyDerived : public MyObject {
public:
bool derivedSlotCalled = false;
void mySlot() override { derivedSlotCalled = true; }
};
void test1() {
MyObject base;
MyDerived derived;
Q_ASSERT(!base.baseSlotCalled);
Q_ASSERT(!derived.baseSlotCalled && !derived.derivedSlotCalled);
signaler.mySignal();
Q_ASSERT(base.baseSlotCalled);
Q_ASSERT(!derived.baseSlotCalled && derived.derivedSlotCalled);
}
int main(int argc, char *argv[]) {
test1();
QCoreApplication app(argc, argv);
test1();
return 0;
}
#include "main.moc"
To share some code between two QObjects, you could have the QObject as a member of the class,an interposing non-object class that uses generic class that's parametrized only on the base type. The generic class can have slots and signals. They must be made visible to moc only in the immediately derived class - and not in any further derived ones.
Alas, you generally cannot connect any of the generic class's signals or slots in the constructor of the class, since at that point the derived class isn't constructed yet, and its metadata isn't available - from Qt's perspective, the signals and slots don't exist as such. So the Qt 4-style runtime-checked connect will fail.
The compile-time-checked connect will not even compile, because the this pointer it works on has an incorrect compile-time type, and you know nothing about the type of the derived class.
A workaround for Qt-4 style connect only is to have a doConnections method that the derived constructor has to call, where the connections are made.
Thus, let's make the generic class parametric on the base and the derived class as well - the latter is known as the Curiously Recurring Template Pattern, or CRTP for short.
Now you have access to the derived class's type, and can use a helper function to convert this to a pointer to the derived class, and use it in the Qt 5-style compile-time-checked connects.
The Qt 4-style runtime checked connect still needs to be invoked from doConnections. So,if you use Qt 5, that's not an issue. You shouldn't be using Qt 4-style connect in Qt 5 code anyway.
The slots require slightly different treatment depending on whether the class immediately derived from the generic class overrides them or not.
If a slot is virtual and has an implementation in the immediately derived class, you should expose it to moc in the normal fashion - using a slots section or the Q_SLOT macro.
If a slot doesn't have an implementation in the immediately derived class (whether virtual or not), its implementation in the generic class should be made visible to moc only, but not to the compiler - you don't wish to override it, after all. Thus the slot declarations are wrapped in #ifdef Q_MOC_RUN block that is only active when moc is reading the code. The generated code will refer to the generic implementations of the slots.
As we wish to make sure this indeed works, we'll add some booleans to track whether the slots were invoked.
// main.cpp
#include <QtWidgets>
template <class Base, class Derived> class MyGenericView : public Base {
inline Derived* dthis() { return static_cast<Derived*>(this); }
public:
bool slot1Invoked, slot2Invoked, baseSlot3Invoked;
MyGenericView(QWidget * parent = 0) : Base(parent),
slot1Invoked(false), slot2Invoked(false), baseSlot3Invoked(false)
{
QObject::connect(dthis(), &Derived::mySignal, dthis(), &Derived::mySlot2); // Qt 5 style
QObject::connect(dthis(), &Derived::mySignal, dthis(), &Derived::mySlot3);
}
void doConnections() {
Q_ASSERT(qobject_cast<Derived*>(this)); // we must be of correct type at this point
QObject::connect(this, SIGNAL(mySignal()), SLOT(mySlot1())); // Qt 4 style
}
void mySlot1() { slot1Invoked = true; }
void mySlot2() { slot2Invoked = true; }
virtual void mySlot3() { baseSlot3Invoked = true; }
void emitMySignal() {
emit dthis()->mySignal();
}
};
The generic class is very simple to use. Remember to wrap any non-virtual overridden slots in a moc-only guard!
Also recall the general rule that applies to all Qt code: if you have a slot, it should be declared to moc only once. So, if you had a class that further derives from MyTreeWidget or MyTableWidget, you don't want a Q_SLOT or slots macro in front of any necessarily virtual slot overrides. If present, it'll subtly break things. But you definitely want Q_DECL_OVERRIDE.
If you're on Qt 4, remember to call doConnections, otherwise the method is unnecessary.
The particular choice of QTreeWidget and QTableWidget is completely arbitrary, meaningless, and shouldn't be taken to mean that such use makes any sense (it likely doesn't).
class MyTreeWidget : public MyGenericView<QTreeWidget, MyTreeWidget> {
Q_OBJECT
public:
bool slot3Invoked;
MyTreeWidget(QWidget * parent = 0) : MyGenericView(parent), slot3Invoked(false) { doConnections(); }
Q_SIGNAL void mySignal();
#ifdef Q_MOC_RUN // for slots not overridden here
Q_SLOT void mySlot1();
Q_SLOT void mySlot2();
#endif
// visible to the C++ compiler since we override it
Q_SLOT void mySlot3() Q_DECL_OVERRIDE { slot3Invoked = true; }
};
class LaterTreeWidget : public MyTreeWidget {
Q_OBJECT
public:
void mySlot3() Q_DECL_OVERRIDE { } // no Q_SLOT macro - it's already a slot!
};
class MyTableWidget : public MyGenericView<QTreeWidget, MyTableWidget> {
Q_OBJECT
public:
MyTableWidget(QWidget * parent = 0) : MyGenericView(parent) { doConnections(); }
Q_SIGNAL void mySignal();
#ifdef Q_MOC_RUN
Q_SLOT void mySlot1();
Q_SLOT void mySlot2();
Q_SLOT void mySlot3(); // for MOC only since we don't override it
#endif
};
Finally, this little test case shows that it indeed works as desired.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyTreeWidget tree;
MyTableWidget table;
Q_ASSERT(!tree.slot1Invoked && !tree.slot2Invoked && !tree.slot3Invoked);
emit tree.mySignal();
Q_ASSERT(tree.slot1Invoked && tree.slot2Invoked && tree.slot3Invoked);
Q_ASSERT(!table.slot1Invoked && !table.slot2Invoked && !table.baseSlot3Invoked);
emit table.mySignal();
Q_ASSERT(table.slot1Invoked && table.slot2Invoked && table.baseSlot3Invoked);
return 0;
}
#include "main.moc"
This approach gives you the following:
The common code class derives from the base class, and can thus easily invoke or override the behavior of the base class. In this particular example, you can reimplement the QAbstractItemView methods etc.
There is full support for signals and slots. Even though the signals and slots are declared as such in the metadata of the derived class, you can still use them in the generic class.
In this situation you may make use of composition rather than multiple inheritance. Something like this:
class MySignaler : public QObject
{
Q_OBJECT
public:
MySignaler : QObject(NULL) {}
signals:
void MySignal();
}
MySignaler signaler;
class MyBaseWidgetContainer: public QWidget
{
Q_OBJECT
public:
MyBaseWidgetContainer() : QObject(NULL), widget(NULL)
{
connect(&signaler, SIGNAL(MySignal()), this, SLOT(MySlot()));
}
public slots:
virtual void MySlot()
{
// Default behavior here
}
private:
QWidget *widget;
}
class MyTabWidgetContainer : public MyBaseWidgetContainer
{
Q_OBJECT
public:
MyTabWidgetContainer() {
widget = new QTabWidget(this);
QLayout *layout = new QBoxLayout(this);
layout->addWidget(widget);
}
public slots:
void MySlot()
{
// Decide to handle the signal for custom behavior
}
}
I'm studying the Qt4 library and I want to add some functionality to all the children of QWidget in my project. I need all widgets to have mousePressEvent overridden. Obviously I do not need to override it in every particular widget I use(I use many of them and I they to follow DRY rule) , instead I create a Foo class:
class Foo : public QWidget
{
Q_OBJECT
protected:
/* implementation is just a test */
virtual void mousePressEvent(QMouseEvent*) { this->move(0,0); }
};
And derive my button from it:
class FooButton : public QPushButton , public Foo
{
public:
FooButton (QWidget* parent) : QPushButton(parent) { };
};
But the event seems to be not overridden... What am I doing wrong?
Thanks in advance.
For the mousePressEvent access, try QObject::installEventFilter().
http://doc.qt.digia.com/stable/qobject.html
You are inheriting twice now from QWidget. This is problematic (see diamond problem).
Instead, drop your Foo class and move your custom mouse press event handler to your FooButton class:
class FooButton : public QPushButton
{
Q_OBJECT
protected:
/* implementation is just a test */
virtual void mousePressEvent(QMouseEvent*) { this->move(0,0); }
public:
FooButton (QWidget* parent) : QPushButton(parent) { };
};
If this doesn't suit the design of your application, then try using virtual inheritance instead. That is, change Foo to:
class Foo : public virtual QWidget
If that doesn't help, you should follow the advice of the other answers and install an event handler.
(You can read about virtual inheritance in its Wikipedia article.)
I suspect that the problem is that you're inheriting from QWidget twice, once through QPushButton and once through Foo.
From the way you phrased the question, I'm assuming that you want to do this for varying kinds of widgets, and thus don't want to have to subclass QPushButton, QLabel, QCheckBox, etc. If this is not the case then you should use Nikos's answer.
If not, your best bet is probably doing to be to use an event filter.
class MousePressFilter : public QObject {
Q_OBJECT
public:
MousePressFilter(QObject *parent) : QObject(parent) { }
protected:
bool eventFilter(QObject *watched, QEvent *event) {
QWidget *widget = dynamic_cast<QWidget*>(watched);
widget->move(0,0);
return false;
}
};
And then in your Foo class constructor:
class Foo {
Foo() {
installEventFilter( new MousePressFilter(this) );
}
};