Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QThread example to run a function in MainWindow on button click



  • Hello,

    I am trying to wrap my head around QThread and how it relates to MainWindow functions(NOT Main).

    I have a QT Application that has a MainWindow:

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    

    It has a button signal:

    void MainWindow::on_buttonRun_clicked()
    {
              startTheRun();   
    }
    
    

    That calls a function:

    void MainWindow::startTheRun(){
    //does stuff, gets information from ui like this:
    QString something = ui->textbox->text();
    )
    

    I want to run this function on a separate thread and still have access to the ui.

    Can someone point me to an example that does not us the Main.cpp but the MainWindow.cpp?

    I have found examples of this but none seem to have access to the MainWindow functions/objects from their 'run' methods. Clearly I am missing a link somewhere but just cannot wrap my head around it.

    Thanks,
    --James



  • @JSher
    That's because you are not allowed to do this in Qt! Your main UI thread only can access UI objects, any other threads must not. You must use signals/slots as required to communicate between UI thread and other threads. For example, a worker thread could emit() a signal when something happens, and the UI thread could have a slot connected to the signal so that it (the UI thread) can do whatever to update the UI.



  • @JonB

    So I created a big elaborate function that runs based off user input from the ui and in order to change it to a thread I have to write it all in the run() function and pass signals back and forth to get the information from the ui?

    Hmm this does not make sense to me.

    Is it possible to have the thread emit a signal to then run the function I have created?

    --James


  • Lifetime Qt Champion

    @JSher Do you have to pass user input all the time to your function?
    Usually you would do it once when starting the function. So, I don't see how it does not make sense. To my knowledge most GUI frameworks do not allow changes to GUI from other threads than main (GUI) thread, not only Qt.

    Yes, threads can emit signals too.



  • No I do not pass user input other than the initial start but I get paramaters from the ui such as ui->comboBox->currentText() all through the function

    --James



  • For instance in Java using Swing I just create a class in my MainGUI class like this:

    class MASummaryTask extends SwingWorker<Void, Void> {
    }
    

    It has full access to the GUI members etc. I just start it from the push button method like this:

    summaryTask = new MASummaryTask();
    summaryTask.addPropertyChangeListener(this);
    summaryTask.execute();
    

    So when I needed to go multithreaded I just run that function from the doInBackground() method of the thread class
    --James


  • Lifetime Qt Champion

    @JSher I still don't see the problem. Before starting this function collect all needed information from the UI elements and pass it as parameters to your function.



  • I was hoping to avoid this as it is a great deal of clean up as there is 30+ paramaters mostly pulled from the UI. Was hoping to just be able to run that function in a thread:)

    Thanks,
    --James



  • Ok so I can create threads and emit information back to the main GUI that can then use that information to update a vector or something of that nature to keep track of the work the threads are doing.

    What I cannot figure out is how to pass the information to the worker thread IE

    mThread = new MyThread(this);
    connect(mThread, SIGNAL(runThread()),this,SLOT(onRunThread()));
    mThread->start();
    

    In this code if I put paramaters for runThread(thread class) and same paramaters in onRunThread(gui class), the paramaters will be available to the main gui.

    So how do I pass paramaters to the thread worker? Here is the thread header:

    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    
    #include <QThread>
    
    class MyThread : public QThread
    {
        Q_OBJECT
    public:
        explicit MyThread(QObject *parent = 0);
        void run();
    signals:
        void runThread();
    
    public slots:
    
    };
    
    #endif // MYTHREAD_H
    

    Thanks,
    --James



    1. What was said above about ui in a secondary thread is correct and it's a limitation of some OSs, not of Qt. Having said that, however, getters like ui->comboBox->currentText() do not change the UI so they can be called in a secondary thread. The problem remains, however, of how do you prevent race conditions if you access the ui directly (what stops the user to change the index of ui->comboBox while the code is running?)
    2. if you just need to run a function in a different thread you don't need anything fancy coming from Qt, std::async does that
    3. QThread is not the thread, it's a container of the actual thread that lives on the tread that spawns it. this means emitting a signal of MyThread in the secondary thread is a race condition and slots of MyThread will be executed in the main thread, not the one it spawns. See this article for an explanation on how to use signals and slots in a secondary thread


  • @VRonin I want to run the function in another thread because I want to run the function across several threads(concurrently) and return a results vector to then be used to produce a spreadsheet once all the threads have finished.

    I can find no examples of pushing a button in a GUI, sending information to a thread function to run and then returning that information to the main thread.....

    Thanks,
    --James



  • @JSher said in QThread example to run a function in MainWindow on button click:

    sending information to a thread function to run and then returning that information to the main thread

    This is literally what std::async of vanilla C++ does, otherwise you can use QtConcurrent. You can just google examples of std::async



  • @JSher said in QThread example to run a function in MainWindow on button click:

    @VRonin I want to run the function in another thread because I want to run the function across several threads(concurrently) and return a results vector to then be used to produce a spreadsheet once all the threads have finished.

    This sounds like you want something like the functions in QtConcurrent. There is a difference between launching a single thread to do work asynchronously and using multiple threads to split the work. For the latter it makes sense to use a thread pool so you don't have to manage the number of threads yourself. QtConcurrent will use a thread pool internally which automatically adapts to the number of cores available. Probably, you want something like QtConcurrent::map or QtConcurrent::filter. These will give back a QFuture object. Which in turn can be handed to a QFutureWatcher so that you can connect signals from QFutureWatcher to update your GUI once the work is finished.


Log in to reply