在 Qt/QML 中访问/修改一个类型的所有实例

Posted

技术标签:

【中文标题】在 Qt/QML 中访问/修改一个类型的所有实例【英文标题】:Accessing/modifying all instances of a type in Qt/QML 【发布时间】:2015-02-27 14:30:38 【问题描述】:

在 QML 中,我有一个自定义对象类型(一个单独的 QML 文件),我想要一种访问和/或修改此类型的每个实例的方法。举个很简单的例子:

MyText.qml:

Text 
    height: 100
    width: 100
    color: "red"

    function logStuff() 
        console.log("This is MyText")
    

SomePage.qml:

MyText 
    id: text1
    anchors.left: parent.left
    anchors.verticalCenter: parent.verticalCenter
    text: "foo"


MyText 
    id: text2
    anchors.right: parent.right
    anchors.verticalCenter: parent.verticalCenter
    text: "bar"

当事件发生时(例如,单击 SomePage.qml 上的按钮或发出信号),我希望能够将 MyText 的所有实例更改为对一个属性具有相同的值,或者调用每个 MyText 的 @ 987654323@函数。

注意:在我的实际用例中,实际上有几十个这样的实例,并且还会有其他 Text 元素不是 MyText 的实例。

我对 jQuery 有一点经验,并希望有一些类似于 jQuery 选择器的东西,但我一直找不到任何类似的东西。 QML 或 C++(或混合)解决方案都可以。

【问题讨论】:

【参考方案1】:

我想建议一种使用 C++ 的方法。 由于无法获取QML 对象的基类,因此您可以基于objectName 属性进行搜索,Witch 可在C++ 中访问。

假设我们有基础QML 对象:

import QtQuick 2.3

Item 
    id: base
    objectName: "BaseItem"
    property int someValue: 0
    onSomeValueChanged: 
        console.log("'someValue' was changed to " + someValue + " for " + base);
    

还有另一个 QML 文件,其中使用了这些对象:

import QtQuick 2.4
import QtQuick.Window 2.2

Window 
    visible: true
    width: 300
    height: 300
    id: mainWindow

    Base 
        id: derived1
    
    Base 
        id: derived2
    
    Base 
        id: derived3
    

想法是所有派生对象都从基类继承相同的objectName

所以现在您可以简单地找到C++ 中的所有对象:

QObject *root = engine.rootObjects().first();
QList<QObject *> list = root->findChildren<QObject *>("BaseItem");
qsrand(QTime::currentTime().msec());
foreach(QObject *item,list) 
    item->setProperty("someValue",qrand());

这里我只是更改属性,但您也可以使用QMetaObject::invokeMethod() 等调用一些方法。

【讨论】:

【参考方案2】:

我不确定你的需要,但我会像这样使用Connections 元素:

SomePage.qml:

MyText 
    id: text1
    anchors.left: parent.left
    anchors.verticalCenter: parent.verticalCenter
    text: "foo"
    Connections 
        target: senderItemId
        onFooChanged: logStuff()
    


MyText 
    id: text2
    anchors.right: parent.right
    anchors.verticalCenter: parent.verticalCenter
    text: "bar"
    Connections 
        target: senderItemId
        onFooChanged: logStuff()
    

【讨论】:

再次阅读主题。如何使用 Connections 访问某个类型的所有实例? 您是否像在您的示例中那样自己创建实例?如果是这样,那么是什么阻止您像这个答案所暗示的那样在每个人中放置一个小“连接”块? 为什么要在每个实例中放置一个连接?把它放在元素本身! (即在MyText.qml @folibis 就像 RoeyLehman 所说,如果 OP 自己创建对象,他可以轻松地手动添加连接。我在建议一种替代方法来访问 c++ 中的元素。我们可以将 Connections 直接放在 .qml 文件中,但它不会很灵活,这取决于我猜的需要。 完全同意@GrecKo(@peppe 改进:D)。我已经将Connection 用于这个确切的目的,它真的很有魅力。此外,通过使用target 属性、三元运算符和null,您可以轻松打开/关闭连接,在运行时创建Items 的子组,这些子组受信号影响/不受信号影响。【参考方案3】:

Qt 中没有执行此操作的 API 调用(我可以找到),但您可以使用 C++ 中的 QObject::children() 和 QMetaObject 按类型查找所有 QML QObject。下面是一个实现示例。

QList<QObject *> MySingleton::findObjectsOfComponent(QObject *parent, QQmlComponent *component) const

    auto object = component->create(QQmlEngine::contextForObject(parent));
    auto foundObjects = findObjectsOfObject(parent, object);
    delete object;
    return foundObjects;


QList<QObject *> MySingleton::findObjectsOfObject(QObject *parent, const QObject *object) const

    auto className = object->metaObject()->className();

    QList<QObject*> items;
    for(auto child : parent->children()) 
        if(child->metaObject()->className() == className) 
            items.append(child);
        

        items.append(findObjectsOfObject(child, object));
    
    return items;

那么你应该将 MySingleton 注册为 QML 单例并使用 Component 来查找类型。

Component 
     id: errorLabelComponentId
     ErrorLabel 


Button 
    onClicked: 
        //Un-ignore all error labels
        var errorLabels = MySingleton.findObjectsOfComponent(pageId, errorLabelComponentId)
        for(var i in errorLabels) 
            //ignoreError is a property of ErrorLabel 
            errorLabels[i].ignoreError = false 
        
    

【讨论】:

以上是关于在 Qt/QML 中访问/修改一个类型的所有实例的主要内容,如果未能解决你的问题,请参考以下文章

Qt/QML - 在 C++ 中注册 QML 类型会使 QML 代码不起作用

使用具有UI控制的所有状态的1个图像在QT / QML中创建UI

Qt/QML:在加载程序加载后访问 ListView 以跳转到特定项目/页面

更改后,QT QML资源文件不会重新编译

尝试通过插入子样式项来设置 Qt QML 项的样式

如果数据库可访问,如何快速检查? (Qt、QML、C++)- Linux