I have a simple GUI for my application = I have to set some input parameters for my math function, then click 'compute' button, and function starts. Math function(s) are written in pure C so there are no objects, just functions.
It looks like this:
#include "mymath.h"
class myMath : public QMainWindow
{
Q_OBJECT
// ...
void compute();
};
void myMath::compute()
{
//get parameters from gui
call_C_fun();
// save results to GUI
}
The main problem with this code is that when I click 'compute' (it does sooo much computation, it takes up to 5 minutes or so) it hangs out my GUI so I can't do anything else (I can't even see my GUI, window is "frozen" for the time that computation is running. After the function is finished, it prints out results on QLabels, and GUI is once again "alive". How can I solve this? I don't want my GUI to be "frozen" when computation takes time. Any ideas? I thought about QThread
- but I'm kinda new in threads-thing, so please, give simple-easy-to-understand answers for newbie :)
Factor out the computation to another thread, like this: -
// This is the object that will run the computation on a different thread
class Computation : public QObject
{
signals:
void Finished();
public slots:
void Compute();
};
Then create the other thread in your main window class and start it running: -
class MyMath : public QMainWindow
{
public:
void StartComputation();
};
MyMath::StartComputation()
{
QThread* pThread = new QThread;
Computation* pComputation = new Computation;
// move computation to the new thread
pCompuation->moveToThread(pThread);
// Note Qt5 connection style
// ensure the computation starts when the thread starts
connect(pThread, &QThread::started, pComputation, &Computation::Compute);
// when computation is finished, quit the thread
connect(pComputation, &Compute::Finished, pThread, &QThread::quit);
// have the thread tidy up when finished
connect(pThread, &QThread::finished, pThread, &QThread::deleteLater);
// start it!
pThread->start();
}
Instead of rolling your own threading stuff, try the built-in QtConcurrent namespace. It's easier, optimized and less error prone. There is no need to worry about moving stuff to other threads and performing explicit synchronization using mutexes.
QtConcurrent::run uses an internal thread pool to run your tasks and returns a QFuture with which you can interact using QFutureWatcher and signals & slots. The names may sound complicated, but the code is very simple:
class MyMath : public QObject
{
Q_OBJECT
public:
explicit MyMath(QObject* parent) : QObject(parent) {
this->watcher = new QFutureWatcher(this);
connect(this->watcher, SIGNAL(finished()),
this, SLOT(computationFinished()));
}
public slots:
void compute() {
// This one is called by the user. Retrieve
// the computation arguments (whatever they
// may be), start the computation using
// QtConcurrent::run and prepare to receive
// the results.
//
// Maybe update the UI to tell the user that
// the computationis being performed?
Args args = getSomeArgs();
QFuture<Result> res = QtConcurrent::run(this, &MyMath::internalCompute, args);
this->watcher->setFuture(res);
}
void computationFinished() {
// The computation is done. Update the GUI
// to display the results. Done.
}
private:
QFutureWatcher<Result>* watcher;
Args getSomeArgs() const {
// return arguments needed by compute.
}
Result internalCompute(Args args) const {
// perform very expensive math.
}
};
Update. After Merlin069's comment, I think it's not wise to recommend using the more complex operations provided by QtConcurrent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With