Qt executes an event before another event finishes its execution - c++

I'm working on a project, which is a C++/Qt desktop application. In this application, I've identified a certain problem related to the execution of interface events.
For example, in this application, the mousePressEvent delegates a certain operation to the program, and this operation can be slow sometimes, so if the user presses the mouse button before this operation ends, the program begins to execute another operation before the previous one finishes.
Does anyone ever have this same issue with Qt?
Thank you.

Related

QPushButton - Execute while loop until Pushbutton is not clicked

I have implemented a GUI and my problem is to handle two tasks at the same time. My code should be provide the opportunity to execute the task by clicking on a Pushbutton or by listening to CAN messages with the read function.
I had the idea to read CAN messages with a while loop until the pushbutton is clicked. Is this a good approach?
Your GUI itself should have some sort of main loop that continuously runs waiting for any updates to process. Each iteration of which, it should be reading the CAN messages and if there is a trigger for a specific task, you should have code implemented that handles that. The same thing goes for any of your push buttons. You should not have any logic that stops checking the CAN if a button is pushed, or vice-versa. Instead, you should keep track of specific events being triggered with a boolean and prevent retriggering them until they are complete/resolved.

Qt application interface freeze

I'm experiencing some problems with my embedded application. It is a page that contains a QTimeEdit that counts the time each second, some checkboxes and some QLineEdits that refresh each second.
After some minutes of working, I see a freeze of interface, even if the application is still running. If a try to press buttons or checkboxes an access violation message appears:
Exception 'Access Violation' (14): Thread-Id=05d80002(pth=8af6109c), Proc-Id=04a90002(pprc=91431714) 'nmb3.exe', VM-active=04a90002(pprc=91431714) 'nmb3.exe' PC=407ea307(qtgui4.dll+0x0005a307) RA=40d6c82c(qtgui4.dll+0x005dc82c) SP=01c1b928, BVA=00000004
The exception is related to qtgui4.dll. I checked if a saturation of virtual memory occurs, but this is not the problem that causes the freeze.
The freeze doesn't occur if I avoid to update the QTimeEdit, but I don't understand why.
You should move the timer into the mainwindow class, keeping the sensors handler in the separated thread.
The sensors handler should:
store the data
emit a "data ready" signal to the window
Then the timer in the mainwindow, every second, will:
read the data from the sensors handler
update the GUI
(make sure you are using thread-safe objects or, managing the critical sections)

Making a music player in C++/GTK

I would like to create a music player, but I'm working with robots.
My robot should play a series of action (speech, move, etc) and I need to be able to stop it at anytime (for security).
I'm working with C++ and GTK.
I have a PLAY button linked to the function play_playlist:
void play_playlist ()
{
std::deque<history_record>::iterator it = list_to_play_.begin();
while (!g_stop_ && it != list_to_play_.end())
{
play_action(it); // take time to execute (simulate using sleep 3sec)
it++;
}
}
And a STOP button linked to the function set_stop_to_false:
void set_stop_to_true()
{
g_stop_ = true;
}
When I click PLAY the GUI freezes and I'm not able to click on STOP.
How can I have my playlist running and be able to click on the GUI? (i.e. GUI should be responsive)
My best hope is a thread, but I'm not sure how to use it appropriately.
When I click PLAY the GUI freezes and I'm not able to click on STOP.
You need to build a multi-threaded application. Your interface freezes because your application is busy doing something else, so not only that events raised from GUI are not being processed but they are not even raised.
Your application should start a worker thread that will do its job in the background, the main thread can then communicate with this worker thread for example via shared memory.
Once you enter a callback like play_playlist, the GTK main loop can't process events until you exit that function, which freezes the user interface. As play_action takes seconds to run, you only have 2 choices:
split play_playlist execution in several smaller steps, and use a
state machine to execute each step one after the other using a
callback triggered by g_idle_add. Here's an example of this
technique for lazy loading.
the other solution is to run your blocking play_action in a thread. Give a look at GThread. You start your thread when you press PLAY and stop it when you press STOP. However, you can't manipulate the user interface from a thread, GTK is not thread safe. Every GTK action should be processed from the main thread.

Is CWnd::ScreenToClient safe?

I am currently making a lot of use of code like this in order to determine a control's location within a window's client area:
CRect rect;
GetDlgItem(IDC_CONTROL_ID)->GetWindowRect(&rect);
ScreenToClient(&rect);
All is working fine, but I'm concerned about the safety of this code. Specifically, if the user moves the window in between GetWindowRect and ScreenToClient due to the thread containing the above code being suspended by Windows, will it produce the wrong results? If so, is there a better way of doing this?
The user won't be able to move the window at all while your code inside of a message handler function is executing. So no, this will not be a problem.
The UI is basically temporarily frozen or suspended while your code is running. Technically, this is because Windows is unable to process other messages until you return. The message loop starts running again once you return from your message handler function, thus returning control.
This is, of course, why you shouldn't execute code that takes a long time to run (e.g., complex calculations) inside of your message handlers because the UI will be frozen until it finishes.
Instead, you should spin off a separate thread to run this kind of stuff. Since you're not multi-threading here (and don't need to because this code takes a negligible amount of time to execute), there will be no re-entrancy problems.

QT Repaint/Redraw/Update/Do Something

I'm New to QT. I understand that you can force a display refresh, but I've pulled all my hair out trying to figure out how. Here is what I'm specifically trying to do.
I press a button (onClick signal event), which runs code that changes an image (QLabel) on the display, waits for input, and then proceeds by changing a new image (different QLabel). I've tried everything and the display doesn't refresh until the onclick signal event code is complete. Right now, I'm not waiting for user input, I'm using usleep(~500 ms) for testing purposes.
From what I read, QT is event driven meaning that I'm basically creating a bunch of events, that get put in a que, and executed when the (onClick signal event) returns to the (main loop)/(event handler). I don't want to wait until the function is complete, it's going to make programming extremely painful if I have to accomplish this routine entirely based on events.
How can I force the QLabel pixmap to refresh. I've tried everything. Below is all the code I have tried in my onClick signal event handler. (upButton is the name of the QLabel which is a pixmap)
update();
repaint();
ui->upButton->setUpdatesEnabled(TRUE);
update();
repaint();
QPaintEvent paintevent(ui->upButton->childrenRegion());
QPaintEvent * test = &paintevent;
paintEvent(test);
this->changeEvent(test);
ui->upButton->update();
ui->upButton->repaint();
ui->upButton->repaint(ui->upButton->childrenRegion());
repaint();
QApplication::sendPostedEvents();
this->parentWidget()->update();
usleep(100000);
As you can see, I'm just shooting in the dark at this point. I've tried to look at sample code and do all my homework, but I'm lost. Appreciate any help, advice, and or sample code.
I was using sleep to emulate a brief amount of time the computer was waiting for something to happen.
As I stated in my question, I didn't want to use events because it's a whole lot of unnecessary work to accomplish something extremely simply.
Also, the 'event' that needs to take place for the program to continue, is a USB event. Since I'm using an HID class device, there is no way to set an event to happen without a wait loop. USB HID classes don't permit setting interrupts, the OS claims the device.
I managed to get the above to work. I walked through the debugger and noticed the display would refresh before the sleep function. Running the program independently, I got random results with the display refreshing 1% of the time. I got rid of the sleep function, and added some other code in it's place to emulate a delay, and it was fine.
Just for everyone's knowledge, this is possible, it's not forbidden, and it's easy to do with the following:
qApp->processEvents();
qApp is a global external variable in the QApplication header.
Because this USB event is making my flow tricky, I stumbled upon the QWaitCondition Class. I was going to start a process waiting for the USB event. I would wait until the process releases the wait condition for my routine to continue.
But if anyone thinks this is a bad idea, please, speak out. I really do appreciate your feedback PiedPiper and Hostile Fork.
Thank you.
I noticed sometimes when you have multiple layered widgets, or widgets inside of widgets it helps to call their repaint() events.
For example
this->repaint();
this->parentWidget()->repaint();
this->parentWidget()->parentWidget()->repaint();
This is far easier then pushing out any processing to another Thread, or creating additional event handlers.
You shouldn't be waiting for input in your event handler. You need to rethink the logic of your program to use events the way they were intended. All the update() and repaint() calls in your code are unnecessary if you return to the event loop.
If i understood correctly, you have a slot and in this slot, you update the image shown in a QLabel. But you want this change to be displayed before the slot finishes.
If that is the case, issue an update() event, and call qApp->processEvents(). This method processes events that are waiting in the event queue and then returns, therefore this may be what you are after.
PS: an update() may not be necessary at all, i am not sure.