0

I wanted to run few functions using different threads or QProcess or something which is more effective and also provide good performance. I am trying to build one gui for calibrator and as soon as I press calibrate button it needs to calibrate. For calibrating, I have some function to do that. However it takes some time to do this calibration process. Until my calibration is done my gui stays unresponsive. So what i am trying to do here is I would like to run that function in some parallel process or threads or some other things.

#include "widget.h"
#include "ui_widget.h"

#include <iostream>
#include <sstream>

#include <QtConcurrent/QtConcurrent>
#include <QFuture>

using namespace Eigen;

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


    ui->lineEdit->setReadOnly(true);
        
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_pressed()
{
    ui->plainTextEdit->appendHtml("<div style='color: green;'> Calibrating .....  </div>");

    QString body = ui->comboBox->currentText();
    int body = body.toInt();
    /*
    I want to run calib function here in separate thread or QtConcurrent so my gui will stay resposive even my function takes some time close to 1 min to do calibration
    
    */

}

void Widget::printReceivedBody(int x)
{
    
}

    

    
void Widget::Calib(int x)
{

    printReceivedBody(int x)
}

I checked some questions in stack and also in qt but unable to fix my problem.I found few questions but are trying to run executable. I can do via executable also but i would like to try above approach instead of going with executable.

I went to qt Documentaion but that documentation gives me more confusion :-(

Can someone suggest me how to do this?

user12071441
  • 95
  • 1
  • 8
  • You don't want to run an executable, but you're wondering if you should use QProcess? That's all QProcess does. So you can rule out QProcess if you don't want to run an executable. Look up examples for [QThread](https://doc.qt.io/qt-5/qthread.html). They are numerous. – JarMan Feb 09 '21 at 15:07
  • Or [QtConcurrent::run](https://doc.qt.io/qt-5/qtconcurrent.html#run) is another option. – JarMan Feb 09 '21 at 15:09
  • I answered a similar [question](https://stackoverflow.com/questions/66081991/get-multireturn-value-from-a-stdtuple-function-qtconcurrentrun) couple of days ago . – Kao Feb 09 '21 at 15:37

2 Answers2

1

A QProcess is meant to run an external process (an executable if it may be clearer). This is not what you need in my humble opinion.

What you may need is to use QThread to run your function of Calibration.

As you have already looked at the documentation, let us provide you some examples of how to execute functions using QThread in QT.

// execute a lambda
void MainWindow::onButton1Click()
{
    qDebug()<< "clicked";
    qDebug() << " the main thread id = " << QThread::currentThread();

    QThread* l_thread = QThread::create([&]()
    {
        qDebug() << "Running Thread " << QThread::currentThreadId() << " to emit signal only ";
        //emit dummy signal (for instance to refresh GUI
        //emit sigShowHide( !this->ui->pushButton_2->isVisible());
    });
    l_thread->start();
}

// example of an external function to execute

void test(int value1, int &value2)
{
    value2 = value1 + 1;
    return;
}

void MainWindow::onButton2Click()
{
    
    auto func = std::bind(test,value1, std::ref(value2));
    QThread* qthread = QThread::create(std::bind(test,value1, std::ref(value2)));
    qthread ->start();

}


// execute a method defined in MainWindow
void MainWindow::count()
{
    qDebug()<< "Counting";
}


void MainWindow::onButton3Click()
{
     ui->label->setText("Starting to count");
     auto function = std::bind(&MainWindow::count, this);
     QThread* l_thread = QThread::create(function);
     l_thread->start();
}

Update: As for you (in the updated question), you may run you calibration like the following

void Widget::on_pushButton_pressed()
{
    ui->plainTextEdit->appendHtml("<div style='color: green;'> Calibrating .....  </div>");

    QString body = ui->comboBox->currentText();
    int body = body.toInt();
    /*
    I want to run calib function here in separate thread or QtConcurrent so my gui will stay resposive even my function takes some time close to 1 min to do calibration
    */
    // LIKE THIS
    // for instance you can to call Widget::Calib with the arugment int x=15
    int x =15;
    auto func = std::bind(&Widget::Calib, this, x));
    QThread* qthread = QThread::create(func);
    qthread ->start();
    
    // if you want to wait for the QThread to finish before continuing, you can add 
    // qthread.wait()
}

Only for information, here is an example of the usage of a QProcess to launch a windows command line cmd.exe and execute somme copycommands with arguments

#include <QCoreApplication>
#include <Qdebug>
#include <QObject>
#include <QProcess>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QProcess* processus = new QProcess();
    QStringList args; 
    QString path("/path_accentué");
       
    args << "/C" << "copy" << "/toto/sfx.exe" << path;// "F:\\path_accentué";
    processus->start("cmd", args);  

    if (!processus->waitForStarted())
    {
        qDebug() << "Could not launch the process";
    }
    processus->write(s.c_str());
    if (!processus->waitForFinished(-1))
    {
        qDebug() << "Finished";
    }
    delete processus;
    return app.exec();
}
Pat. ANDRIA
  • 2,330
  • 1
  • 13
  • 27
  • 1
    What is the point of using Windows paths with cross-platform API? Always code with "/" separators and no letter. Especially with a BSD avatar. – Adrian Maire Feb 09 '21 at 21:28
  • Thanks for the suggestion. A bad copy paste from an example I have done many times ago. It's corrected – Pat. ANDRIA Feb 09 '21 at 21:51
  • I updated my response with your case if you may want to look at it and test – Pat. ANDRIA Feb 10 '21 at 10:22
  • You need to be on QT5.10 at least. In the doc, you should see : "This function was introduced in Qt 5.10." Also, ensure that in your QT project file (the .pro file) you have this clause QT +=core If something is already there, add "core" – Pat. ANDRIA Feb 10 '21 at 11:54
  • Sorry, You won't have `QThread::create` it if you do not have at least QT5.10 and if I'm not mistaken, `std::bind` is provided by C++11, so you have to compile with c++11 compatibility. An alternative to `QThread::create` is to use a worker class and associate it with a QThread ( https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/) – Pat. ANDRIA Feb 11 '21 at 12:41
  • @Pat.ANDRIA Thanks worker class helped me. I also have updated my qt to 5.12, so now i can try the method mentioned by you. But how can i give two arguments? For Example in the example given by you we are giving x as an input to calib function. But my question is how can i give two arguments using your method? Can I give like this auto func = std::bind(&Widget::Calib,this,x,y); – user12071441 Feb 19 '21 at 14:42
  • Yes, you can do it like you said with multiple arguments. If you may compile in C++17, you can also directly use `QThread::create(Function &&f, Args &&... args)` with the arguments. Reference is here (https://doc.qt.io/qt-5/qthread.html) – Pat. ANDRIA Feb 20 '21 at 08:44
  • use signal slot to update you GUI. You may look at my response [here] (https://stackoverflow.com/questions/66063164/how-can-i-change-gui-from-stdthread/66064301#66064301) - How can I change GUI from std::thread (or QThread). With this approach your GUI is updated by theG GUI Thread and not by the custom thread. No more need to click on the text edit to update it. Hope it helps – Pat. ANDRIA Feb 25 '21 at 11:38
  • @Pat.ANDRIA Thanks for all your insights. Now i have a better picture of qt and its functionalites. Regarding coming to this updating my gui i opened new thread because i thought for some beginners they might have this kind of problem and they can easily find question when it compares to comments. So here you can find the question (https://stackoverflow.com/questions/66418780/progress-bar-not-updating-during-iterations-but-updating-once-the-process-is-com) . I think i am doing it in a right way! But should see :-) – user12071441 Mar 01 '21 at 08:38
0

To maintain your GUI responsive, heavy processing needs to be performed in background threads.

You can run a thread using standard library:

#include <thread>
...
std::thread t(Calib, 42);
...
t.join();

Obviously, don't join synchronously in your main thread, otherwise you lose all the benefit of it.

For displaying the result, Qt does not allow to modify the GUI from background threads, so you must enqueue a signal, that is, configure connect with Qt::QueuedConnection.

Qt signals (QueuedConnection and DirectConnection)

Adrian Maire
  • 14,354
  • 9
  • 45
  • 85
  • don't use `join()` as it will block the main thread and consequently freeze the GUI – eyllanesc Feb 09 '21 at 18:44
  • @Adrian Maire. Thanks a lot. Will give a look into this. But I would prefer to use qt functionality in this for example QtConcurrent or something – user12071441 Feb 10 '21 at 09:54