Unsolved GUI does not have time to update?
-
I open the valve and immediately update the paint buttons:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { //*** emergency = new EmergencyResetOfPressure(); connect(emergency, SIGNAL(openValveSignal(int)), this, SLOT(openValve(int))); connect(emergency, SIGNAL(closeValveSignal(int)), this, SLOT(closeValve(int))); //emergency->start(); emergency->moveToThread(emergency); connect(this, SIGNAL(destroyed(QObject*)), emergency, SLOT(quit())); connect(ui->emergencyButton, SIGNAL(clicked(bool)), this, SLOT(emergencyRelease())); //*** } void MainWindow::emergencyRelease() { if (!emergency->isRun) { emergency->start(); //emit emergencyReleaseSig(); } else { emergency->quit(); //How do I stop the flow? Ideally, abort "run" and start the stop algorithm } } void MainWindow::openValve(int id) { //QString style = QString(DEFAULT_STYLE_BUTTON) + QString(DEFAULT_BACKGROUND_BUTTON); //valveButton[id]->setStyleSheet(style); QString str = "Valve №" + QString::number(id+1); valveButton[id]->setEnabled(false); if (valve->open(id)) { if (manualModeState) valveButton[id]->setEnabled(true); //valveButton[id]->setPalette(QPalette(Qt::green)); //valveButton[id]->setStyleSheet(VALVE_OPEN_COLOR); QString style = QString(DEFAULT_STYLE_BUTTON) + QString(DEFAULT_BACKGROUND_BUTTON); valveButton[id]->setStyleSheet(style); ui->mainLabel->setText(str + " opened! :)"); } else { if (manualModeState) valveButton[id]->setEnabled(true); ui->mainLabel->setText("Cant open " + str); remoteStatus(0); } } void MainWindow::closeValve(int id) { QString str = "Valve №" + QString::number(id+1); valveButton[id]->setEnabled(false); if (valve->close(id)) { if (manualModeState) valveButton[id]->setEnabled(true); //valveButton[id]->setPalette(style()->standardPalette()); valveButton[id]->setStyleSheet(""); ui->mainLabel->setText(str + " closed! :)"); } else { if (manualModeState) valveButton[id]->setEnabled(true); ui->mainLabel->setText("Cant close " + str); remoteStatus(0); } } EmergencyResetOfPressure::EmergencyResetOfPressure(QObject *parent) : QThread(parent) { } EmergencyResetOfPressure::~EmergencyResetOfPressure() { } void EmergencyResetOfPressure::run() { isRun = true; for (int i = 0; i<7; i++) { msleep(200); emit openValveSignal(i); } for (int i = 0; i<7; i++) { msleep(200); emit closeValveSignal(i); } }
If done without sleep/msleep, the buttons are not painted over. Why?
P.S. valve->close/valve->open takes some time (60-70ms), because there is communication on the port. But is not the if() expected to wait for the response of the function? -
Hi,
What you are doing is blocking the event loop that's why you don't see any GUI update. You are basically chaining blocking methods that takes long time to run several times in a row.
-
I think SGaist provide correct answer, setStyleSheet is slow. Just some tips,
1 : you have memory leak
emergency = new EmergencyResetOfPressure;
It should be
emergency = new EmergencyResetOfPressure(this);
Please find a great book of c++ and study how to handle resource by parent and child mechanism of Qt, this could make your life easier if you want to develop things with Qt.
2 : this line is weird
emergency->moveToThread(emergency);
it loooks weird to move the QThread into the same QThread, unless I do not know what would happen under this case
-
@tham said in GUI does not have time to update?:
setStyleSheet is slow
So... How can I update the appearance of the buttons if I want to switch the valves as quickly as possible?
ui->mainLabel->setText(str + " opened! :)"); also does not work.
The code should not be consistently executed? I do not understand anything ...@tham said in GUI does not have time to update?:
emergency->moveToThread(emergency);
it loooks weird to move the QThread into the same QThread
As I understand it, the object is created in the main thread, so you need to reassign it to another thread
-
@maratk1n "As I understand it, the object is created in the main thread, so you need to reassign it to another thread" - this is wrong.
A QThread instance maintains a thread - it does not run in the thread it is maintaining."If done without sleep/msleep, the buttons are not painted over. Why?" - @SGaist already explained why. closeValve() and openValve() need long to do their work as you said. While they are busy the Qt event loop is blocked and the UI cannot be updated. If you put thos sleep calls then there is enough time for closeValve() and openValve() to finish and the event loop can then update the UI before closeValve() and openValve() are called again.
Qt is an event driven framework as most other GUI related frameworks. You should adapt to event driven programming. One of the most important rules: do not block the event loop. -
@jsulm What is the way out of this situation? Create signals and slots?
-
@maratk1n What I don't understand is: what's the point to call openValveSignal(i) 7 times in a row and in each call update the UI? Look: you call openValveSignal(i) for the first time, it updates the UI, then the second call arrives and updates the UI - who will notice the first UI update if it is IMMEDIATELY overwritten? And so forth... Same for closeValveSignal(i).
-
@jsulm These are seven different buttons for seven valves. I want to quickly open all 7 valves and, correspondingly, paint all 7 buttons.
-
@maratk1n Then you should not block the event loop.
As a work around (not really a good solution) you can call http://doc.qt.io/qt-5/qcoreapplication.html#processEvents instead of msleep. -
@maratk1n said in GUI does not have time to update?:
So... How can I update the appearance of the buttons if I want to switch the valves as quickly as possible?
Maybe you can give setPalette a try first?If this do not work, let us find next solution.
@maratk1n said in GUI does not have time to update?:
ui->mainLabel->setText(str + " opened! :)"); also does not work.
This is weird, maybe your codes have some bugs(like I say, please study a great c++ book, this could save you a lot of headaches, education in university is far from enough), could you reproduce the issues with minimum codes and upload the whole project to somewhere(mega, dropbox, etc)?
-
@tham said in GUI does not have time to update?:
education in university is far from enough
I did not have any programming at the university (now I'm studying in the magistracy for robotics)...
@tham said in GUI does not have time to update?:
could you reproduce the issues with minimum codes and upload the whole project to somewhere(mega, dropbox, etc)?
I can upload anywhere, but this will not work, because communication with the board occurs
-
@maratk1n said in GUI does not have time to update?:
I can upload anywhere, but this will not work, because communication with the board occurs
What do you mean "communication with the board occurs"? Do you program depend on some specific hardware?
"reproduce the issues with minimum codes" == Do not send us your whole project, create a new project, with minimum lines of codes which could reproduce your issues.
If your issues are hardware/os specific, please write down the hardware, os, compiler and Qt version you are using.
@maratk1n said in GUI does not have time to update?:
I did not have any programming at the university (now I'm studying in the magistracy for robotics)...
Then I think study a great book of c++ could help you even more, Programming -- Principles and Practice Using C++ (Second Edition). This book is design for beginners of programming and c++
-
@maratk1n Hi, to simply fix your problem, without going deeper into the issue, I believe this can be solved in a few easy steps.
First you need a new
SIGNAL
signals: void valveIsOpen(int id);
That is emited when your open function is finished. Than you need a slot to update your buttons:
void updateValveButtons(int id){ QString str = "Valve №" + QString::number(id+1); valveButton[id]->setEnabled(true); QString style = QString(DEFAULT_STYLE_BUTTON) + QString(DEFAULT_BACKGROUND_BUTTON); valveButton[id]->setStyleSheet(style); ui->mainLabel->setText(str+ " opened! :)"); }
than connect the SIGNAL/SLOT :
connect(valve, SIGNAL(valveIsOpen(int), this, SLOT(updateValveButtons(int),Qt::QueuedConnection);