1
votes

My QLabel is not updating from slot. I run sender class in separate thread using QObject::moveToThread:

QThread* serviceThread = new QThread;
service = new ExportService();
connect(service,SIGNAL(stateChanged(Service::ServiceState)),
        this,SLOT(statusChanged(Service::ServiceState)));
service->moveToThread(serviceThread);
serviceThread->start();

Service object send states by emiting signal with ServiceState enum value, this signal is captured by QDialog slot:

void Dialog::statusChanged(Service::ServiceState s)
{
    switch (s) {
    case Service::IDLE:
        qDebug() << "Idle";
        ui->label->setText("Service send response succesfully.");
        break;
    case Service::REQUESTING:
        qDebug() << "Requesting";
        ui->label->setText("Requesting response from service...");
        break;
    case Service::ERROR:
        qDebug() << "Error";
        ui->label->setText("Error. Cannot get response from service.");
        break;
    default:
        break;
    }
}

After operation on the object which emits a signal twice, the first time with value of Service::REQUESTING and second time with value of Service::IDLE my QLabel change text only to "Service send response succesfully.". In the console I can see that qDebug() << "Requesting"; works so the state changed successfully.

After comment out ui->label->setText("Service send response succesfully."); label has changed to requesting state but after the whole operation was done ie i see "Requesting" in console then "Idle" and after that QLabel has changed.

What should I do if I want to see QLabel changing in realtime?

2
How long is it in "requesting" state? Maybe it goes just too fast? Is the UI responsive in between?Frank Osterfeld
I think the same like @FrankOsterfeld . It seems QLabel updates too fast and you can't fixed changes.t3ft3l--i
You also need to explicitly specify Qt::QueuedConnection In your connect() call for objects moved to another thread.anonymous
@FrankOsterfeld It is in "Requesting" state for ~1 second, UI is responsive when requesting response. I will try with more complex request and see if it works then.Sajmplus
You may want to try and process the events in the event loop after setting the text of the label. See QApplication::processEvents().erl

2 Answers

3
votes

First, try adding update() after setText(), chances are setText() doesn't automatically schedule a repaint() for the QLabel, if it works then problem solved.


However, for update() function:

http://doc.qt.io/qt-4.8/qwidget.html#update

void QWidget::update()

This function does not cause an immediate repaint; instead it schedules a paint event for processing when Qt returns to the main event loop. This permits Qt to optimize for more speed and less flicker than a call to repaint() does.

> Calling update() several times normally results in just one paintEvent() call.

which basically says, if you call them too frequently and some of them will be optimized away.

If this is not the desired behaviour, try adding a forced repaint() after setText(), or using a timer to schedule periodical forced repaints.

http://doc.qt.io/qt-4.8/qwidget.html#repaint


UPDATE

As is mentioned in the comment, forcing repaint() isn't good solution.

This answer is intended to provide an analysis of the cause of the code's behaviour and the "forced repaint()" suggestion is more of a way to verify this analysis than a solution to the problem.

However, without further information on the purpose of the program, it's very difficult to provide further suggestions.

1
votes

The status change from requesting to idle happens quickly. The text "Requesting response from service..." is not on the label long enough for the eye to see it.

The fact that "Requesting ..." is in the debug output is proof of this, but if you want more proof there are other things you could do:

  1. use a counter that counts each time the statusChanged() function is called and display this either in the same label as the status text (in addition to the status text) or a different label.

  2. add a high accuracy timer output to the debug outputs - see how close together the status changes are.

  3. use a couple of check boxes, one for idle status and one for requesting status. Change their state when the appropriate status is received. That is whne the first Idle is received set the check box to checked. When the next idle is received toggle it to unchecked.

I would just accept that the debug outputs are telling the truth and move on.