在Qt中创建一个小部件工厂

问题描述 投票:0回答:2

你好~我正在创建一组自定义小部件,用于扩展 Qt 中的本机小部件。我的自定义小部件应该是从数据源构建的,它们都提供自定义功能

Foobar
。例如:

class CheckBox: public QCheckBox, public Control
{
Q_OBJECT

public:
  CheckBox(QWidget* parent = 0);
  CheckBox(DataSource* data, QWidget* parent = 0);
  virtual ~CheckBox();

  virtual void Foobar();
};

class ComboBox: public QComboBox, public Control
{
Q_OBJECT

public:
  ComboBox(QWidget* parent = 0);
  ComboBox(DataSource* data, QWidget* parent = 0);
  virtual ~ComboBox();

  virtual void Foobar();
};

每个小部件类都有一个相应的数据源类,负责创建小部件。例如:

class CheckBoxDataSource: public DataSource
{
public:
  CheckBoxDataSource();
  virtual ~CheckBoxDataSource();

  virtual QWidget* createControl(QWidget* parent);
};

class ComboBoxDataSource: public DataSource
{
public:
  ComboBoxDataSource();
  virtual ~ComboBoxDataSource();

  virtual QWidget* createControl(QWidget* parent);
};

这些类暴露给Python之后,拥有各种数据源列表的Python客户端预计会像这样使用它:

for data in dataSources:
    widget = data.createControl(parent)  # returns a QCheckBox/QComboBox/etc
    # at a later time ...
    widget.Foobar()

但是,这是行不通的,因为

data.createControl()
将返回 PyQt 中
QCheckBox
QCombox
类型的对象,因此客户端将无法调用
widget.Foobar()
,因为
Foobar()
函数不在这些课程中可用。我该如何解决这个问题? 到目前为止,我已经尝试过以下这些,但没有一个起作用......

尝试1

在 Python 中,我尝试将小部件转换为正确的 C++ 类,以便我可以调用

Foobar()

widget.__class__ = CheckBox
widget.__class__ = ComboBox

在某些情况下,这工作正常,在其他情况下,即使它是正确的类型,我也会收到错误

AttributeError: 'CheckBox' object has no attribute 'Foobar'
。有趣的是,如果我在该行上放置一个断点并在调试器中单步执行它,它总是可以工作,没有断点它会失败,所以似乎存在一个我无法弄清楚的计时问题。不管怎样,变异
__class__
是危险的,所以我可能应该避免它。

尝试2

如果我将

virtual void Foobar()
添加到基类
Control
并声明
createControl()
以返回
Control*
而不是
QWidget*
。这应该允许客户端在 Python 中调用
Foobar()
,但他们也失去了将其视为
QWidget
的能力。

尝试3
widget = CheckBox(data.createControl(parent))

通过将返回的对象包装在另一个构造函数调用中,Python 中的小部件现在应该具有正确的类型。但这会创建 2 个

CheckBox
小部件,而不是 1 个,所以我必须“删除”其中一个。看起来在这种情况下正在调用复制构造函数。我不认为我可以用 Python
move
实现它。

抱歉我的大脑现在一片混乱,我想应该有更好的工厂设计?

python c++ qt
2个回答
1
投票

因此您希望拥有

QWidget*
以及附加接口
Foobar
。恐怕这可能是不可能的,不是以简单的 C++ 方式,没有包装类,例如类似于
Qt User Interface Compiler
使用的 setupUi(parentPtr); 模式。 Qt 不允许从
QObject
进行多重继承,因此您不能将
class Control
设计为
QWidget
,因为那样您就无法同时继承
Control
QCheckBox

但是,您可以使用元对象功能(反射模式)。如果您将附加接口定义为

QINVOKALBES
:

class MyCheckBox : public QCheckBox {
    Q_OBJECT;

public:
    Q_INVOKABLE void Foobar() { qDebug() << "MyCheckBox::Foobar"; }
};

然后您可以用

QMetaObject::invokeMethod(myCheckBoxPtr, "Foobar", Qt::DirectConnection);
来称呼它们,其中
myCheckBoxPtr
QWidget*
(如果您想进一步抽象,甚至可以使用
QObject*
)。

C++ 文档python 文档


0
投票

QWidget* createControl(QWidget* parent);
返回一个没有 Foobar() 的 QWidget 指针。

你不能在cpp或python中调用

widget->Foobar()
,因为widget是一个QWidget。

解决这个问题:

制作一个扩展 QWidget 和 Control 的基本小部件(例如 BaseWidget)。 BaseWidget 有成员函数 Foobar()。然后更改

virtual QWidget* createControl(QWidget* parent);
返回 BaseWidget* 。然后你可以在Python中调用w.Foobar()。

© www.soinside.com 2019 - 2024. All rights reserved.