[SOLVED] Seek documentation reference for calling C++ from QML
-
I'm new to Qt with an interest in using it for illustrating dynamic simulations. The computational side would be in C++. I would like to play with QtQuick 2 for the user interface. My first puzzle is how to communicate, for example, updated (x,y) positions in each step of the simulation to the display rectangle defined in a .qml file. (The latter would also hold some execution controls.)
After watching many YouTube demos and searching the docs and forums, I have found this:
http://qt-project.org/forums/viewthread/32144/
I'm hoping for a reference to something a little more extensive. In advance, thanks... -
-
Hi, and welcome to the world of Qt!
Generally, your QML file emits a signal which is connected to a C++ slot, rather than calling C++ functions directly. This is how Qt cleanly separates the GUI from the computational logic.
Have you dealt with C++ signals and slots before?
Here's the updated version of Chris' link -- Qt 5.0 had some documentation issues: http://qt-project.org/doc/qt-5.1/qtqml/qtqml-cppintegration-topic.html
-
Thanks Chris and JKSH. The 5.1 link should get me started. I failed to find the ~/qtqml page when going down the qt-project.org/doc/qt-5.1 tree.
I have a little exposure to signals and slots. I started my study with the widget-based book "C++ GUI Programming with QT 4" by Blanchette and Summerfield. But, looking at Qt Quick, I have taken a little side trip into that territory. -
Most of what you learnt from Blanchette and Summerfield still apply to Qt 5. Signals from QML files work the same way as signals from widgets.
But anyway, I was mistaken earlier (sorry for any confusion caused). You CAN call C++ functions directly from QML. Here is an example of 2 ways to "call C++ from QML":
MyItem.qml
@
Rectangle {
signal mySignalEmittedMouseArea { anchors.fill: parent onClicked: { mySignalEmitted() // Emit QML signal myObj.mySlot2() // Call C++ slot directly } }
}
@main.cpp
@
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);// Create and show your QML GUI QQuickView *view = new QQuickView(QUrl("main.qml")); view->show(); // Get a pointer to your QML item and C++ object QQuickItem *item = view->rootObject(); MyObject *obj = new MyObject(); // 1) Connect the QML signal to a C++ slot QObject::connect(item, SIGNAL(mySignalEmitted()), obj, SLOT(mySlot2())); // 2) Allow the QML file to call MyObject's C++ slots directly view->rootContext()->setContextProperty("myObj", obj); return app.exec();
}
@Now, every time you click on your Qt Quick window, it does 2 things:
Emit mySignalEmitted() which calls MyObject::mySlot1() indirectly
Call MyObject::mySlot2() directly
Method #1 provides better encapsulation, at the cost of 1 extra line of code
-
Thanks again JKSH -- no confusion 'cause I haven't had the time to move forward yet. This answers my question about buttons in my planned simulation to control progress via, say, GO, STOP, PAUSE, RESET commands.
If I can ask one further basic question. MyObject would be a collection of points undergoing motion in 2D. After the position of each member of the set has been updated, how is the "reverse signal" issued to force a graphic update? (Sorry for my ignorance at this level. I've dived into the pool but haven't even reached the bottom yet.)
-
You're welcome :) Please don't apologize! We all have things to learn.
It's probably best to implement graphical items in Qt Quick. When you update the x and y properties in QML code, and the QML engine will repaint it automatically. You don't need to manually emit any signals.
But, the thing you really want is an animation. You just specify the start point, end point, and how long the motion should take -- there's no need to update (x, y) values over and over again. See http://qt-project.org/doc/qt-5.1/qtdoc/qtquick-usecase-animations.html
-
Once again thanks for spending time on such questions.
In more detail, I'm planning a number of simple math- and physics-related demos such as multibody orbital action under gravity or a fictitious force field, So the revised (x,y) positions really need a computational module unlike animation "in betweening". I'm hot for QtQuick because the underlying graphics uses OpenGL (rendering speed) which I expect to become important eventually. Thus, I shy away from JavaScript inside QML.
I think I understand generating a signal in QtQuick that could be used, for instance, to stop the C++ update loop. I'm looking for the key fact on how to trigger a graphics update on the QML side when my C++ code loop has completed. -
Ah, I see.
To send a signal from C++ back to QML, you use the same technique for signal-slot connections. All QML (JavaScript) functions act as slots that take QVariants as inputs:
@
// QML
Rectangle {
id: background
width: 800
height: 600Rectangle { id: freeBody color: "green" width: 100 height: 100 } function moveBody(x, y) { freeBody.x = x freeBody.y = y }
}
@
@
// C++
QQuickItem *item = view->rootObject();
connect(physicsEngine, SIGNAL(posChanged(QVariant,QVariant)),
item, SLOT(moveBody(QVariant,QVariant)));
@Since performance is important to you, be sure to upgrade to Qt 5.2 when it is released in November. It brings impressive improvements to Qt Quick rendering: http://blog.qt.digia.com/blog/2013/09/02/new-scene-graph-renderer/
If, for any reason, you want to make OpenGL calls yourself, have a look at the OpenGL classes in the Qt GUI module: http://qt-project.org/doc/qt-5.1/qtgui/qtgui-index.html
-
OK, great! You've supplied what I think is the key idea. Now I have some experience to gain (expand example to array of moving objects, deeper understanding of Qt, etc.) but am very encouraged. Thanks again, I'll now call this thread "solved".
-
Glad to hear. Happy coding!
-
Some great tips here. I'd like to add that one way to update the items' position could be to implement a QAbstractListModel in C++ with roles for 'x_pos' and 'y_pos' then you can use a Repeater to instantiate the points:
@
Repeater {
Rectangle {
x: x_pos
y: y_pos
width: 10
height: 10
}
model: myPointModel
}
@Then you may update all the points and do a single emit dataChanged() on the model.
This approach should be fine for hundreds or a few thousand points is my guess.
If you really need 10 thousands or 100,000s+ points you should look into creating a custom QQuickItem and add the points to a VBO and update that when the physics model has computed new positions.
-
Torgeir, you must be a mind reader. After seeing the advice of JKSH I've been thinking about how to implement a collection of mass points (perhaps dozens, but not 10K). You brought up the previously-unknown -- to me -- item "Repeater". Perhaps I should retitle the posting as "[SOLVED -- even better]".
Thanks.