Packaging a Streaming Program with Qt GUI

I have an app out of the box that uses multiple boost threads and works great with the command line interface.

I have packaged this program with a "wrapper" class so that I can run functions inside the program from the main Qt window.

For example:

netWrap.getImgs(ui->sampleNameEdit->text().toStdString());

      

Retrieves images from a network program with the sampleName parameter from the text field and invoked from the slot launched by the button.

This all works great, however some features like the one above can take about 20 seconds and it hangs on the GUI. I wish it wouldn't hang the GUI.

The obvious choice is to use QThread

, but I don't want to add additional classes to my program as this is just a supposed simple interface. Is there a way that I can run this function on a thread and wait for the completion signal without freezing the GUI?

EDIT: QFutures:

 QFuture<int> run = QtConcurrent::run(&(netWrap.getImgs), ui->sampleNameEdit->text().toStdString());

      

This leads to 4 errors, the most relevant are:

error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&networkWrapper::getImgs' [-fpermissive]
     QFuture<int> run = QtConcurrent::run(&(netWrap.getImgs), ui->sampleNameEdit->text().toStdString());

      

and

error: no matching function for call to 'run(int (networkWrapper::*)(std::string), std::string)'
     QFuture<int> run = QtConcurrent::run(&(netWrap.getImgs), ui->sampleNameEdit->text().toStdString());

      

+3


source to share


2 answers


You are not subclassing QThread to run something on another thread. QThread is used via signals / slots.

http://doc.qt.io/qt-5/qthread.html#started

By default, QThread :: run () starts an event loop allowing you to handle things like network events on another thread. This means that you hook into the QThread :: start signal, initiate your requests, and process them on a different thread. Then you can signal your main GUI thread with another signal you made and data is available.

If you only need to call some function on a different thread, use Qt Concurrent. It is much easier to use than QThread.

http://doc.qt.io/qt-5/qtconcurrent.html#run

void my_function(int a, double b) {
     .... do something in another thread ....
}
    ....
    auto some_function = std::function<void(int, double)>(&my_function);
    QFuture<void> ret = QtConcurrent::run(some_function, 10, 20.0);
    ....

      



Or without using the std :: function just use simple function pointers,

QFuture<void> ret = QtConcurrent::run(&my_function, 10, 20.0);

      

To call the members of a class, it is also as simple as

class Foo {
public:
     void foo(int a) {}
};

...
Foo *foo_instance = new Foo;
QFuture<void> ret = Qtconcurrent::run(foo_instance, &Foo::foo, 10);
...

      

And your function runs on a different thread. It's easy.

NOTE. Do not allow access to / GUI classes from non-GUI threads.

+3


source


You have to provide a pointer to an object as well as the address of the member function of the class and the required parameters, for example:

QFuture<void> future = QtConcurrent::run(netWrap, &networkWrapper::dbsChanged, ui->sampleNameEdit->text().toStdString());

      

You can check the status of asynchronous computations presented in the future, for example:

if(future.isRunning())
{
    // It is currently running
}

      



Or wait for the end:

future.waitForFinished();

      

QtConcurrent::run()

does not automatically provide progress information, eg QtConcurrent::mappedReduced()

. But you can have your own progress reporting mechanism using signals.

To signal completion, emitting a signal from a function that indicates that it is complete is an easy way.

+1


source







All Articles