0

I'm making some GUI through QT. I almost complete my work but I have a hard time dealing with Qthread. My goal is to measure the position of the motor (it moves) and display it on the Qtextbrowser while working another function in the main thread. When I wrote codes like below, people said I can't use QTextBrowser(Qwidget) directly in the thread, so I'm searching how to return location value to the main thread. Can you do me a favor? MDCE is a class in another header and the codes I attach are some parts of my first code.

void MotorPort::StartThread(MDCE* com, QTextBrowser* browser)
{

    thread1 = QThread::create(std::bind(&MotorPort::MeasureLocation,this,com,browser));
    thread1 -> start();
}

void MotorPort::MeasureLocation(MDCE* com, QTextBrowser* browser)
{
    double location;
    while(1)
    {
        location = CurrentLocation(com); \\return current position value
        browser->setText(QString::number(location));
        if (QThread::currentThread()->isInterruptionRequested()) return ;
    }
}

void MotorPort::stopMeasure()
{
    thread1->requestInterruption();
    if (!thread1->wait(3000))
    {
        thread1->terminate();
        thread1->wait();
    }
    thread1 = nullptr;
}
H.Y Kim
  • 13
  • 6
  • You may not access GUI stuff from other threads. Qt widgets are not thread-safe. I wrote a bit about this topic in my answer to [SO: How to alter Qt Widgets in WINAPI threads?](https://stackoverflow.com/a/61750145/7478597) (ignoring the Windows specific aspect of the question). – Scheff's Cat Jul 15 '20 at 10:33

1 Answers1

1

You should use the Qt signal/slot mechanism for iter-thread notification such as this. Firstly change your MotorPort class definition to declare a signal location_changed...

class MotorPort: public QObject {
    Q_OBJECT;
signals:
    void location_changed(QString location);
    ...
}

Now, rather than MotorPort::MeasureLocation invoking QTextBrowser::setText directly it should emit the location_changed signal...

void MotorPort::MeasureLocation (MDCE *com, QTextBrowser *browser)
{
    while (true) {
        double location = CurrentLocation(com);

        /*
         * Emit signal to notify of location update.
         */
        emit location_changed(QString::number(location));
        if (QThread::currentThread()->isInterruptionRequested())
            return ;
    }
}

Finally, update MotorPort::StartThread to connect the signal to the browser's setText slot...

void MotorPort::StartThread (MDCE *com, QTextBrowser *browser)
{
    connect(this, &MotorPort::location_changed, browser, &QTextBrowser::setText);
    thread1 = QThread::create(std::bind(&MotorPort::MeasureLocation, this, com, browser));
    thread1->start();
}
G.M.
  • 12,232
  • 2
  • 15
  • 18
  • Really Really Thank you so much! The problem is solved! Can you explain to me about 'this' in the connect function? because I made QT program just after studying C++ a month, I don't know about 'this'. – H.Y Kim Jul 16 '20 at 15:59
  • `this` is simply a `c++` [keyword](https://en.cppreference.com/w/cpp/language/this) used to refer to the current object instance -- nothing to do with Qt. Regarding the `connect` call you should read the [definitive documentation](https://doc.qt.io/qt-5/signalsandslots.html) regarding signals and slots -- it's a key feature of Qt and therefore important to understand thoroughly. – G.M. Jul 16 '20 at 17:58
  • I really appreciate your answer! Thank you for helping :) – H.Y Kim Jul 20 '20 at 05:56