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

Accessing/modifying all instances of a type in Qt/QML

本文关键字:类型 实例 修改 Qt QML 访问      更新时间:2023-10-16

在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的logStuff()函数。

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

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

我想推荐一个使用C++的方法。由于无法获得QML对象的基类,因此可以基于C++中可访问的objectName属性进行搜索。

假设我们有一个基本的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()等调用一些方法。

我不确定是否理解您的需求,但我只想使用这样的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()
    }
}

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 
        }
    }
}