Change QML Screen from C++ thread
-
Hello,
My project consist in a simple touchscreen that enables few switchs by touching a button in the screen. When the application starts, runs in parallel a thread to launch a TCP socket (CreateSocket) and keeps listening for incoming connections.
When an external connection is linked I would like to show the same screen that is shown when you click on "Advanced" button (Advanced.qml).I red the following tutorials but I dont know how to define the signals/slots. How should I define the signals to activate the screen that I in local mode activate by clicking on the button "Advanced"
http://doc.qt.io/qt-4.8/qtbinding.html
https://wiki.qt.io/Receiving_signals_with_arguments_in_QML_from_C%2B%2BCan anybody help me? I would really aprreciate it! I am quite new by Qt!
dataprovider.h
Class DataProvider : public QObject { Q_OBJECT Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged) public: explicit DataProvider(QObject *parent = 0); void setValue(int newVal) { // <--- do your stuff to update the value if (newVal != m_value) { m_value = newVal; // qDebug() << "changing to" << newVal; emit valueChanged(newVal); // <--- emit signal to notify QML! } } int value() const { return m_value; } Q_INVOKABLE void on(int position); Q_INVOKABLE void adv_on(int switch_id, int position, bool is_off); void* CreateSocket(DataProvider *dataP); signals: void valueChanged(int i); // <--- actual signal used as notification in Q_PROPERTY private: int m_value; // <--- member value which stores the actual value
};
main.cpp
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); QQmlApplicationEngine engine; /*Every app needs an app engine*/ DataProvider dt; /*Class with properties to access from back-end to front-end*/ engine.rootContext() -> setContextProperty("dataProvider", &dt); engine.addImportPath(":/imports"); std::thread thread(&CreateSocket, &dt); engine.load(QUrl(QLatin1String("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec();
mainwindow.qml
import QtQuick.Extras 1.4 import QtQuick.Dialogs 1.2 Rectangle { id: root visible: true width: 800 height: 480 } // Extra objects removed to be irrelevant Advanced { id: advanced anchors.left: parent.left anchors.leftMargin: 450 anchors.top: parent.top anchors.topMargin: 408 anchors.bottom: parent.bottom anchors.bottomMargin: 26 anchors.right: parent.right anchors.rightMargin: 277 }
Advanced.qml
import QtQuick 2.4 Item { id: advance width: 74 height: 50 Image { id: logo width: 74 height: 50 fillMode: Image.PreserveAspectFit source: "images/Next.png" MouseArea { anchors.bottomMargin: 0 anchors.topMargin: 0 anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.fill: parent onClicked: { pageLoader.source = "AdvancedPage.qml"; } } } }
-
How should I define the signals to activate the screen that I in local mode activate by clicking on the button "Advanced"
Can you rephrase this? I have no idea what you mean.
In any case, you attach your
DataProvider
correctly. It is now available asdataProvider
in your whole QML application. So whenever you want to use it, you can simply call it, like:Button { onClicked: dataProvider.value = 1234 }
-
Hi sierdzio, thanks for your answer.
I try to explain it better:
The project consists on a switch driver with "local" and "remote" working modes.
In local mode you push few QML buttons that call C++ funtions ("on" and "adv_on") to activate GPIO outputs of a Raspberry Pi.
To work in remote mode, a TCP socket is running in a separate thread and listen for incoming connections. These remote clients send commands corresponding to button pressings in local mode, therefore I use the same C++ functions ("on" and "adv_on").Until now (local mode) I call C++ functions from QML (when I push the button with the mouse).
What I want to do now (remote mode) is to interact QML objects from the TCP socket written in C++ code .I would like to activate the QML button "Advance" from the C++ socket, as it would have been pressed with the mouse.
I hope to have explained better now.
Thanks for your support.
-
@JaviRodriguez Have you already check the QML / C++ integration documentation?
So following the example of
userNameChanged()/onUserNameChanged
from that article, I'd suggest that your C++ backend handling the remote connection and parsing the commands, emit a signal (i.e.remoteModeRequested
) whenever you know a remote connection has requested remote mode, so the QML handleronRemoteModeRequested
will load/show the proper QML view for remote mode. -
@Pablo-J-Rogina
Thank you for you answer. I red integration documentation you mention several times.
This is exactly the point where I am stuck on: I emit the Signal but i do not how to Connect It to the "Advanced.qml" nor to activate the command 'pageLoader.source = "AdvancedPage.qml";' to load the wished qml Page.Could you please write a small example for me bases on muy code? I would really appreciate it.
Thanks for your support.
-
@JaviRodriguez said in Change QML Screen from C++ thread:
I emit the Signal but i do not how to Connect It to the "Advanced.qml"
Could you show your QML code so far? (at least the part relevant to the signal handler)
-
@Pablo-J-Rogina
Hi. Following I show some relevant code.main.cpp
// I launch a new thread to run the socket DataProvider dt; /*Class with properties to access from back-end to front-end*/ std::thread thread(&CreateSocket, &dt);
dataprovider.cpp
void* CreateSocket(DataProvider *dataP){ //... some irrelevant code new_socket = accept(serverSocket, (struct sockaddr *)&serverAddr, (socklen_t*)&addr_size); if (new_socket > 0) { emit dataP->RemoteModeOn(); }}
dataprovider.h
class DataProvider : public QObject { Q_OBJECT signals: void RemoteModeOn (void); }
What I want is to call "AdvancedPage.qml" object in the same way that is done by "Advanced.qml" when I click with the mouse. I dont know how to tell the function RemoteModeOn to activate onClicked property of advanced.qml
advanced.qml
import QtQuick 2.4 Item { id: advance width: 74 height: 50 Image { id: logo width: 74 height: 50 fillMode: Image.PreserveAspectFit source: {"images/Next.png" dataProvider.QRemoteModeOn} MouseArea { anchors.bottomMargin: 0 anchors.topMargin: 0 anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.fill: parent onClicked: { pageLoader.source = "AdvancedPage.qml"; } } } }
I hope this extract of code is enough to understand what I am trying to do.
Thank you very much for your support. -
@JaviRodriguez I'd suggest to go through the documentation referred before again. Pay attention to the C++ signal and how that signal is handled in QML