QML 绑定整数 属性 - C++ 中的更改未发送到 QML

QML Binding integer property - changes in c++ not sent to QML

我是 QtQuick 控件的新手,我想创建一个简单的 GUI,但在将某些 c++ 变量绑定到 qml 小部件属性时遇到了以下问题: 在下面的简化示例中,我有一个组合框,我想为其分配一个项目列表,并且还能够设置从应用程序的 C++ 端选择哪个项目。

对于 test_list/model 对,一切都按照我的预期进行,但对于 test_index/currentIndex 则不然。在将 test_index 设置为 2 并调用通知后,什么也没有发生——我希望应该调用 READ 方法 (getIndex),但实际上并没有(它是针对 test_list 的)。从 GUI 更改索引有效,即由于 onCurrentIndexChanged,值从 qml 发送到 c++ 端,但反之则不起作用。所以在调用 modifyValues() 之后,组合框中有四个项目 - 0、1、2、3 - 但 currentIndex 仍然是 0,因此选择了“0”项目(同时,test_index 等于2).

奇怪的是 getIndex 确实在第一次创建小部件时被调用。我读过在 qml 中更改 属性 将终止所有声明性绑定,但我不明白为什么会发生这种情况,尤其是当它适用于 'model' 属性 (或其他我试过的,例如 currentText)。尽管如此,我也尝试将 myCombo.currentIndex = testClassInstance.test_index 放入 onCurrentIndexChanged 中,但这并没有帮助(而且它似乎不正确......)。

我的问题:currentIndex 属性 有什么特别之处吗?如何在不求助于在 qml 中显式定义信号连接的情况下实现我想要的(我认为这基本上就是 Q_PROPERTY 宏的用途)?我想我可以想出一些解决方法来实现我的目标,所以这不是我在这里寻找的 - 相反,我更愿意有人能向我解释为什么这种特殊方法没有按我预期的方式工作。

main.qml

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Dialogs 1.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")


    MainForm {
        objectName: "mainForm"
        anchors.fill: parent
    }
}

MainForm.qml

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1

Item {
   width: 640
   height: 480


   Rectangle {
      anchors.centerIn: parent

      ComboBox {
            id: myCombo
            model: testClassInstance.test_list
            currentIndex: testClassInstance.test_index
            visible: true
            onCurrentIndexChanged: {
                testClassInstance.test_index = myCombo.currentIndex
            }
       }
   }
}

testClass.h

#ifndef TESTCLASS_H
#define TESTCLASS_H

#include <QObject>

class testClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int test_index READ getIndex WRITE setIndex NOTIFY notification)
    Q_PROPERTY(QStringList test_list READ getList WRITE setList NOTIFY notification)

public:
    testClass(QObject *parent) : QObject(parent) {}
    ~testClass() {}

    void modifyValues()
    {
        test_list << "1" << "2" << "3";
        notification();
        test_index = 2;
        notification();
    }

    int getIndex() { return test_index;  }
    QStringList getList() { return test_list;   }

    void setIndex(int val) { test_index = val;  }
    void setList(QStringList val) { test_list = val; }

signals:
    void notification();

private:
    int test_index = 0;
    QStringList test_list = QStringList("0");

};

#endif

main.cpp

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;

    testClass test(&engine);
    engine.rootContext()->setContextProperty("testClassInstance", &test);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    test.modifyValues();

    return app.exec();
}

作为快速回复,您可以使用 Connections

   ComboBox {
       id: myCombo
       model: testClassInstance.test_list
       visible: true
       onCurrentIndexChanged: {
           testClassInstance.test_index = myCombo.currentIndex
       }
       Connections {
           target: testClassInstance
           onNotification: myCombo.currentIndex = test_index;
       }
   }

让我们分步进行:

1) 您创建组合框对象并将其属性(索引和模型)绑定到 class' 属性

2) 您调用 modifyValues 并 a)更改列表,这会触发模型更改 b) 更改索引,这会触发...什么都没有

问题出在步骤 2a 上。 ComboBox里面有如下代码:

onModelChanged: {
    ...
    popup.__selectedIndex = 0
}

此调用会破坏您对索引的绑定,因此当您转到步骤 2b 时,绑定不再存在。

这是您问题的解决方案,您应该在模型更改后更新绑定:

onModelChanged: {
     currentIndex = Qt.binding( function(){return testClassInstance.testIndex} )
}