5

このようなことが可能かどうかはわかりませんが、Qt のプロパティ システムに登録されているプロパティに基づいて GUI を動的に生成しようとしています。私の仮定は、この方法で Q_PROPERTY() を使用してプロパティを登録したためです。

Q_PROPERTY(propertyType propertyName WRITE setPropertyName READ getPropertyName NOTIFY propertynameSignal)

connect() 関数を使用して、接続用の書き込み関数または読み取り関数の署名を取得できるはずです。これの目的は、プロパティを変更するためにこのオブジェクトにダイアログを接続することですが、すべてを手書きする必要はありません。これは可能ですか、間違った方法で行っていますか、それともダイアログをハードコーディングする必要がありますか?

EDIT 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 に答える