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_cast
ing 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
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