如何在 C++ 端获取 QQuickItem 的 C++ 对象实例 [重复]

Posted

技术标签:

【中文标题】如何在 C++ 端获取 QQuickItem 的 C++ 对象实例 [重复]【英文标题】:How to get a C++ object instance of a QQuickItem on C++ side [duplicate] 【发布时间】:2016-10-22 17:40:19 【问题描述】:

我有QtApp 和一个纯 C++ 库。 C++ 库公开了一个名为MyCppLibApiClass 的简单类。 QtApp 有一个嵌入在main.qml 上的类。以下是课程:

class MyQuickItem : public QQuickItem 
  MyQuickItem();

按照qml 代码为quick item

import MyQuickItem 1.0

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

以下是我的main.cpp,显示我加载了qml 项目:

qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
return app.exec();

MyQuickItem 需要访问 MyCppLibApiClass 实例。 如何在main.cpp 中获得MyQuickItem 的有效实例? 我需要将MyCppLibApiClass 的对象设置为MyQuickItem 中的成员。我可以使用 setter 方法来做到这一点。但是,首先我需要获得MyQuickItem 的有效实例。那么如何在main.cpp 中访问MyQuickItem

编辑: 在问这个问题之前,我已经搜索了很多。我通读了这个link。另外,我发布的This 问题没有给我一个准确的答案。因此,更清楚地改写我的问题以尝试得到答案。感谢对此的建议..

【问题讨论】:

要将您的类公开给 QML,您应该至少从 QObject 派生它(如果这是可见项目,则从 QQuickItem 派生)。在另一种情况下,您可以将其包装到 QObject 中,然后使用 qmlRegisterType 将其公开给 QML 正如您在我的问题中看到的,我已经从QQuickItem 派生了MyQuickItem。现在,我应该如何访问MyQuickItemmain.cpp 中的实例? 这是什么意思?如果您使用 qmlRegisterType 将您的类公开给 QML,则不应实例化它。它将被 QML 实例化。 我的问题是:如何访问 QML 在调用 qmlRegisterType 后创建的 MyQuickItem 实例。 啊..现在就知道了。只需将 objectName 分配给 QML 项目,QQuickItem *myItem = engine.rootObjects()[0]-&gt;findChild&lt;QQuickItem *&gt;("myQuickItem"); 也是如此 【参考方案1】:

如果您有一个库对象的单个实例,您可以通过两种方式来处理它,具体取决于您需要什么样的访问权限:

将实例作为 MyQuickItem 类的静态成员,在创建 QML 应用程序之前在 main.cpp 中初始化它,然后您可以在 C++ 中从 MyQuickItem 内部访问它。

让实例继承 QObject 并将其公开为上下文属性,这样就可以从 QML 访问它。

如果它不是一个单例对象,你有两个动作:

从 C++ 创建 QML 对象,它会给你直接指向它的指针 使用QQmlApplicationEngine::rootObjects().at(0).findChild()作为类型和对象名称在对象树中查找 QML 对象,如果找到,您将拥有指向该对象的指针

但是,正如您喜欢的问题的答案之一所暗示的那样,这并不是真正的推荐做法。可能有更好的方法来做到这一点,你不应该在 main.cpp 中设置 QML 对象属性,它应该在 MyQuickItem 的构造函数或公共接口中。

【讨论】:

感谢您对此的关注。我可以在接受纯 C++ 类的MyQuickItem 中公开setproperty 吗?您能否在 github 或其他地方提供一些参考项目? 您可以在 QML 中传递不透明的非 QObject 派生 C++ 类型作为参数并返回值,如果您 Q_DECLARE_METATYPE(YourType) 那就是如果您需要从 QML 执行此操作,则从 C++ 您可以完全访问对象的公共接口,你可以为所欲为。但同样,您做错了。现在可能不重要,但迟早会的。从长远来看,糟糕的设计总是很糟糕。 @NelsonP - 您的使用场景未知,因此我无法获得具体建议。但是,使用 C++ INSIDE MyQuickItem 中的库而不是 main.cpp 有什么问题?听起来这就是你应该做的。 我是 Qt 新手。在回答或询问任何其他信息之前,我必须先尝试这些建议。我会在尝试后回来。非常感谢您对此的关注。 如果您从 QML 调用并在那里传递参数,您只需要变体包装器。在 C++ 方面,你不需要那种糖。【参考方案2】:

在你的 main.cpp 中:

qmlRegisterType<MyQuickItem>("MyQuickItem", 1, 0, "MyQuickItem");
QQmlApplicationEngine engine;
MyQuickItem myItem;
engine.rootContext()->setContextProperty("myItem", &myItem);
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));

现在您可以从 C++ 访问 myItem 并从 QML 访问相同的 myItem,只需将 QML 上下文的根级别上的属性“myItem”设置为对您的自定义对象的引用。

编辑

我在答案中添加了 qmlRegisterType 声明。

根据评论中的要求:

使用 qmlRegisterType() 用于在 QML 中注册特定类型,然后可以从 QML 创建/访问。

通过使用engine.rootContext()-&gt;setContextProperty("myItem", &amp;myItem) 方法您实际上是在 C++ 中创建 myItem 并将 myItem 的所有权设置为 C++

由于 QML 旨在与 C++ 一起使用,因此可以简单地将 myItem 分配为 QML 中的属性,并且由于 QML 自动从父对象继承属性/对象,因此 myItem 在整个 QML 上下文中都可用。

这两个例子都没有经过测试,只是为了演示这个想法

ma​​in.qml 示例

import MyQuickItem 1.0

Item 
   Component.onCompleted 
        myItem.visible = true;
        myItem.myCustomMethod();
   

C++ 类示例

class MyQuickItem : public QQuickItem 


     MyQuickItem();

 public slots: 
    void myCustomMethod()  /* do some C++ stuff here */ 

 

【讨论】:

我的答案实际上只是 ddriver 的答案,只是用代码写出来的,所以要更好地理解它,请参阅上面的 ddriver 的答案 感谢代码。我看到你没有做qmlRegisterType&lt;MyQuickItem&gt;("MyQuickItem", 1, 0, "MyQuickItem")。如果我不这样做,那么 Qt 不允许我执行import MyQuickItem 1.0。因此,完全禁止我在 main.qml 中声明 MyQuickItemqmlRegisterType 不再需要了?您能否提供MyQuickItem 周围代码的qml 部分?

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

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

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

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

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

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

来自 C++ 的 QQuickItem 实例化和设置难题(不允许将任何内容传递给构造函数)