Reputation: 645
I am creating a plotting component in QML. The structure of my QML component looks like this:
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{}
}
}
here PlotArea
is my c++ class. I need to interact with this QML component from C++, more precisely, I need to call a member function of PlotArea
to add data to the plot. The usual way is to use findChild<QObject*>("objectName")
, but as the component will get reused, I cannot give PlotArea
and object name.
How can I access PlotArea
if I have a pointer to "myPlot"
? I tried
QObject *plot = rootObjects.value(0)->findChild<QObject*>("plotObject");
PlotArea * myplot = (plot->findChild<PlotArea*>("pa"));
but this does not work. However, what works is the above approach if I do
PlotArea {
id: pa
objectName: "pa"
} // this is my c++ QQuickItem
But I wonder if this is safe, as there will be serveal PlotAreas in my application, and all of them have the name "pa".
Upvotes: 0
Views: 1372
Reputation: 4484
The code in below only one solution to the problem, but not the correct answer because it messes up the ownership of QML objects. The PlotArea
generate from QML
engine but using in the C++ side. To correctly solving the problem recommend redesigning the 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
}
}
}
Upvotes: 1
Reputation: 24416
You shouldn't interact with QML from C++ unless you're writing unit tests. See this documentation for an explanation.
The better approach is to expose a C++ type to QML.
For example, you could register the C++ class that adds the plot data as a singleton:
qmlRegisterSingletonType<PlotDataAdder>("App", 1, 0, "PlotDataAdder", plotDataAdderCreationFunction);
Then you could do this in QML:
import App 1.0
PlotArea {
id: plotArea
Component.onCompleted: PlotDataAdder.addData(plotArea)
}
This is an imperative approach.
If it's possible in your situation, you could do it declaratively instead with qmlRegisterType()
:
qmlRegisterType<PlotDataSource>("App", 1, 0, "PlotDataSource");
Then, in QML:
import App 1.0
Window {
PlotDataSource {
id: plotDataSource
}
PlotArea {
id: plotArea
plotData: plotDataSource
}
}
You said the plot data is dynamically generated by hardware, so this approach would work in that case, whereas the first approach using singletons would be more difficult.
Or, if you can't create the C++ class on-demand (if it comes from a third party library, for example), use setContextProperty()
:
engine.rootContext()->setContextProperty("plotDataSource", plotDataSource);
Then, in QML:
import App 1.0
Window {
PlotArea {
id: plotArea
plotData: plotDataSource
}
}
Upvotes: 5