QWidget update events but no visual update - c++

Using Qt4.8 on a Mint Linux 12, I implemented a simple window containing a QTableView to show contents of a model. The model data is continually updated (log messages) and the dataChanged() signal is emitted on a regular basis (i.e. every 100ms).
The problem I see is stuttering visual updates on the table.
I installed an event filter on the window that counts updateRequest-type events, which should trigger a widget repaint (also on child widgets, i.e. the tableView). These come in with an average time of ~170ms between them and a standard deviation of ~90ms (which is rather large, I guess). However, the perceived visual update rate is only two or three times a second and I wonder why. It seems that not all updateRequest events trigger a widget repaint or that the window system swallows visual updates.
As a second test, I forced the window to update itself by calling repaint or update every 100ms. Using repaint, I saw a corresponding increase in updateRequest-type events and a decrease of the standard deviation of the gaps; with update, the number did not increase. However, there was only a moderate increase of perceived update rate in both cases.
Also: Is there a good method to measure how often a widget is actually really repainted without having to overload its paintEvent handler? Maybe something from QTest?
Update: I extended my event filter to also catch paintEvent-type events. There are only a one-digit number of those versus > 1000 updateRequest-type events.

You should instrument the event dispatcher's aboutToBlock() and awake() signals, and measure time between them using a QElapsedTimer. The instance of the event dispatcher for the current thread is returned by the static QAbstractEventDispatcher::instance().
If the event loop sleeps for a very small fraction of your time measurement window, it means there's too much stuff going on in the GUI thread. You can keep a count of how long the event loop slept, say, during the last second. If it's below 10%, you can expect slow updates and whatnot. Remember that update events are queued with Qt::LowEventPriority. They will be preempted by standard queued signals and almost all other events.

QApplication::compressEvent discards QEvent::UpdateRequest, if there is already one unprocessed. Thus even repaint(s) can return immediately without painting, if the event is discarded. You can check, if your updateRequest events are discarded by overwriting compressEvent.

Related

How can i slow down QSpinBox scrolls while holding Up/Down (Keyboard)

The scenario is the following:
When my active Widget is a QSpinBox, I can change the value by clicking or holding a click on an arrow of the box or by pressing or holding Page Up/Page Down/ ▲ / ▼ .
The problem is, that i have some hardware communications on valueChanged() which needs some milliseconds.
While i permascroll (mouse) or hold the click on a boxes arrow, this isn't a problem, because the scroll seems to be slower here (acceleration off), but when i use my keyboard (acceleration also off), the scrollspeed is much faster which causes the timing problem. The application slows down, then freezes for some seconds until the event queue is finished.
I need to allow using the keyboard input (including holding the keyboard key), so I'd like to know if there is a way to slow down key repeat rate of arrow/page up/down.
Actually I'm triggering a 200 msec oneshot timer on value changed, which passes the spinbox value on timeout. The timer will only be triggered if it's not running. That means when i change the value it will always have a 200 msec delay and the update frequency can only be 5 updates/sec or slower. It actually works, but I'd really like to improve this by reducing the key repeat rate somehow.
Ok no I see problem. Here problem is keyboard repaying character on button hold.
To overcome this without direct interaction with keyboard, I would try use event filter, observe key press events and reject some of them if then are arriving to fast.
Your device communication subsystem has two states: busy and available. When it's busy, you should schedule an update of a particular variable in your target, but don't execute it just yet. When the previous communications are done, and the subsystem is available, it should pick up any outstanding changes and propagate them.

How to monitor QT signals?

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.

MFC application freezing while updating CListCtrl

I have a CListCtrl in my MFC application. The list needs to be updated when I get some notification from the server. Updating list works quite good when there are less notification as operations on the list are less. But in case of heavy load, list control and in turn the application gets freeze.
I am aware of updating UI items in the separate thread in case of bulk updates, but in this case I have the notifications that can come in any order and in any volume, I need to handle in such way that my main thread is not getting blocked.
If anyone faced the issue before please suggest the approach for this case.
You could put all the updates into a queue. Then do a limited number of updates from the queue to the control in the OnIdle function. OnIdle is called when your GUI message queue is empty. It could do up to, say, 20 updates and then return. The main thread would than process any GUI input and when finished with that it would call OnIdle again. In this way you delay and spread out the updates while keeping the GUI alive.
I had a similar situation and resolved it using a Timer. Only when the Timer ticked the ListCtrl could got updated.
Side note: You should do
SetRedraw(FALSE);
before a bulk update
and
SetRedraw(TRUE);
after.
You should not have the control drawing itself at a one-by-one item level, when doing a bulk operation.
Use Thread.I had the same problem and I solved it by just having the loop of adding elements into the clistctrl in thread function. That is,is the POSTMESSAGE() function in the thread should be called as much time as we want to add elements .
MFC Application getting stuck when adding list control elements
Also refer the above link to get some idea

Qt 4.8 - Showing “loading” animation while updating the QGraphicsScene

I’m using Qt 4.8.
I have a big QGraphicsScene to update (it takes 3 secs to append the new QGraphicsObjects).
I would like to show the user that the update is in progress.
In particular I thought about showing a loading wheel on screen and than remove it when the update ends.
The problem here is that I should make the wheel visible and then not visible in the
same thread of the scene update. This because:
It is not allowed to edit graphic properties outside the gui thread.
I cannot move the computation in a “worker thread” since it involves graphics.
This results in the wheel not showing at all, since when the view is updated the wheel
has been already set visible and then not visible again:
showWheel();
/*... big computation involving graphics ...*/
hideWheel();
/*... here GUI is updated, thus the wheel doesn't show up...*/
Is there anything I can do?
Thanks
Presumably you have some event triggering the computation. Instead of using it to trigger the computation, use it to trigger a scheduleComputation()slot. The scheduleComputation slot can call showWheel() and then schedule the doComputation() slot for the end of the next event queue, after which it will return. This will allow the event loop to run and show your wheel, then perform computation. When computation is over, you can call hideWheel() and return to the event loop.
Something like this:
void scheduleComputation()
{
computeScheduler = new QTimer(this);
computeScheduler->setInterval(0);
connect(computeScheduler,SIGNAL(timeout()),this,SLOT(doComputation()));
showWheel();
}
void doComputation()
{
//...Computation Here...
hideWheel();
}
It is also a good idea to keep from blocking the UI thread for long periods of time. This can be done by splitting your long running code into smaller pieces that can be triggered by a timer.
At regular intervals in the "big computation" you can let the event handler run for a little while.

QT Event Problem

I am writing a qt program and have the following requirement.
When 30 sec passed without any click, lock the screen. If someone clicks again after these 30 secs, redirect him to a login screen.
I have read the qt doc about event and I believe that I need either method 1 or 2 to process mouse event.
1.Installing an event filter on qApp
An event filter on qApp monitors all events sent to all objects in the application.
2.Reimplementing QApplication::notify().
Qt's event loop and sendEvent() call this function to dispatch events. By reimplementing it, you get to see events before anybody else.
They also seems powerful to me, but I don't understand their difference.
Which one suits my requirement? Thank You.
You can basically achieve the same thing with either solution except for the fact that QApplication::notify (or its override) will be called before any event filter that may be on your application.
As the first approach does not require subclassing QApplication, it usually is the preferred one.The only reason to override QApplication::notify in your case would be if you needed to override it due to other reasons anyway, e.g. because you need to do anything related to your own custom events.
But looking at your requirements I would personally go for the following solution:
Install an event filter on qApp
Create a timer with a 30 seconds interval
Connect the timer to the lock screen method
Have your event filter reset the timer every time a mouse press is detected.
Dependent on your application you might also want to look for KeyPress events and maybe MouseMove events as well.