如何在 C++ 端获取有效的 QQuickItem 实例

Posted

技术标签:

【中文标题】如何在 C++ 端获取有效的 QQuickItem 实例【英文标题】:How to get a valid instance of a QQuickItem on C++ side 【发布时间】:2016-10-21 13:46:34 【问题描述】:

好的。我已经搜索了很多,但还没有一个好的解决方案。我是Qt 的新手。我有一堂课是QQuickItem,就像这样,

class MyQuickItemClass : public QQuickItem

    Q_OBJECT
    SetInfo(SomeCppClass object)
;

我在我的main.cpp 中创建了一个qmlRegisterType,以便像这样在qml 一侧注册它,

qmlRegisterType("MyQ​​uickItemClass", 1, 0, "MyQuickItemClass");

到这里为止一切都很好。但是 -> 我想在 MyQuickItemClass 中设置一个对象实例和一些属性,其中还有一些 C++ 逻辑,然后将MyQuickItemClass 对象传递给qml。或者,从 Qml 获取 MyQuickItemClass 的有效实例。 如何在main.cpp 的 C++ 端从 QML 获取 vlid 实例 MyQuickItemClass 对象实例?

我尝试通过链接here 进行以下学习。但是这种技术会创建两个独立的 MyQuickItemClass 对象。一个来自QML,一个来自c++。因此对我不起作用。

以下是我经过大量搜索后尝试执行此操作的方式。

int main(int argc, char *argv[]) 

  qmlRegisterType< MyQuickItemClass >("MyQuickItemClass", 1, 0, "MyQuickItemClass");
  QQmlApplicationEngine engine;
  SomeCppClass someCppClassObject;
  someCppClassObject.updateSomething();

  MyQuickItemClass myquickItemObject;
  myquickItemObject.SetInfo(someCppClassObject);
  engine.rootContext()->setContextProperty("myquickItemObject", &myquickItemObject);

  engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
  return app.exec();

但是,执行上述操作会使MyQuickItemClass 的构造函数被调用两次。当我创建一个对象时,一次来自cpp,一次来自qml。通过在MyQuickItemClass 的构造函数中放置一个断点来验证这一点。结果,当程序运行时,我设置的someCppClassObjectMyQuickItemClass 内为空。因为 qml 已经对MyQuickItemClass 进行了最终调用来实例化,因此忽略了我在main.cpp 中创建的MyQuickItemClass 对象。

这是我的qml 代码MyQuickItemClass

import QtQuick 2.5
import MyQuickItemClass 1.0

ParentContainerItem 
  id: parentItem
  color: "black"

  MyQuickItemClass 
      id: myQuickItemID
      visible: true
      objectName: "myQuickItem"

      property bool someProperty1: false
      property bool someProperty2: true

      anchors.top: parent.top
      anchors.horizontalCenter: parent.horizontalCenter
  

  //Other qml components

这是需要将其对象设置为MyQuickItemClass的C++类。

SomeCppClass 
  //Pure C++ class. No Qt

请注意,我需要保留从QQuickItem 派生的MyQuickItemClass。请建议...

【问题讨论】:

您遇到什么错误?实例如何“无效”? MyQuickItemClass 的构造函数被调用了两次。当我创建一个对象时,一次来自cpp,一次来自qml。通过在MyQuickItemClass 的构造函数中放置一个断点来验证这一点。结果,当程序运行时,我设置的someCppClassObjectMyQuickItemClass 内为空。因为qml最后调用MyQuickItemClass进行实例化,因此忽略了我在main.cpp中创建的MyQuickItemClass对象 您也应该将错误添加到问题中。所以发现这个问题的人不必为此通读 cmets。 好的。现在将错误添加到问题中 向我们展示 main.qml 【参考方案1】:

通常最好避免访问 QML 实例化对象 from outside,因为大多数访问方法会生成从 C++ 到 QML 的依赖关系,从而限制了 QML 树的完成方式。

例如要求某些对象在某个时间点存在,具有特定的objectName 值等。

最好通过在暴露的 C++ 对象/API 上调用方法从 QML 端“注册”对象,或者让 QML 在其自己的 C++ 代码中实例化对象注册自己。

后者显然本质上是自动的,即这样的类的每个实例都会这样做,而前者则让 QML 代码自行决定它想知道哪个创建的实例。

【讨论】:

没有任何方法可以从 qml 对象树中获取 MyQuickItemClass 的有效实例并方便自己调用方法 SetInfo 吗?奇怪的 !!我以为这会很简单 有,只需使用QObject::findChild() 搜索给定对象名称的对象,但如果有更简洁的方法,为什么要这样做呢?【参考方案2】:

根据here 讨论中的建议执行以下操作可解决问题并获得 QuickItem qml 文件的有效对象

QQuickItem *myItem = engine.rootObjects()[0]->findChild<QQuickItem *>("myQuickItem");

【讨论】:

以上是关于如何在 C++ 端获取有效的 QQuickItem 实例的主要内容,如果未能解决你的问题,请参考以下文章

C++ QQuickItem:如何在项目大小更改时触发函数

如何创建 QQuickItem 的单独副本并将其呈现在不同的窗口上

如何将 X 和 Y 转换值应用于 C++ 端的 QQuickItem

如何正确使用 QQuickItem::stackBefore() 重新排序 GridLayout 中的项目?

有效地从 QPaintDevice 到 QQuickItem 中的 QSGTexture

Qt:如何获取 QQuickItem 的快照,将其子 QQuickItems 从获取的结果中剔除