【问题标题】:Accessing Qt / QML objects with C++使用 C++ 访问 Qt / QML 对象
【发布时间】:2017-03-07 17:39:51
【问题描述】:

我正在开发一个最终将与串行端口通信的 C++ Qt 项目。其中一部分是访问 C++ 部分中的 QML 对象。我有可以设置 QML 属性的代码,但是现在访问那些作为方法的功能让我很难过。查看以下代码:

object = view.rootObject();

rect = object->findChild<QObject *>("box");
rect->setProperty("color", "red");                  // Verifies the object tree is accessible
viewer = object->findChild<QObject *>("viewer");    // Access the viewer text box

viewer->append("dummy text");           // OOPS! This doesn't compile!!!

现在,类型作为方法 setProperty(..),但是如何访问对象的方法。 “查看器”是一个 TextArea,我想先执行 selectAll(),然后执行 cut() 来清除框。

这里的问题是这是如何编码的?谢谢大家。

【问题讨论】:

  • 提供 QML 部分。猜测是您应该通过text 的属性viewer 进行交谈。
  • QML 看起来像这样。导入 QtQuick 2.0 导入 QtQuick.Controls 1.2 项目 { 宽度:350 高度:450 TextArea { id:查看器 x:8 y:8 宽度:223 高度:415 文本:“文本” font.pixelSize:12 objectName:“查看器”} 按钮{ id: open x: 251 y: 8 text: "Open" } }
  • @JoeVoytovich - 下次在问题中包含 QML 代码,它可以正确格式化。

标签: c++ qt object qml


【解决方案1】:

当然不会编译,QObject 没有append() 方法。

如果它是 C++ 函数,则必须将 qobject_cast 设置为具有它的适当类型。然而,这对于许多用 C++ 实现的库存 QML 类型并不总是很容易获得,并且作为 C++ 类型,它们不是公共 API 的一部分,通常不打算供最终用户直接使用。

如果是 JS 函数,则必须使用QMetaObject::invokeMethod。这也适用于已为其生成元数据的 C++ 函数。这也是setProperty() 的工作方式,而setColor() 不能与QObject* 一起工作,就像append() 不能一样。

最后但并非最不重要的一点是,绝对没有充分的理由让您从 C++ 中做这些事情。使用 C++ 中的 QML 对象是糟糕的设计和反模式。你只会养成试图这样做的坏习惯。这种交互必须限于使用信号、槽和属性的明确定义的接口。一般来说,QML 可以进入 C++,因为这只能通过暴露的接口发生,但相反的方式,即使可能,也不应该使用。

这样想 - 汽车使用发动机,发动机不使用汽车。并且发动机控制是通过启动钥匙和油门踏板连接的,不能直接使用。 C++ 的东西应该保留给应用程序引擎——高性能或效率核心逻辑,或后端,而 QML 部分用于 GUI/前端。

【讨论】:

  • 是的,我看到 QObject 没有 append() 方法。我确实尝试了 qobject_cast 过程,但无法获得正确的对象来处理它。 TextArea 在 Qt 网站上被定义为 QML 类型。这些类型是否混合在一起(QObject、QML)?
  • @JoeVoytovich 对应的类型是QQuickTextArea。然而,它作为 C++ 类型是“私有的”,因此虽然可能,但它的直接使用并不容易获得。所以你应该试试看invokeMethod()是否可以工作。
  • Invoke() 是一个很好的解决方案。我试过了,它有效,而且很短。 3换3!不能错过帽子戏法。我也喜欢 GUI / 后端分离逻辑。
【解决方案2】:

作者的 QML 部分可能会暴露别名属性来操作所需的文本字段内容:

import QtQuick 2.0
import QtQuick.Controls 1.2

Item {
    property alias viewerText: viewer.text // added

    width: 350
    height: 450
    TextArea {
        id: viewer
        x: 8
        y: 8
        width: 223
        height: 415
        text: "text"
        font.pixelSize: 12
        objectName: "viewer"
    }
    Button {
        id: open
        x: 251
        y: 8
        text: "Open"
    }
}

然后作者的C++部分就可以轻松做到:

auto* object = view.rootObject();    
viewer = object->findChild<QObject *>("viewer");
viewer->setProperty("viewerText", "dummy text"); // using the new property added

【讨论】:

    【解决方案3】:

    使用invoke方法使用此处发布的答案,这是可行的解决方案:

    // C++ Code to call function reset()
    QMetaObject::invokeMethod(object, "reset");
    
    // QML code to select all text the delete it
    function reset() {
        viewer.selectAll()
        viewer.cut()
    }
    

    【讨论】:

    • 这也可以,尽管它是最错误的解决方案。首先,您从 C++ 进入 QML,这是错误且不必要的。第二 - 您不需要将所有文本复制到剪贴板只是为了清除文本区域,您可以viewer.text = ""。您也可以通过 setProperty("text", "") 从 C++ 轻松完成。
    • 我也试试这个。这会更简单。
    猜你喜欢
    • 2021-03-22
    • 1970-01-01
    • 2018-05-17
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多