【问题标题】:Access QML Child Component from C++ without ObjectName?从没有 ObjectName 的 C++ 访问 QML 子组件?
【发布时间】:2018-04-06 08:21:09
【问题描述】:

我正在 QML 中创建一个绘图组件。我的 QML 组件的结构如下所示:

Rectangle {
  id: canvas
  objectName: "myPlot"
  Rectangle {
    id: plot
    PlotArea {
      id: pa
    } // this is my c++ QQuickItem
    MouseArea {} // for handling interaction with the plot, like zooming
    XAxis{}
    YAXis{}
  }
}

PlotArea 是我的 c++ 类。我需要从 C++ 与这个 QML 组件进行交互,更准确地说,我需要调用 PlotArea 的成员函数来将数据添加到绘图中。通常的方法是使用findChild<QObject*>("objectName"),但是由于组件会被重用,我不能给出PlotArea和对象名称。

如果我有指向"myPlot" 的指针,我如何访问PlotArea?我试过了

QObject *plot = rootObjects.value(0)->findChild<QObject*>("plotObject");
PlotArea * myplot = (plot->findChild<PlotArea*>("pa"));

但这不起作用。但是,如果我这样做,上述方法是有效的

PlotArea {
  id: pa
  objectName: "pa"
} // this is my c++ QQuickItem

但我想知道这是否安全,因为在我的应用程序中会有多个 PlotAreas,并且它们都具有名称“pa”。

【问题讨论】:

    标签: qt qml qtquick2


    【解决方案1】:

    除非您正在编写单元测试,否则您不应该在 C++ 中与 QML 进行交互。请参阅this documentation 了解说明。

    更好的方法是将 C++ 类型公开给 QML。

    单例

    例如,您可以将添加绘图数据的 C++ 类注册为singleton

    qmlRegisterSingletonType<PlotDataAdder>("App", 1, 0, "PlotDataAdder", plotDataAdderCreationFunction);
    

    然后你可以在 QML 中做到这一点:

    import App 1.0
    
    PlotArea {
        id: plotArea
        Component.onCompleted: PlotDataAdder.addData(plotArea)
    }
    

    这是一种命令式的方法。

    命名类型

    如果在您的情况下可能,您可以使用 qmlRegisterType() 以声明方式执行此操作:

    qmlRegisterType<PlotDataSource>("App", 1, 0, "PlotDataSource");
    

    然后,在 QML 中:

    import App 1.0
    
    Window {
        PlotDataSource {
            id: plotDataSource
        }
    
        PlotArea {
            id: plotArea
            plotData: plotDataSource
        }
    }
    

    您说绘图数据是由硬件动态生成的,因此这种方法适用于这种情况,而使用单例的第一种方法会更困难。

    上下文属性

    或者,如果您不能按需创建 C++ 类(例如,如果它来自第三方库),请使用 setContextProperty()

    engine.rootContext()->setContextProperty("plotDataSource", plotDataSource);
    

    然后,在 QML 中:

    import App 1.0
    
    Window {
        PlotArea {
            id: plotArea
            plotData: plotDataSource
        }
    }
    

    【讨论】:

    • 从 c++ 与 QML 交互有什么问题?特别是在这种情况下,哪里 PlotArea 已经是一个 c++ 对象?另外,我可能有几个 Plot 组件对象,我将如何选择在单例解决方案中添加数据?
    • 我们正在添加涵盖此主题的文档,但目前仅作为快照提供:doc-snapshots.qt.io/qt5-5.11/…
    • 我不确定你的第二个问题..语法很奇怪所以我不明白。
    • 感谢您提供的文档。我明白这一点。虽然我不确定这对我来说是否可行(可能是因为我还不了解您提出的解决方案)。进入该图中的数据可能是由硬件动态生成的,因此很可能需要以某种方式从 c++ 触发 addData。关于您提出的解决方案:如果我的应用程序将有多个图,我将需要向各个图添加不同的数据,这将如何与您的单例一起使用?
    • @numberCruncher 在逻辑和 gui 之间没有适当的隔离,你的设计很糟糕。必须从 C++ 访问 QML 对象已经是糟糕的设计。由于您是新手,因此可能并不明显,但从长远来看,您最终会后悔的。它效率低下,容易出错且难以维护。数据应该是核心逻辑层的一部分,QML 应该与之相连。不是相反。
    【解决方案2】:

    下面的代码只是解决问题的一种方法,但不是正确的答案,因为它弄乱了 QML 对象的所有权。 PlotAreaQML 引擎生成,但在 C++ 端使用。要正确解决问题,建议重新设计PlotArea

    C++:

    QObject* test = engine.rootObjects()[0]->findChild<QObject*>("test");
    PlotArea* plotArea = test->property("plotArea").value<PlotArea*>();
    

    QML:

    Item{
        objectName: "test"
        property var plotArea : plotArea
        Item{
            PlotArea{
                id: plotArea
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      • 2012-03-19
      • 2018-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多