5

我不确定这样的事情是否可行,但我正在尝试根据已注册到 Qt 属性系统中的属性动态生成 GUI。我的假设是,由于我以这种方式使用 Q_PROPERTY() 注册了一个属性:

Q_PROPERTY(propertyType propertyName WRITE setPropertyName READ getPropertyName NOTIFY propertynameSignal)

我应该能够使用 connect() 函数检索写入或读取函数的签名以进行连接。这样做的目的是让一个对话框连接到该对象以修改属性,但不必手写所有内容。这可能吗,我是不是走错了路,还是我应该对对话框进行硬编码?

编辑1:我将分享一些我拥有的代码(精简),希望能更清楚地了解我正在尝试做的事情:

特定类的类声明:

class MyObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool someBool READ getBool WRITE setBool)
  public:
    bool someBool;

    bool getBool();
    void setBool(bool);
}

指向此对象的 QDialog 子类:

void MyDialog::generateUI()
{
    const QMetaObject* metaObject = _MyObjectPtr->metaObject();
    for (int i = 0; i < metaObject->propertyCount(); ++i)
    {
        QMetaProperty property = metaObject->property(i);
        if (!strcmp(property.typeName(), "bool")
        {
            QCheckBox* checkBox = new QCheckBox(this);
            bool state = metaObject->property(property->name()).toBool();
            checkBox->setCheckState((state) ? Qt::Checked : Qt::Unchecked);

            // Add checkBox to QDialog layout widgets here
        }
    }
}

原谅所有 My* 重命名,但我需要将我的实际类/成员名称保密。

我可以确认 MyObjectPtr 指向的对象正在被正确读取,因为起始值反映了我在更改它们时所期望的值。问题在于将其连接回该对象。我可以更改复选框 GUI 端内的值,但这些值不会发送到 _MyObjectPtr 指向的实际对象。

4

3 回答 3

5

要检索 QObject 方法(信号、槽等)的签名,您可以使用元对象 ( QMetaObject) 信息。例如以下代码(取自 Qt 文档)提取对象的所有方法的签名:

const QMetaObject* metaObject = obj->metaObject();
QStringList methods;
for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
    methods << QString::fromLatin1(metaObject->method(i).signature());

要检查方法是槽还是信号,可以使用QMetaMethod::methodType()函数。用于签名QMetaMethod::signature()(请参阅上面的示例)。

QMetaObject 参考

更新@HD_Mouse 用关于他的想法以基于对象的属性创建动态 GUI 的附加信息更新了问题后,我想出了以下可以解决问题的代码:

添加将存储 GUI 组件和相应属性索引之间的映射的成员变量:

class MyDialog : public QDialog
{
    [..]
private:
    /// Mapping between widget and the corresponding property index.
    QMap<QObject *, int> m_propertyMap;
};

创建 GUI 组件时(复选框),将其更改信号连接到将处理相应属性更新的特殊插槽。

void MyDialog::generateUI()
{
    const QMetaObject* metaObject = _MyObjectPtr->metaObject();
    for (int i = 0; i < metaObject->propertyCount(); ++i)
    {
        QMetaProperty property = metaObject->property(i);
        if (!strcmp(property.typeName(), "bool")
        {
            QCheckBox* checkBox = new QCheckBox(this);
            bool state = metaObject->property(property->name()).toBool();
            checkBox->setCheckState((state) ? Qt::Checked : Qt::Unchecked);

            // Add checkBox to QDialog layout widgets here

            // Store the property and widget mapping.
            connect(checkBox, SIGNAL(stateChanged(int)),
                    this, SLOT(onCheckBoxChanged(int)));
            m_propertyMap[checkBox] = i;
        }
    }
}

当某个复选框状态发生变化时,找到对应的属性(使用映射)并根据复选框状态进行更新:

void MyDialog::onCheckBoxChanged(int state)
{
    QObject *checkBox = sender();
    QMetaObject* metaObject = _MyObjectPtr->metaObject();
    int propertyIndex = m_propertyMap.value(checkBox);
    QMetaProperty property = metaObject->property(i);

    // Update the property
    _MyObjectPtr->setProperty(property.name(), bool(state == Qt::Checked));
}
于 2013-09-13T20:07:07.890 回答
2

我不确定这是否对你有用,但我走了另一条路。我编写了 gui 并将小部件绑定到基于属性的数据模型。您也许可以使用模型来获取属性以动态生成 gui,然后将生成的小部件与模型联系起来。我写了一个类,QPropertyModel它为任何具有属性的 QObject 创建一个单行数据模型。这些属性对应于模型中的列。我在一个要点中发布了这个类,这里​​有一个使用它的例子:

https://gist.github.com/sr105/7955969

QPropertyModel *model = new QPropertyModel(myQObjectPtr, this);
qDebug() << "model props:" << model->propertyNames();
QDataWidgetMapper *_mapper = model->mapper();
_mapper->addMapping(ui->lblBalance, model->columnForProperty("balance"), "text");
_mapper->addMapping(ui->lineEdit, model->columnForProperty("balance"));
_mapper->toFirst();
于 2013-12-14T06:53:18.550 回答
0

我也有一些关于基于 QObject 属性的自动 UI 生成的想法。但目前我不朝这个方向工作,因为通常我需要特定的 UI 布局以使其对用户友好一点。

虽然我对自动 UI 生成没什么好说的,但我一些关于自动 UI 绑定的东西。代码并不完美,有点硬编码,但主要思想是可见的。我认为这样的东西也可以用于自动 UI 生成。

于 2017-07-06T02:58:53.547 回答