QML 在匿名孙子之间发送信号

Posted

技术标签:

【中文标题】QML 在匿名孙子之间发送信号【英文标题】:QML send signals between anonymous grandchildren 【发布时间】:2016-06-12 19:39:19 【问题描述】:

我正在尝试在树结构中的 qml 组件之间进行通信。我有一个 main.qml 组件,其 id 为 root。它有两个孩子,每个孩子都有任意数量的从转发器和模型动态创建的孩子。

当点击其中一个孙子时,我希望其他人知道并能够采取行动。所以如果我可以在孙子之间发送信号就好了。

问题是它们都没有设置 id 属性,因为它们是动态生成的,并且其中一些位于不同的范围内。为了在他们之间进行交流,我做了以下事情: 在 root 中创建了一个函数,每个孙子都可以看到,并且可以使用消息作为参数调用它。然后根函数会发出一个带有消息作为参数的信号。所有的孙子都可以连接到信号,因为他们知道 root 的 id。

人们对此有何看法?我感觉我错过了 qml 中的信号点,感觉就像我实现了一个粗略的系统并且错过了整个点或其他东西。

另外,我想远离 C++ 世界,但人们是否认为最好使用 C++ 类以便我可以使用信号和插槽。

我的目标是一个耦合非常松散的 MVC 结构和一个集中式控制器。人们如何看待 MVC 中 QML 组件之间的通信。

我在这里发现的唯一类似问题是关于 C++ 或在组件上使用硬编码的 id。

我认为 id 不能动态设置,甚至在创建时也不能;我错了吗?

另外,组件在不同的范围内,所以无法解析 id;我错了吗?

我已经写了一些代码:

//qml.main
import QtQuick 2.4
import QtQuick.Controls 1.3

ApplicationWindow 
    id: root
    visible: true
    menuBar: MenuBar 
        Menu 
            title: qsTr("File")
            MenuItem 
                text: qsTr("&Open")
                onTriggered: console.log("Open action triggered");
            
            MenuItem 
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            
        
    

    property string thisName: "root"

    signal rootSays(string broadcastMessage)

    function callRoot(message) 
        var response = message
        print("Root received: " + message)
        print("Root broadcasting: " + response)
        rootSays(response)
    

    MajorComponent//this is root's child A
        property string thisName: "A"
        thisModel: [name:"First Grandchild of A", color:"red", y:0,
                    name:"Second Grandchild of A", color:"green", y:80]
    

    MajorComponent//this is root's child B
        property string thisName: "B"
        thisModel: [name:"First Grandchild of B", color:"blue", y:210,
                    name:"Second Grandchild of B", color:"yellow", y:290]
    





//qml.MinorComponent
import QtQuick 2.0

Rectangle 
    property string thisName: ""
    property string thisColor: ""

    color: thisColor
    height: 50; width: 200
    Text 
        anchors.centerIn: parent
        text: thisName
    

    MouseArea 
        anchors.fill: parent
        onClicked: 
            print(thisName + " clicked")
            print("Root called with: " + thisName)
            root.callRoot("Hello from " + thisName)
            print("---")
        
    



//qml.MajorComponent
import QtQuick 2.0

Rectangle 
    property var thisModel: []

    Repeater 
        model:thisModel
        MinorComponent 
            y: modelData.y
            thisName: modelData.name
            thisColor: modelData.color
            function handleResponse(response) 
                print(thisName + " received: " + response);
            
            Connections 
                target: root
                onRootSays: handleResponse(broadcastMessage)
            

        
    


【问题讨论】:

这是一个有趣的问题,但要回答它,有一些可用的代码会更容易,我们可以使用和测试。我的意思是,有人可能会直接给你答案,但是对于像 QML 这样的特定问题,并且考虑到 Qt 在 QML 中的错误或实现细节的跟踪记录,拥有一些代码会容易得多。 将控制器作为 C++ 公开对象有什么问题? @peppe 这有什么帮助? 你可能会觉得这个读起来很有趣:medium.com/@benlaud/…我以一种简化的方式使用这个模式,我直接监听 AppActions 因为一旦您的应用程序增长,您就需要将大孙子的事物连接到其他大孙子。这需要集中式设计,这在 C++ 中更容易。 (或通过 QML 中的pragma Singleton 【参考方案1】:

我认为 id 不能动态设置,甚至在创建时也不能; 我错了吗?

ids 纯粹是“编译”时构造。话虽如此,没有什么能阻止您实施和管理自己的对象注册系统。一个简单的空 JS 对象就可以了,它可以有效地用作 QMap 根据键(属性名称)查找对象。如果您将地图对象设置为根对象的属性,由于动态范围,它应该可以从树中的每个对象中解析。

使用信号的方法是一种可靠的 IMO。我使用了类似的东西,结合仿函数和引用捕获,允许访问任意树结构中的任意和可选的现有对象,通过他们必须满足的各种标准过滤候选对象。你可以用这种技术做一些非常棘手的事情。

话虽如此,一个说明您实际想要实现的目标的实际示例将有助于提供更具体的答案。

【讨论】:

以上是关于QML 在匿名孙子之间发送信号的主要内容,如果未能解决你的问题,请参考以下文章

qml 从信号发送列表/数组

从 C++ (Qt5) 向 QML 项目发送信号

QThread如何从其自己的线程发送一个带有枚举作为QML消耗参数的信号?

如何将一维整数数组从 QML 发送到 C++?

2 个不同 QML 文件中的 2 个不同对象之间的通信

python 包之 blinker 信号库教程