正如我在评论中提到的那样,如果您想要一个易于扩展的功能系统,那么使用
装饰者模式是一个明显的选择。否则,只需从QObject继承而不是从基本“接口”继承即可,代码几乎相同。
我将从其他答案中提供的IMHO较差的方法开始:
- 子类化每个spin box
这显然非常繁琐,更重要的是,您将无法支持任何QSpinBox子类,因为您总是需要为每个添加创建新的子类。这只是一种不灵活的方法。
- 有一个包含按钮和旋转框的父小部件
这看起来像是两个不同事物的不必要耦合,因此,如果您稍后通过按钮以外的方式触发它们,您将无法轻松地重用旋转框。我认为这两个概念应该保持不同并分别管理。
此外,建议使用qobject_cast而不是dynamic_cast。
让我们更仔细地看看装饰器方法:
![enter image description here](https://istack.dev59.com/2skZ7.webp)
这还不是你情况的解决方案,但它很好地展示了如何将功能(即“装饰”)添加到现有层次结构中。为了更具体地讲述你的用例,让我们看看在你的特定场景中会发生什么:
- 组件:QAbstractSpinBox
- 具体组件:
- QSpinBox
- QDoubleSpinBox
- QDateTimeEdit
- QDateEdit
- QTimeEdit
- 装饰器:AbstractSpinBoxDecorator(在你的情况下可以省略此步骤)
- 具体装饰器:RevertibleSpinBoxDecorator
让我们开始动手实现这个设计吧:
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();
}
如果要摆脱
QAbstractSpinBox
的继承关系,你需要应用更多的粘合剂,我认为这并没有太大的收获,而是失去了灵活性。你可以从类似于以下内容开始:
非装饰者模式
#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
构建和运行
qmake && make && ./main