Hello everybody,
i want to avoid event queue flooding.
Imagine a timed repaint, that works nicely but sometimes cannot be handled immediately, while e.g. a dialog is opened, windows works on something unknown, a network drive is accessed etc... Then redraws (or other commands) pile up and many problems occur. Is is possible to access the message queue (wxPendingEvents in former times) and check the last issued but not handled - aka 'pending' event? Actually all that has to be avoided is issuing a multitude of consecutive paint events (not two consecutive paint events, this is perfectly fine, this means timed animation without user interaction)
In previous versions 2.8 there was wxPendingEvents, what is the wx 3.0 equivalent?
Best regards
Heiner
Avoid message queue flooding
-
- Experienced Solver
- Posts: 99
- Joined: Sat Oct 26, 2013 11:54 am
Re: Avoid message queue flooding
I don't know any way to access the event queue, but that definitely sounds like a bad idea. You should try to avoid flooding the queue in the first place.
How exactly do you trigger the repaints? Calling Refresh() should just mark the window as 'dirty' and calling it multiple times should not generate additional events.
Another option could be to use a one-shot timer that you only (re-)start at the end of the paint event handler.
How exactly do you trigger the repaints? Calling Refresh() should just mark the window as 'dirty' and calling it multiple times should not generate additional events.
Another option could be to use a one-shot timer that you only (re-)start at the end of the paint event handler.
Use the source, Luke!
-
- Experienced Solver
- Posts: 99
- Joined: Sat Oct 26, 2013 11:54 am
Re: Avoid message queue flooding
Hi doublemax,
thank you for your answer.
Actually i had good results so far with the following approach, please comment if you see problems:
1. override Filterevent, keep deque of two last issued events
2. in actual paint handler, check pending events *and* for successive paint events
It is working fine with stable frame rates and no lags when opening large dialogs, opening network drives etc, also across multiple OS and wx versions. I do not miss any mouse moves or whatever. To my surprise it was sufficient to keep record only for the last two events.
Best regards,
Heiner
thank you for your answer.
True, but only a threaded timer gives me exact jitter-free pulses. I tried a lot other stuff, it was all not reliable for several reasons. Then again inside the timer, it is impossible to check the application state, so i have to fire the pulses there and sort out elsewhere.You should try to avoid flooding the queue in the first place.
Actually i had good results so far with the following approach, please comment if you see problems:
1. override Filterevent, keep deque of two last issued events
Code: Select all
std::deque<bool> queued_events_were_draw_events;
int App::FilterEvent(wxEvent& event)
{
// keep record of events
queued_events_were_draw_events.push_back(event.GetEventType() == wxEVT_UPDATEFRAME);
if (queued_events_were_draw_events.size() > 2)
{
queued_events_were_draw_events.pop_front();
}
// process the events normally by default
return -1;
}
Code: Select all
canvas::paint()
{
if (wxGetApp().Pending() && wxGetApp().updateframes_events_recorded_only())
{
return;
}
//else paint ..
}
Code: Select all
bool App::updateframes_events_recorded_only()
{
return std::all_of(queued_events_were_draw_events.begin(), queued_events_were_draw_events.end(), [](auto e) { return e; });
}
Best regards,
Heiner
Re: Avoid message queue flooding
Looks ok. But wouldn't a single flag have been enough? Just don't send a new event if the last paint event hasn't been handled yet?
Use the source, Luke!
-
- Experienced Solver
- Posts: 99
- Joined: Sat Oct 26, 2013 11:54 am
Re: Avoid message queue flooding
I think about that a lot, but it is a little bit difficult to grasp. All i can do is skip an excessive paint inside the paint handler, based on previous events. But maybe it is a valid paint event, i am about to skip? Maybe it is exactly the event that has this single flag in ::FilterEvent? So i thought, if there are two successive paint events scheduled, i can be sure at least one f them is excessive, so i can skip the one i am inside.But wouldn't a single flag have been enough?
Sorry for my weird explanation, i still have to learn about this event handling.
Re: Avoid message queue flooding
My idea was to have a flag, e.g. "bool redraw_pending".
Default would be false.
Inside the thread, if the flag is false, you set it to true and send to event to trigger a redraw
At the end of the paint event handler, you set it to false
Default would be false.
Inside the thread, if the flag is false, you set it to true and send to event to trigger a redraw
At the end of the paint event handler, you set it to false
Use the source, Luke!
Re: Avoid message queue flooding
I remember that Petzold wrote may years ago that windows combines the pending WM_PAINT for a single window.
As I was not sure, i looked it up and found a post illustrating exactly that : "https://stackoverflow.com/questions/257 ... d-messages" So checking if there is a WM_PAINT on the que to prevent additional ones I would not do. (I possibly I did not understand your question correctly).
Then if you want to make sure that you do not overload your application, consider using on idle.
and
I had a similar problem with updating a list control that needed to process tons of updates, and the above approach worked very well: updates are fast and if things overload, non GUI gets priority.
As I was not sure, i looked it up and found a post illustrating exactly that : "https://stackoverflow.com/questions/257 ... d-messages" So checking if there is a WM_PAINT on the que to prevent additional ones I would not do. (I possibly I did not understand your question correctly).
Then if you want to make sure that you do not overload your application, consider using on idle.
Code: Select all
void WawiLib002Frame::OnEvtIdle(wxIdleEvent& event)
{
UpdateGui(); => Invalidate your parts to be redrawn if something needs to be redrawn
}
Code: Select all
void WawiLib002Frame::OnTimer(wxTimerEvent& e)
{
wxWakeUpIdle();
}
-
- Experienced Solver
- Posts: 99
- Joined: Sat Oct 26, 2013 11:54 am
Re: Avoid message queue flooding
Using OnIdle() itself gave very jittery timing (see my posts in the beginning) but combining the scheduled timer with wxIdleEvent looks good:JOHI wrote:Then if you want to make sure that you do not overload your application, consider using on idle.
- set up a bool 'can_i_draw' flag
- before posting a paint message (from the timer thread) check the flag
- if false, do not send
- if true, send and set the flag to false
- in the OnIdle() handler, set the flag to true, because
OnIdle() gets called when every event has been handled. When this is fulfilled, switch back to timed repainting.wxIdleEvent doc wrote:"This class is used for idle events, which are generated when the system becomes idle."
This. Now i know how.doublemax wrote:You should try to avoid flooding the queue in the first place