在没有 ObjectName 的情况下从 C++ 访问 QML 子组件?
Access QML Child Component from C++ without ObjectName?
我正在 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++class。我需要从 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"。
除非您正在编写单元测试,否则不应从 C++ 与 QML 交互。有关解释,请参阅 this documentation。
更好的方法是将 C++ 类型公开给 QML。
单例
例如,您可以将添加绘图数据的 C++ class 注册为 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++ class on-demand(例如,如果它来自第三方库),请使用 setContextProperty()
:
engine.rootContext()->setContextProperty("plotDataSource", plotDataSource);
然后,在 QML 中:
import App 1.0
Window {
PlotArea {
id: plotArea
plotData: plotDataSource
}
}
下面的代码只是问题的一种解决方案,但不是正确答案,因为它打乱了 QML 对象的所有权。 PlotArea
从 QML
引擎生成,但在 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
}
}
}
我正在 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++class。我需要从 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"。
除非您正在编写单元测试,否则不应从 C++ 与 QML 交互。有关解释,请参阅 this documentation。
更好的方法是将 C++ 类型公开给 QML。
单例
例如,您可以将添加绘图数据的 C++ class 注册为 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++ class on-demand(例如,如果它来自第三方库),请使用 setContextProperty()
:
engine.rootContext()->setContextProperty("plotDataSource", plotDataSource);
然后,在 QML 中:
import App 1.0
Window {
PlotArea {
id: plotArea
plotData: plotDataSource
}
}
下面的代码只是问题的一种解决方案,但不是正确答案,因为它打乱了 QML 对象的所有权。 PlotArea
从 QML
引擎生成,但在 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
}
}
}