I have two functions: myCode1() and myCode2(). I have very little control over what is in myCode1() (will be implemented by other party), it can be almost anything, within some sane limits, of course. I need to call first myCode1() and only after it is "finished" I need to call myCode2(), which implementation I have in full control. By "finished" I mean when all synchronous code is done and event loop is done processing all events which were created as the result of myCode1().
My first try was trivial:
myCode1();
myCode2();
But there is a trouble that when myCode1() opens dialog with its own event loop (QDialog::exec()), then myCode2() is called only after the dialog is closed, which is not what I need. I need to call myCode2() after the dialog gets open and is waiting for users interaction.
So my second try:
QTimer::singleShot(0, []{ myCode2(); });
myCode1();
This is slightly better because it schedules myCode2() to be processed by event loop after myCode1() does its synchronous work, i.e. after the potential dialog with blocking event loop gets opened.
But there is yet another problem. myCode1() can create lots of posted events in event queue and I need them to be processed before actually before calling myCode2(). But with the way show above, these events are queued after scheduled myCode2().
So what I would actually need is to schedule myCode2 after ALL events are done including posted events, i.e. when the event loop is empty. And it should work also in the presence of blocking dialogs etc.
I also tried QCoreApplication::processEvents() but these events can post more events and enqueue them at the end of the queue... Moreover QCodeApplication::hasPendingEvents() is marked as deprecated so it cannot help to check whether event queue is empty. Otherwise my implementation would look like this:
void myCode2()
{
while (QCoreApplication::hasPendingEvents())
{
QCoreApplication::sendPostedEvents();
QCoreApplication::processEvents();
}
doMyCode2(); // this would do the actual code
}
And I would schedule it with the QTimer as above. But as I wrote, hasPendingEvents() is deprecated... so I am in bad luck.
Any ideas how to achieve what I need to achieve? I hope there is some simple solution which I just overlooked.
PS: To clarify the purpose - myCode2() should inform about the state of the application. And I need to inform about "final" or "stable" state. Which means that if there are yet more events to be processed, the state is not finished nor stable. Therefore I need to process all events first, including events which were created by previous events.
Related
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.
I'm beginner learning Qt, and trying to understand a Qt provided example for download operation. In downloadmanager.cpp, a member function is the following:
void DownloadManager::append(const QUrl &url)
{
if (downloadQueue.isEmpty())
QTimer::singleShot(0, this, SLOT(startNextDownload()));
downloadQueue.enqueue(url);
++totalCount;
}
I'm confused to why, if downloadQueue is empty, it will need to activate the startNextDownload() before adding the url. (note that: startNextDownload() ends the program if the downloadQueue is empty)
I'm unsure why: QTimer::signleShot(x, y, z) has been used at all. As I understand it to be, a timer that activates the slot with delay of 0 millisecond.
I could not figure out from looking at Qt Assistant whether singleShot is a one time setup for repeated activation to the slot at given millisecond interval or whether it is one time
Clarification:
I'm a beginner and in examples like:
statement1;
statement2;
I'm used to seeing statement1 running and finishing before moving on to working on statement2. But trying to learn Qt and reading the given example, I see the SLOT(startNextDownload()) being activated after downloadQueue.enqueue(url); has taken place. I am trying to understand why does this work.
This queues a callback in the message queue.
The timer immediately elapses, and a message is posted to the message queue. When the process reaches the main loop for the next time, the startNextDownload() function is called. By this time, the URL is in the queue.
The startNextDownload() function is called from the dispatch context, where it is safe to change window contents. This way, the DownloadManager class can be used from a multithreaded application, where the thread starting the download might be running concurrently with the handler for a Paint event. By invoking it from the same thread that would handle Paint events you can be sure that no such event is being processed, and you can update widgets safely.
If a widget needs to be repainted afterwards, it then asks to be repainted, and the OS will send a Paint event if the widget is currently visible.
Answer to current question title
Every call to QTimer::singleShot(...) is executed on the event loop of the thread where it is invoked **. If invoked from the main thread, it'll be the event loop started with app.exec().
According to the Qt-Network-Manager-Example, this function is called after the network-manager is filled with the URL's so the single-shot will be processed after the queue has been completely filled. Poorly the qt documentation isn't that clear about this topic yet, so for more information about event processing etc please look here.
Answer for old question title
Before I start, the timer is for having the download in an extra thread. So the GUI keeps responsive.
The complete downloadNext() method is recursive. It will be only called once and called till the queue is empty.
See this:
void DownloadManager::append(const QStringList &urlList)
{
foreach (QString url, urlList)
append(QUrl::fromEncoded(url.toLocal8Bit())); //Call for only one URL
...
}
void DownloadManager::append(const QUrl &url)
{
if (downloadQueue.isEmpty())
//I'm only called if the queue is empty! And I will be called after the next line. Not instantly!
QTimer::singleShot(0, this, SLOT(startNextDownload()));
downloadQueue.enqueue(url);
++totalCount;
}
After the queue is empty each method returns and at least the message that the download is done will be printed.
So why does this work?
Please see first chapter below.
you can understand things about Class QTimer before you end up with a solution as you desire, please have a look here for your understanding
During debugging, I want to see what's awaits my program's event loop.
It's probably flooded, and I want to see by what signals, without (manually) adding specific log-message to every Q_EMIT.
Possible solutions might be watching some internal-qt-data structure that contains the events-queue (Is there such thing? how?)
Or -
Write a log message for every signal emitted (Is that possible?).
Any other ideas?
(QT 4.8 on Windows, using visual studio 2012)
Signals and events are two things that don't have anything to do with each other.
I want to see what's awaits my program's event loop. It's probably flooded.
First of all, let's get the nomenclature straight:
an event queue is where events are stored until delivery;
an event loop is what drains the event queue and delivers events to QObjects,
an event flood happens when, on average, during the delivery of each event there is more than one event added to the queue.
There are two reasons only why an event queue might get flooded:
It takes too long to process some events (e.g. when your code blocks): the drain rate of the queue is lower than the fill rate due to timing.
You're adding more than one event per each event delivered (on average): the fill rate of the queue is higher than the drain rate due to event multiplication - this is completely unrelated to any timing. An apt name for it would be an event storm.
To detect code the blocks for too long, you can use a tool I wrote for another answer.
To know how many events are waiting for any given thread, use the undocumented qGlobalPostedEventsCount(). You add that to the code of the tool linked-to above.
Not sure if this is sufficient for you but you can try installing event filters in between QObjects that implement eventFilter() like this:
class MyWidget : public QWidget
{
QGraphicsView myView;
MyWidget()
{
myView->installEventFilter(this);
// incoming events to myView are shown on the standard output
}
};
You can get more creative with this reading the docs.
The Qt documentation for Events and Filters states:
It is also possible to filter all events for the entire application, by installing an event filter on the QApplication or QCoreApplication object. Such global event filters are called before the object-specific filters. This is very powerful, but it also slows down event delivery of every single event in the entire application.
Therefore, you can create an event filter on the QApplication or QCoreApplication and monitor all events, checking their type.
Alternatively, QCoreApplication uses the virtual notify function to deliver events to objects. Overriding QCoreApplication would allow you to see both the event and QObject to which the event will initially* be delivered.
*Note that events are propagated to parent objects, if the receiving object ignores the event.
If you choose to use notify, be aware of the future direction for this function:
Future direction: This function will not be called for objects that live outside the main thread in Qt 6. Applications that need that functionality should find other solutions for their event inspection needs in the meantime. The change may be extended to the main thread, causing this function to be deprecated.
I'm attempting to implement a simple, lightweight system for recording Qt GUI events and playing them back from a script. I thought this would be fairly straightforward using the magic of Qt's event system, but I'm running into a problem I don't understand.
Here's quick summary of what I'm doing:
RECORDING:
I use QApplication.instance().eventFilter() to capture all GUI events I'm interested in* and save them to a Python script, in which each step looks something like this:
obj = get_named_object('MainWindow.my_menubar')
recorded_event = QMouseEvent(2, PyQt4.QtCore.QPoint(45, 8), 1, Qt.MouseButtons(0x1), Qt.KeyboardModifiers(0x0))
post_event(obj, recorded_event)
PLAYBACK:
I simply execute the script above, in a worker (non-GUI) thread. (I can't use the GUI thread because I want to keep sending scripted events to the application, even if the 'main' eventloop is blocked while a modal dialog eventloop is running.)
The important stuff happens in my post_event() function, which needs to do two things:
First, call QApplication.postEvent(obj, recorded_event)
Wait for all events to finish processing:**
Post a special event to the same eventloop that obj is running in.
When the special event is handled:
Call QApplication.processEvents()
Set a flag that tells the playback thread it's okay to continue
After the second part is complete, my expectation is that all effects of the first part (the recorded event) have completed, since the special event was queued after the recorded event.
The whole system mostly seems to work just fine for mouse events, key events, etc. But I'm having a problem with QAction handlers when I attempt to playback events for my main QMenuBar.
No matter what I try, it seems that I can't force my playback thread to block for the completion of all QAction.triggered handlers that result from clicking on my QMenu items. As far as I can tell, QApplication.processEvents() is returning before the QAction handler is complete.
Is there something special about QMenu widgets or QAction signals that breaks the normal rules for QApplication.postEvent() and/or QApplication.processEvents()? I need a way to block for the completion of my QMenu's QAction handlers.
[*] Not every event is recorded. I only record spontaneous() events, and I also filter out a few other types (e.g. Paint events and ordinary mouse movements).
[**] This is important because the next event in the script might refer to a widget that was created by the previous event.
I think your problem might best be served by using QFuture and QFutureWatcher (that is, if you're using the QtConcurrent namespace for threads, and not QThreads). Basically, the Qt Event handling system does NOT necessarily handle events in the order they're posted. If you need to block until a certain action is completed, and you're doing that action in a separate thread, you can use the QFuture object returned by QtConcurrent::run() with a QFutureWatcher to block until that particular thread finishes its processing.
Something else to consider is the way you handle events. When you use QApplication.postEvent(), the event you create gets added to the receiver's event queue to be handled later. Behind the scenes, Qt can reorder and compress these events to save processor time. I suspect this is more your problem.
In your function which handles playback, consider using QCoreApplication::processEvents(), which will not return until all events have finished processing. Documentation for QCoreApplication is here.
QMenu widgets and QAction signals are a special case. QMenu has an exec() function, normally used for popups. I suspect (but I don't know for sure) that QMenuBar would use this mechanism when it opens a regular pull-down menu. The docs are not clear about this, but Menus act a lot like dialog boxes in that they block all other user activity - how would Qt do this except by giving menus their own event loop? I can't fill in all the blanks from the information in your post, but I don't see how your playback thread would cope with a new event loop.
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.