11

Qml 内からオーバーロードされた C++ メソッドを呼び出し、その背後にある理由を理解しようとしているときに、Qt フレームワークの奇妙な動作に遭遇しました。QList<QVariant>次のメソッドを持つ のようなクラスがあるとします。

...
Q_SLOT void append(const QVariant &item);
Q_SLOT void append(const QVariantList &items);
Q_SLOT void insert(int index, const QVariant &item);
Q_SLOT void insert(int index, const QVariantList &items);
...

Qml:

onclicked: {
  var itemCount = myListObject.size();
  myListObject.insert(itemCount, "Item " + (itemCount + 1));
}

Qt はどういうわけか、ラップされたオーバーロードではなく、引数が空に設定されvoid insert(int index, const QVariantList &items)オーバーロードを呼び出すことにしました。itemsnull QVariantQVariantListvoid insert(int index, const QVariant &item)QStringQVariant

次のように宣言の順序を変更すると、期待どおりに動作します。

Q_SLOT void insert(int index, const QVariantList &items);
Q_SLOT void insert(int index, const QVariant &item);

宣言の順序と、それが呼び出し中にメソッドが解決される方法にどのように影響するかに関するQtフレームワークのドキュメントの下には何も見つかりませんでした。

誰か説明してくれませんか?ありがとうございました。

4

2 に答える 2

4

この質問は、JavaScript のオーバーロードに関連しています。それを理解すると、コードの「奇妙な動作」の理由を理解できます。Javascriptでの関数のオーバーロード - ベスト プラクティス をご覧ください。

簡単に言うと、次のことをお勧めします:QVariant両側 (QML と Qt/C++) で変数を操作できるため、バリアントをパラメーターとして渡し、必要に応じて Qt/C++ 側で処理します。

次のようなものを使用できます。

C++ クラスを作成して QML に渡しました (例: as setContextProperty("TestObject", &tc)):

public slots:
    Q_SLOT void insert(const int index, const QVariant &something) {
        qDebug() << __FUNCTION__;
        if (something.canConvert<QString>()) {
            insertOne(index, something.toString());
        } else if (something.canConvert<QStringList>()) {
            insertMany(index, something.toStringList());
        }
    }

private slots:
    void insertOne(int index, const QString &item) {
        qDebug() << __FUNCTION__ << index << item;
    }

    void insertMany(int index, const QStringList &items) {
        qDebug() << __FUNCTION__ << index << items;
    }

あなたのQMLのどこかに:

Button {
    anchors.centerIn: parent
    text: "click me"
    onClicked: {
        // Next line will call insertOne
        TestObject.insert(1, "Only one string")
        // Next line will call insertMany
        TestObject.insert(2, ["Lots", "of", "strings"])
        // Next line will call insertOne
        TestObject.insert(3, "Item " + (3 + 1))
        // Next line will call insertOne with empty string
        TestObject.insert(4, "")
        // Next line will will warn about error on QML side:
        // Error: Insufficient arguments
        TestObject.insert(5)
    }
}
于 2015-02-15T20:21:12.133 に答える