Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt GUI math application hangs out GUI while computing

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 :)

like image 659
yak Avatar asked Sep 30 '13 13:09

yak


2 Answers

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();
}
like image 152
TheDarkKnight Avatar answered Sep 18 '22 02:09

TheDarkKnight


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.

like image 43
andref Avatar answered Sep 17 '22 02:09

andref