在 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
,您可以轻松打开/关闭连接,在运行时创建Item
s 的子组,这些子组受信号影响/不受信号影响。【参考方案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