[SOLVED] update message display from another thread



  • I have a QDialog to display some message with QLabel and QString. I need to update the message, replace the QString or append the newer. The message is from another QThread which is doing some calculation. And the calculation is triggered by a button on the dialog.

    I want the message being updated immediately when new result is available and there are many results come out at different time.

    Quesitons:

    1. QString and QLabel are right widgets for this purpose? message will not be very long.
    2. read online the QLabel::repaint() will update the display but it cannot be triggered from another thread. Qt will throw: Cannot send events to objects owned by a different thread. Without the repaint() call, the label will be updated at the end of all results are available. In Java there are Event Dispatcher thread and Worker thread. Qt may has similar things. Then what's the right way to update GUI display from other thread?


  • [quote author="user001" date="1373986405"]

    1. QString and QLabel are right widgets for this purpose? message will not be very long.
      [/quote]
      Yes they are.

    [quote author="user001" date="1373986405"]

    1. read online the QLabel::repaint() will update the display but it cannot be triggered from another thread. Qt will throw: Cannot send events to objects owned by a different thread. Without the repaint() call, the label will be updated at the end of all results are available. In Java there are Event Dispatcher thread and Worker thread. Qt may has similar things. Then what's the right way to update GUI display from other thread?[/quote]

    2. You never need to call of repaint() member of QLabel, QLabel::setText() is enough.

    3. If you find that QLabel doesn't get updated after setText(), there must be something wrong in other place. which cause your main thread get blocked.

    4. Make your object in sub-thread emit a signal with QString as parameter, connect this signal to your QLabel's setText() slot.


  • Lifetime Qt Champion

    Hi,

    Have a look at the MandelBrot example, It will help you understand how to achieve what you want to do.



  • [quote author="1+1=2" date="1373987064"]

    1. You never need to call of repaint() member of QLabel, QLabel::setText() is enough.
    2. If you find that QLabel doesn't get updated after setText(), there must be something wrong in other place. which cause your main thread get blocked.
    3. Make your object in sub-thread emit a signal with QString as parameter, connect this signal to your QLabel's setText() slot.[/quote]

    It will not update the display until the end of the calculation if repaint() is not called.

    I didn't use signal. I called a updateMessage(QString) which will do setText() and repaint() (if needed) from the calculation thread.

    I will try signal then.



  • By following mandelbrot example, i cannot make it works. The signal is not passed to slot. Following are those code:

    @#ifndef MYMSGTHREAD_H
    #define MYMSGTHREAD_H

    #include <QThread>

    class MyMsgThread : public QThread
    {
    Q_OBJECT
    public:
    MyMsgThread( QObject *parent = 0);

    signals:
    void newMsgAvailable(const QString&);
    void msgEnded();

    private:
    void run();
    void newMsg(QString);

    };

    #endif // MYMSGTHREAD_H@

    @#ifndef EXITDIALOG_H
    #define EXITDIALOG_H

    #include <QDialog>

    #include "../uiscreen.h"
    #include "../msgthread/mymsgthread.h"

    class QPushButton;
    class QString;
    class QLabel;

    class ExitDialog : public QDialog, public UiScreen
    {
    Q_OBJECT

    public:
    ExitDialog(MainWindow *mWindow);
    ~ExitDialog();

    virtual ReturnStatus showMe();
    virtual ReturnStatus hideMe();
    virtual ReturnStatus disposeMe();
    

    private:
    virtual ReturnStatus init();

    ReturnStatus showDialog();
    ReturnStatus confirmAgain();
    void createUI();
    
    
    QLabel *label;
    QPushButton *yesBtn;
    QPushButton *sureYesBtn;
    QPushButton *noBtn;
    QPushButton *updateMsgBtn;
    QString msg;
    bool msgUpdated;
    MyMsgThread myThread;
    

    private slots:
    void yesBtnClicked();
    void sureYesBtnClicked();
    void noBtnClicked();
    void updateMsgBtnClicked();
    void msgEnded();
    void updateMsg(const QString&);
    };

    #endif // EXITSCREEN_H@

    connect is done in ExitDialog::init()
    @ReturnStatus ExitDialog::init()
    {
    ReturnStatus status = ReturnStatus::Success;
    createUI();
    connect(&myThread, SIGNAL(newMsgAvailable(const QString&)), this, SLOT(updateMsg(const QString&)));
    connect(&myThread, SIGNAL(msgEnded()), this, SLOT(msgEnded()));

    cout << "ExitDialog::init()" << endl;
    return status;
    

    }@

    when updateMsgBtnClicked() is called, it will start() MyMsgThread. newMsgAvailable() will be emitted like this:

    @void MyMsgThread::newMsg(QString msgAvailable)
    {
    cout << "MyMsgThread::newMsg() msg=" << msgAvailable.toStdString() << endl;
    emit newMsgAvailable(msgAvailable);
    }@

    which is called from the MyMsgThread::run(). From the print out I can see the newMsg() method is called several times.

    Suppose the updateMsg(), which is the slot associated with newMsgAvailable(), will be triggered by the messaging system of Qt. But it is not here. Can you see anything wrong with my code?

    the UiScreen class is a regular abstract class (not a QObject) which defines some abstract methods.



  • Your slots are private, make them public, it may fix the problem.



  • [quote author="MaximAlien" date="1374001473"]Your slots are private, make them public, it may fix the problem.[/quote]

    I tried that before. I tested again with clean, build and run. Problem is still there.

    @public slots:
    void msgEnded();
    void updateMsg(const QString&);@



  • I think @MyMsgThread myThread;@ must be pointer @MyMsgThread *myThread;@ And you'll connect it like that:

    @connect(myThread, SIGNAL(newMsgAvailable(const QString&)), this, SLOT(updateMsg(const QString&)));
    connect(myThread, SIGNAL(msgEnded()), this, SLOT(msgEnded()));@



  • Of course it has to be created using @new@ opertator.



  • I found the problem. I have a while loop in the ExitDialog after started the thread. It is that loop blocked the GUI thread. My fault. Thank you for your help.



  • Great, Please mark your topic as SOLVED



  • How can I make it as solved?



  • On the top of this thread there is EDIT link, press it and you'll be able to edit your topic. Simply write [solved] update message display from another thread.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.