How to get Data from GUI into a thread?
-
wrote on 19 Jun 2023, 14:11 last edited by
Hello,
i am trying to get some GUI data which is entered in QtextEdits, etc... into a thread. I run the thread with thread_calculateutilization.start();
And it works perfectly fine....
Now i am asking what is the best way to exchange some data between my mainwindow and the thread? When i use slots and connects then i noticed that it can make some trouble because obviously the run() function is called before the emit signal reaches the thread. I also tried to hand over a struct with connects but it did not work...
Now with this code i initialize my struct and set up the connects for my thread in:mainwindow.cpp
// Create Struct for entered UI Data UIData = { // Lineconfig "Select type", 1, "0", "0", "0", 1, // Shuttleconfig "Select type", "0", "0", // Loaderconfig "Select type", "0", "0", "0", // Unloaderconfig 0, "Select type", "0", "0", "0", // Parameters "0", "0", "0", "0", "0", "0", "0" }; // set connects for our calculation thread connect(&thread_calculateutilization, &QThread::started, &utilizationcalculator, &calculationutilization::run); connect(&utilizationcalculator, &calculationutilization::calculationdone, this, &MainWindow::UtilizationTimeCalculated); connect(this, &MainWindow::started_calculationthread, &utilizationcalculator, &calculationutilization::recvdata); utilizationcalculator.moveToThread(&thread_calculateutilization);
When i click the specific button i emit a signal to the thread with my struct as a handover parameter and start the thread afterwards.
//Button actions void MainWindow::on_pushButton_CalculateTime_clicked() { emit started_calculationthread(UIData); thread_calculateutilization.start(); }
I Have defined my thread, struct and signal like this in the:
maindow.h
private: Ui::MainWindow *ui; QThread thread_calculateutilization; calculationutilization utilizationcalculator; struct DataComingFromUI { // Lineconfig QString Linetype; int MachineLines; QString MachinesLine1; QString MachinesLine2; QString SpacingBetweenMachines; bool LoadedStartupState; // Shuttleconfig QString Shuttletype; QString NumberStationsShuttle; QString NumberShelvesShuttle; // Loaderconfig QString Loadertype; QString NumberStationsLoader; QString NumberShelvesLoader; QString NumberLoaders; // Unloaderconfig bool UnloaderActive; QString Unloadertype; QString NumberStationsUnloader; QString NumberShelvesUnloader; QString NumberUnloaders; // Parameters QString LoadingTimeMachines; QString UnloadingTimeMachines; QString ShuttleVelocity; QString ShuttleAcceleration; QString ShuttleHomingTime; QString ShuttleLevelingTime; QString LoaderVelocity; }; DataComingFromUI UIData; signals: void started_calculationthread(const DataComingFromUI& data);
Now in the class for my thread i have defined things like this:
calculationutilization.h
#ifndef CALCULATIONUTILIZATION_H #define CALCULATIONUTILIZATION_H #include <QObject> class calculationutilization : public QObject { Q_OBJECT public: explicit calculationutilization(QObject *parent = nullptr); signals: void calculationdone(int time); private: int m_MachinesLine1 = 0; int m_MachinesLine2 = 0; struct DataComingFromUI { // Lineconfig QString Linetype; int MachineLines; QString MachinesLine1; QString MachinesLine2; QString SpacingBetweenMachines; bool LoadedStartupState; // Shuttleconfig QString Shuttletype; QString NumberStationsShuttle; QString NumberShelvesShuttle; // Loaderconfig QString Loadertype; QString NumberStationsLoader; QString NumberShelvesLoader; QString NumberLoaders; // Unloaderconfig bool UnloaderActive; QString Unloadertype; QString NumberStationsUnloader; QString NumberShelvesUnloader; QString NumberUnloaders; // Parameters QString LoadingTimeMachines; QString UnloadingTimeMachines; QString ShuttleVelocity; QString ShuttleAcceleration; QString ShuttleHomingTime; QString ShuttleLevelingTime; QString LoaderVelocity; }; public slots: void run(); void recvdata(const DataComingFromUI& data); }; #endif // CALCULATIONUTILIZATION_H
My question now is: what is the best way to transfer the data in my struct from my mainwindow/ui with a button click to the thread and then start the thread?
Best Regards
-
Hello,
i am trying to get some GUI data which is entered in QtextEdits, etc... into a thread. I run the thread with thread_calculateutilization.start();
And it works perfectly fine....
Now i am asking what is the best way to exchange some data between my mainwindow and the thread? When i use slots and connects then i noticed that it can make some trouble because obviously the run() function is called before the emit signal reaches the thread. I also tried to hand over a struct with connects but it did not work...
Now with this code i initialize my struct and set up the connects for my thread in:mainwindow.cpp
// Create Struct for entered UI Data UIData = { // Lineconfig "Select type", 1, "0", "0", "0", 1, // Shuttleconfig "Select type", "0", "0", // Loaderconfig "Select type", "0", "0", "0", // Unloaderconfig 0, "Select type", "0", "0", "0", // Parameters "0", "0", "0", "0", "0", "0", "0" }; // set connects for our calculation thread connect(&thread_calculateutilization, &QThread::started, &utilizationcalculator, &calculationutilization::run); connect(&utilizationcalculator, &calculationutilization::calculationdone, this, &MainWindow::UtilizationTimeCalculated); connect(this, &MainWindow::started_calculationthread, &utilizationcalculator, &calculationutilization::recvdata); utilizationcalculator.moveToThread(&thread_calculateutilization);
When i click the specific button i emit a signal to the thread with my struct as a handover parameter and start the thread afterwards.
//Button actions void MainWindow::on_pushButton_CalculateTime_clicked() { emit started_calculationthread(UIData); thread_calculateutilization.start(); }
I Have defined my thread, struct and signal like this in the:
maindow.h
private: Ui::MainWindow *ui; QThread thread_calculateutilization; calculationutilization utilizationcalculator; struct DataComingFromUI { // Lineconfig QString Linetype; int MachineLines; QString MachinesLine1; QString MachinesLine2; QString SpacingBetweenMachines; bool LoadedStartupState; // Shuttleconfig QString Shuttletype; QString NumberStationsShuttle; QString NumberShelvesShuttle; // Loaderconfig QString Loadertype; QString NumberStationsLoader; QString NumberShelvesLoader; QString NumberLoaders; // Unloaderconfig bool UnloaderActive; QString Unloadertype; QString NumberStationsUnloader; QString NumberShelvesUnloader; QString NumberUnloaders; // Parameters QString LoadingTimeMachines; QString UnloadingTimeMachines; QString ShuttleVelocity; QString ShuttleAcceleration; QString ShuttleHomingTime; QString ShuttleLevelingTime; QString LoaderVelocity; }; DataComingFromUI UIData; signals: void started_calculationthread(const DataComingFromUI& data);
Now in the class for my thread i have defined things like this:
calculationutilization.h
#ifndef CALCULATIONUTILIZATION_H #define CALCULATIONUTILIZATION_H #include <QObject> class calculationutilization : public QObject { Q_OBJECT public: explicit calculationutilization(QObject *parent = nullptr); signals: void calculationdone(int time); private: int m_MachinesLine1 = 0; int m_MachinesLine2 = 0; struct DataComingFromUI { // Lineconfig QString Linetype; int MachineLines; QString MachinesLine1; QString MachinesLine2; QString SpacingBetweenMachines; bool LoadedStartupState; // Shuttleconfig QString Shuttletype; QString NumberStationsShuttle; QString NumberShelvesShuttle; // Loaderconfig QString Loadertype; QString NumberStationsLoader; QString NumberShelvesLoader; QString NumberLoaders; // Unloaderconfig bool UnloaderActive; QString Unloadertype; QString NumberStationsUnloader; QString NumberShelvesUnloader; QString NumberUnloaders; // Parameters QString LoadingTimeMachines; QString UnloadingTimeMachines; QString ShuttleVelocity; QString ShuttleAcceleration; QString ShuttleHomingTime; QString ShuttleLevelingTime; QString LoaderVelocity; }; public slots: void run(); void recvdata(const DataComingFromUI& data); }; #endif // CALCULATIONUTILIZATION_H
My question now is: what is the best way to transfer the data in my struct from my mainwindow/ui with a button click to the thread and then start the thread?
Best Regards
emit the result within your calculationdone() signal.
-
emit the result within your calculationdone() signal.
wrote on 20 Jun 2023, 06:06 last edited by@Christian-Ehrlicher
Yeah i know how to do that and it works.
But that is the other way around (from thread to gui).
Now i want to get all the GUI Data into my thread before working with the thread. (basically the struct DataComingFromUI in mainwindow.h) i declared it as private. But i dont get it to work as a handover parameter... -
@Christian-Ehrlicher
Yeah i know how to do that and it works.
But that is the other way around (from thread to gui).
Now i want to get all the GUI Data into my thread before working with the thread. (basically the struct DataComingFromUI in mainwindow.h) i declared it as private. But i dont get it to work as a handover parameter...wrote on 20 Jun 2023, 06:25 last edited by@mullman123
Exactly in the opposite direction --- send data from UI thread to secondary thread via signals, just as you would the other way round. Note that you do not pass data in aconnect()
call, you only specify what the type of the data will be. We do not know whatWhen i use slots and connects then i noticed that it can make some trouble because obviously the run() function is called before the emit signal reaches the thread
means.
If you need help produce a minimal, compilable example of what you try --- you don't need hundreds of
QString
s to illustrate a problem. Whether you pass a wholestruct
or a singleint
the principle is the same. -
@mullman123
Exactly in the opposite direction --- send data from UI thread to secondary thread via signals, just as you would the other way round. Note that you do not pass data in aconnect()
call, you only specify what the type of the data will be. We do not know whatWhen i use slots and connects then i noticed that it can make some trouble because obviously the run() function is called before the emit signal reaches the thread
means.
If you need help produce a minimal, compilable example of what you try --- you don't need hundreds of
QString
s to illustrate a problem. Whether you pass a wholestruct
or a singleint
the principle is the same.wrote on 20 Jun 2023, 06:42 last edited by mullman123@JonB
Yeah i tried it with a struct but there is an issue with compiling it. Even though it does not have any complains for passing it to the functions. Is there anything wrong with my connect? Or do i need to do anything specific with my struct? -
@JonB
Yeah i tried it with a struct but there is an issue with compiling it. Even though it does not have any complains for passing it to the functions. Is there anything wrong with my connect? Or do i need to do anything specific with my struct?@mullman123 no, your code is wrong.
struct DataComingFromUI is defined twice!
once in
calculationutilization
and once inmaindow
also you might get away without it, but I would recommend adding a copy operator to your struct as well
-
@mullman123 no, your code is wrong.
struct DataComingFromUI is defined twice!
once in
calculationutilization
and once inmaindow
also you might get away without it, but I would recommend adding a copy operator to your struct as well
wrote on 20 Jun 2023, 07:32 last edited by@J-Hilk
Now i got it working. Thanks so far!
The next problem would be how to get my Thread to wait until the data is received from the emit before finishing?
Or is there a better way to pass over my struct to the run process of my thread?
After calling my emit to the thread it does not arrive because i think the thread finishes before it. I am basically calling the recvdata() slot.My Button action in MainWindow.cpp:
//Button actions void MainWindow::on_pushButton_CalculateTime_clicked() { setGUIDataCalculateThread(); emit started_calculationthread(UIData); thread_calculateutilization.start(); }
My thread/connect in calculationutilization.cpp
void calculationutilization::run() { } void calculationutilization::recvdata(DataComingFromUI& data) { data.Linetype = "Hello"; }
-
wrote on 20 Jun 2023, 07:37 last edited by
If I understood correctly you have overwritten the run() method of your thread. Then, signal slot connections won't work because no event loop is running inside your thread. It is also not good practice anymore to override the run() method. Instead, just start your thread and the default implementation of run() will start an event loop. You then place a worker object inside that thread with a slot that would be connected to started_calculationthread(UIData). Your slot will get the data and your can use it to do your actual work.
A slight shortcut is to use
QThread::create([](const DataComingFromUI &data){ /* do the work */ }, UIData);
Or just capture UIData with the lambda. In addition, you need to make sure to delete the thread object created by QThread::create by connecting to its finished signal.
-
@J-Hilk
Now i got it working. Thanks so far!
The next problem would be how to get my Thread to wait until the data is received from the emit before finishing?
Or is there a better way to pass over my struct to the run process of my thread?
After calling my emit to the thread it does not arrive because i think the thread finishes before it. I am basically calling the recvdata() slot.My Button action in MainWindow.cpp:
//Button actions void MainWindow::on_pushButton_CalculateTime_clicked() { setGUIDataCalculateThread(); emit started_calculationthread(UIData); thread_calculateutilization.start(); }
My thread/connect in calculationutilization.cpp
void calculationutilization::run() { } void calculationutilization::recvdata(DataComingFromUI& data) { data.Linetype = "Hello"; }
@mullman123 said in How to get Data from GUI into a thread?:
void calculationutilization::run()
{}
seeing this makes me doubt your thread is actually doing thread things.
What exactly is your set up, what method of "thread" are you using
Can you elaborate more, what exactly do you want to archive?
Is it simply some (long taking) operation on your data in the struct ?If so, then there are easier methods than sub classing QThread, what you seem to have done here. In fact subclassing Thread is very, very early the way to go
-
@mullman123 said in How to get Data from GUI into a thread?:
void calculationutilization::run()
{}
seeing this makes me doubt your thread is actually doing thread things.
What exactly is your set up, what method of "thread" are you using
Can you elaborate more, what exactly do you want to archive?
Is it simply some (long taking) operation on your data in the struct ?If so, then there are easier methods than sub classing QThread, what you seem to have done here. In fact subclassing Thread is very, very early the way to go
wrote on 20 Jun 2023, 07:47 last edited by@J-Hilk
What i want to do is use the data from the struct to calculate a simulation of many automated processes.
The Data from the GUI basically sets the parameters and config for the calculation.
Since it can happen that the calculation might take some time i defined it as a thread.The function is not yet implemented because i struggled with handing over the data from GUI.
But the thread will do kinda lengthy calculations. -
@J-Hilk
What i want to do is use the data from the struct to calculate a simulation of many automated processes.
The Data from the GUI basically sets the parameters and config for the calculation.
Since it can happen that the calculation might take some time i defined it as a thread.The function is not yet implemented because i struggled with handing over the data from GUI.
But the thread will do kinda lengthy calculations.alright, so not a fire and forget function, but you want to access the results.
I would suggest the worker thread approach than.
Make your calculating/processing class. make it so that your interface to that class is slots (passing data to the class) and signals (passing data from the class away) only.
When that is working, you can (literally) move it to its own thread in like 10 lines of code
I have this project, that covers all common ways of "threading "in qt:
https://github.com/DeiVadder/QtThreadExampletake a closer look at the "workerObject" project
https://github.com/DeiVadder/QtThreadExample/tree/master/projects/WorkerObject -
alright, so not a fire and forget function, but you want to access the results.
I would suggest the worker thread approach than.
Make your calculating/processing class. make it so that your interface to that class is slots (passing data to the class) and signals (passing data from the class away) only.
When that is working, you can (literally) move it to its own thread in like 10 lines of code
I have this project, that covers all common ways of "threading "in qt:
https://github.com/DeiVadder/QtThreadExampletake a closer look at the "workerObject" project
https://github.com/DeiVadder/QtThreadExample/tree/master/projects/WorkerObjectwrote on 20 Jun 2023, 08:02 last edited by@J-Hilk
Thanks for your detailed information.
I will try my luck and give some info what i achieved.Thanks to everybody so far for the fast help.
-
wrote on 21 Jun 2023, 07:02 last edited by
I have stumbled on the same kind of problems over and over again. You can find a simple wrapper for this kind of multithreading on GitHub: https://github.com/SimonSchroeder/QtThreadHelper
In your specific case you could just write it like this:
workerThread([](const DataComingFromUI & data){ ... }, UIData);
No need to write a full class or something. It is basically an extension of QThread::create which will avoid memory leaks. The only thing to consider is that a new thread is created whenever you want to execute this. With enough work inside the function the overhead of creating a thread is negligible. Because the GUI will not freeze you have to be careful that this cannot be started several times at once such that not too many threads are running at the same time.
BTW, Qt also has QtConcurrent::run(). This uses a thread pool in the background (so, no oversubscribing of the CPU cores) and it makes it quite easy to run a function inside a thread as well.
1/13