We have a significantly multi-threaded embedded Qt application. However the bulk of it's processing is done in the main thread (i.e.: first started), which obviously also handles the screen painting. For inter-thread communication, a truckload of signal/slot calls are used.
Everything works fine, until the CPU-load hits a certain point, and then the screen stops updating. It doesn't matter what happens to cause the load - more data arriving, more detailed record-processing, extra logging, etc.
From the logs, I can see the main program loop executing many times a second, and while the CPU load is low - I also see the log from one of the widget paint() functions - every iteration. When the load gets too high, I still see the main loop executing, but the widget paint() functions are not called (and the screen is not updating).
Is this a known bug?
Is there some way to debug this further?
Is there a way to absolutely force a screen refresh?
I suspect that possibly some kind of signal/slot handling is starving the paint of CPU time. I imagine the signal interrupting the paint somehow, but before the handling is done, another signal arrives. Do signals/slots work like this?
EDIT: Based on #Jeremy Friesner's comments below, so far I've tried:
// KLUDGE: TRY TO FORCE A REPAINT
// QCoreApplication::postEvent( this, new QEvent(QEvent::UpdateRequest), Qt::HighEventPriority );
QCoreApplication::sendEvent( this, new QEvent(QEvent::UpdateRequest) );
qApp->processEvents();
To no avail.
EDIT2:
Also tried:
//QCoreApplication::postEvent( this, new QEvent(QEvent::Paint), Qt::HighEventPriority );
QCoreApplication::sendEvent( this, new QEvent(QEvent::Paint) );
qApp->processEvents();
Related
For test purposes I'd like to create and display a widget. For now I only need the widget to render correctly but in the future I may want to extend this so I simulate various events to see how the widget behaves.
From various sources it would appear that the following should work:
QApplication app;
QPushButton button("Hello");
button.show();
// Might also be necessary:
QApplication::processEvents();
But for me the widget does not render correctly. A window is created to display the widget, however it is entirely black.
I can get the widget to render correctly by adding the following lines:
std::this_thread::sleep_for(std::chrono::milliseconds(10));
QApplication::processEvents();
With 10 milliseconds being about the smallest time necessary to get the widget to render correctly.
Does anyone know how to get this to work without the time delay, or know why the delay is necessary?
To test Qt GUI application you need at least QApplication instance and event loop being processed. The fastest way is just use QTEST_MAIN macro, this answer explains in a nice way what it does exactly. However, to have more flexibility (e.g. to use GTest, GMock) you can also simply create QAplication instance in your tests main (no need to call exec).
Then, to have the events processed, you should invoke QTest::qWait. This will process your events for the specified amount of time. It is a good practice to use qWaitFor which accepts a predicate - this way you avoid race conditions in your tests.
In the particular scenario, when you expect some signal to be emitted, you can also use similar functionality of QSignalSpy::wait.
Small example when we want to wait until some parameters are passed from one item to another:
QSignalSpy spy(&widget1, &Widget1::settingsChanged);
widget2->applySettings();
ASSERT_TRUE(spy.wait(5000));
// do some further tests based on the content of passed settings
Why don't you want to have the application run exec ? The process of displaying a widget is not "static". You don't "draw" the widget on the screen, but rather you have an application that listen for various events and receives draw events from the windowing manager. The application can only draw the widget when the windowing manager asks it to.
The reason your second code works is that you wait sufficiently long for the windowing manager to have sent the "draw" request in your conditions. This does not guarantee it will always work.
If you want to guarantee the display of the widget, you need to start a loop and wait until you have received at least one draw event, but even that isn't foolproof.
As expertly described by Vincent Fourmond, widgets are not a one-off deal. The GUI is non-blocking and for this, it needs to run in an event loop.
The exec() method starts this event loop which you mimicked by polling.
While it is possible to combine Qt's event loop with other event loops, I would recommend you a simpler solution:
Proceed your program within the event loop by calling a method when it starts. Find an excellent answer here on how to do this: https://stackoverflow.com/a/8877968/21974
As you mentioned unit testing, there is also a signal you can use for doing checks at the end of the lifecycle (before widgets are destroyed): QApplication::aboutToQuit. This will happen when the last window is closed (programmatically or by the user).
I implemented a widget/dialog, which is just a gif animation inside (CircularProgressDlg). Our application consists of Login dialog part and MainWindow part. Between login is accepted and MainWindow is fully loaded there are 5 to 10 seconds of huge init() function.
What I need is to launch my CircularProgressDlg when login is accepted, and I need it to animate it's gif non-blocking. I can't use "update" or "processEvents" inside this huge "init" function, cause it is very complex inside and it won't be smooth enough.
It looks very needful that this type of dialogs, detached from main event loop, exist! So how to achieve that?
I understand that I can create a detached Process with this CircularProgressDlg, but let's leave this way to the end.
What are other ways?
We use QtWidgets, but maybe I can implement small QML dialog for such cases if, of course, QML will solve my problem. Will it?
Which options do I have?
Use the Qt Concurrent library, specifically its QConcurrent::run method to spawn a thread for your expensive task. You get back a QFuture that you can watch with QFutureWatcher.
The QT documentation has an asynchronous image scaling example.
I'm adding selected parts below.
Creating a QFutureWatcher to be signaled when a future is done:
imageScaling = new QFutureWatcher<QImage>(this);
connect(imageScaling, &QFutureWatcher<QImage>::resultReadyAt, this, &Images::showImage);
connect(imageScaling, &QFutureWatcher<QImage>::finished, this, &Images::finished);
Constructing the future:
std::function<QImage(const QString&)> scale = [imageSize](const QString &imageFileName) {
QImage image(imageFileName);
return image.scaled(QSize(imageSize, imageSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
};
QFuture<QImage> fut = QConcurrent::run(scale, "test.png");
Attaching the future to the futurewatcher:
imageScaling->setFuture(fut);
Thanks to everyone. We decided to make things right and refactor loading and updating our widgets in a non-blocking way. With moving all possible logic in separate processes.
I currently have a C++ class inheriting from QQuickPaintedItem. I use it to paint layouted, paginated richtext from a QTextDocument via QTextDocument::drawContents (or by directly calling its QTextDocumenLayout's draw method).
However, as stated in QQuickPaintedItems documentation, there are threading issues to be aware of:
Warning: Extreme caution must be used when creating QObjects, emitting signals, starting timers and similar inside this function as these will have affinity to the rendering thread.
Specifically, in this case, QTextDocumentLayoutPrivate has timers which get started/stopped when QTextDocumenLayout::draw is called. Unfortunately, the QTextDocument and thus the timers lives in the qml main thread, while paint is called in the render thread, leading to messages like
QBasicTimer::start: Timers cannot be started from another thread
While this doesn't affect the functionality of my application (so far), this is probably not a good thing™.
Therefore, my question is whether there is a better way to show the paginated text in QML (not necessarily involving QQuickPaintedItem).
For now I'm still using the QQuickPaintedItem and when paint is called I do the following:
First check whether the QTextDocument has its affinity set to its current thread. If yes, I'll proceed as normal.
Otherwise QMetaObject::invokeMethod is used to call a method which moves the document to the rendering thread, and calls update to trigger a repaint, which now works as the thread affinity is correct. At the end of paint, the QTextDocument's thread affinity is set back to the original thread.
This works as far as I can tell (as in, no more warnings), but feels conceptually rather wrong.
My program takes a few seconds to start up. I am using clutter for the GUI, and I decided to try and make something pop up to indicate that the program is starting up. I wanted to just have a logo pop up and rotate, then disappear when the program starts.
So in clutter, I figured I could just make a new stage (window) add an actor to it, make the and actor spin, in the first section of the main function. The window will pop up right away, but with no content, but the content wont show until you launch the clutter main loop.
So I was just wondering how I might be able to achieve this using clutter or GTK+.
If you are familar with reaper 4, the audio recording program, this program does something similar to what I want to mine to do.
What you want is called a splash screen. I'm unfamiliar with clutter, but I found this GTK splash screen example.
However, I think you're taking the problem the wrong way. Splash screens are a bad idea because you just add overhead. What you need is improving your startup performance, by doing some CPU and/or IO profiling. Loading stuff on-demand, and not all at once will help.
Unfortunately I'm unfamiliar with Clutter. But I'm pretty sure it will be difficult to render an animation without a main loop running in any high level library.
I'd try to put the code that causes the delay into a separate thread and inform the main loop when the startup is done.
Something like this is what i use:
string splashfile = path_templ + "/splashimg.png";
GtkWidget *image=gtk_image_new_from_file(splashfile.c_str());
gtk_container_add(GTK_CONTAINER(SplashWindow), image);
gtk_widget_show_all(SplashWindow);
//Cycle through all iterations (refresh everything in the GUI)
while (gtk_events_pending()){
gtk_main_iteration();
}
sleep(1);
(... rest of code ...)
gtk_main ();
gdk_threads_leave ();
Especially that last part of while events pending is the key
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.