将信号连接到QMetaProperty的插槽

时间:2013-09-13 19:23:08

标签: qt signals-slots

我不确定这样的事情是否可行,但我试图根据已注册到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);
}

指向此Object的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 * renamings,但我需要将我的实际类/成员名称保密。

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

3 个答案:

答案 0 :(得分: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 reference

更新在@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));
}

答案 1 :(得分: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();

答案 2 :(得分:0)

我对基于QObject属性的自动UI生成也有一些想法。但目前我并没有朝着这个方向努力,因为通常情况下,我需要特定的UI布局,以使其有点用户友好。

虽然我对自动UI生成无话可说,但have用于自动UI绑定。代码不完美,有点硬编码,但主要的想法是可见的。我认为像这样的东西也可以用于自动生成UI。