3

The way I am working now is to connect a QTimer to the first slot, inside the first slot it will trigger another single-shot QTimer which will trigger the second slot... and so on.

If I update all of the widgets at once, the GUI will stuck for a flash of a second. But it is noticeable. So I want to avoid that.

But this is very difficult to write code. You have to add QTimer everywhere. Are there any better solutions?

EDIT: This is how I update my widget, maybe there is better way?

void UAVInfoView::updateDisplay()
{

    if (!visibleRegion().isEmpty()){
        info = _dataSrc->getUAVInfo(_id-1);
        if (info)
        {
            //if new package received try to do updating.
            if (_pakchk != info->_pakcnt){
                //only update the text if there is communication
                if (info->_communication != COMMSTATUS::WAIT4CONNECTION && info->_communication != COMMSTATUS::LOST)
                {
                    ui->plainTextEdit->setPlainText(tr("x: %1\ny: %2\nz: %3").arg(info->_pos[0]).arg(info->_pos[1]).arg(info->_pos[2]));
                }
                //only update the status indicator only if status changed.
                if (_status != info->_communication)
                {
                    switch (info->_communication){
                    case COMMSTATUS::CONNECTED:
                        ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:green;}");
                        ui->label_2->setText("On Line");
                        break;
                    case COMMSTATUS::LOST:
                        ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:red;}");
                        ui->label_2->setText("Lost");
                        break;
                    case COMMSTATUS::WAIT4CONNECTION:
                        ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:grey;}");
                        ui->label_2->setText("Off Line");
                    }
                }
            }
            //update the status and package counter to serve the state machine.
            _status = info->_communication;
            _pakchk = info->_pakcnt;
        }
    }
}

As you can see, it is just a bunch of default =, ! if else things...

Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
Nyaruko
  • 4,329
  • 9
  • 54
  • 105

5 Answers5

2

I'm not quite sure what you try to achieve, but if you want to trigger the execution of a specific set of functions with a timer, you probably have to introduce some controlling instance with a singe QTimer that you can use as often as you like.

Now that you said you don't want to update all your GUI widgets all the time, and I guess you are using QWidgets, you could also use the setUpdatesEnabled(bool) method to disable all effects of update() or repaint() calls.

If this doesn't help you, maybe you can explain you problem a bit more detailed?

Thargon
  • 424
  • 1
  • 3
  • 12
  • The problem is: If I update all of the widgets by one QTimer simultaneously, the GUI will stuck for a flash of a second. But it is noticeable. – Nyaruko Feb 27 '15 at 14:03
  • 1
    Such behaviour usually occurs in GUI with a lot of elements, which are all updated sequentially. To avoid that problem, first disable the update for all these GUI elements by using setUpdatesEnabled(bool), then change the content, re-enable updates and update everything only once. Some background: Everytime you change a single element, the whole GUI is repainted (even the elements that did not change). That can cause a lot of computation in some cases. – Thargon Feb 27 '15 at 14:06
  • by that do you mean to call the setUpdatesEnabled for the parent widget which contains many things that needs to be updated? – Nyaruko Feb 28 '15 at 05:32
  • basically, something like this? this->setUpdatesEnabled(false); call each child widgets' update function; this->setUpdatesEnabled(true)? – Nyaruko Feb 28 '15 at 05:37
  • Basically yes, but you don't call the update function of each child. Just disable updates for the parent and change the content of all children as required. Now the children internally look different than on your screen, because you changed them, but the changes did not get painted yet. Just re-enable updates for the parent and repaint it (only the parent) . – Thargon Mar 01 '15 at 09:22
2

You can call them in a slot connected to a timer with a certain interval. Your slot that is connected to the timer could be like :

void myClass::onTriggered()
{
    switch(turn){
       case 0:   
           slot1();
           break;
       case 1:
           slot2();
           break;
       ...
    }

    turn++;
    if(turn>=numberOfSlots)
        turn = 0;
}

This way each time one slot is called and they are called sequentially.

Nejat
  • 31,784
  • 12
  • 106
  • 138
1

Although I believe the problem is somewhere else, I'll give you one possible solution. You could use a state machine. Just have one slot that is triggered by your timer in which you call some other functions based on the current state.

...
connect(&timer, SIGNAL(timeout()), this, SLOT(myStateSlot()));
timer.start(1000);
...


void MyClass::myStateSlot()
{
    switch(state)
    {
    case State_Start:
        operation1();
        // you can change the state here.. or somewhere else.. up to your design
        break;
    case State_Two:
        operation2();
        break;
    case State_End:
        timer.stop();
        break;
    }
}
thuga
  • 12,601
  • 42
  • 52
1

Your problems likely stem from the relative slowness of the QPlainTextEdit. Use a QLabel instead. Otherwise, the code looks fine. Make sure that if there are multiple consequent calls to updateDisplay, they should all happen without the control returning to the event loop between the calls.

The below is wrong, since each processEvents forces a repaint of the widgets.

w.updateDisplay();
QCoreApplication::processEvents();
w.updateDisplay();
QCoreApplication::processEvents();

You might be invoking processEvents() without realizing it. It is effectively invoked every time you return from QObject::event() and the event queue is empty at the time. Also note that QObject::event() is the caller of queued slot calls. Thus, if you have a queued connection to a slot, the control returns to the event loop right after the slot returns.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Thanks! I will give a try! But why would you say the QPlainTextEdit is slower the the label? – Nyaruko Feb 27 '15 at 17:01
  • 1
    @Nyaruko Um, because it is slower. Generally speaking, `QPlainTextEdit` is best suited for static displays. It fails horribly if you wish to update it often - it's completely useless as a realtime log viewer, for example. – Kuba hasn't forgotten Monica Feb 27 '15 at 17:05
0

If the update method is complex, you should try QtConcurrent::map() to run the update in another thread. Then you need no delay, because you'll get notified from map() when the updates are finished.

weeska
  • 439
  • 3
  • 7