Smooth Out wxScrolled<wxPanel> Scrolling Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Tapsa
Earned some good credits
Earned some good credits
Posts: 144
Joined: Tue Dec 06, 2011 5:52 pm
Location: Helsinki

Smooth Out wxScrolled<wxPanel> Scrolling

Post by Tapsa » Thu Mar 02, 2017 1:37 pm

I am trying to implement smooth scrolling function for wxScrolled<wxPanel> object.

Code: Select all

if ( Still painting? )
{
    Add one (not more) pending scrolling event.
}
else
{
    Scroll immediately, causing repaint.
}
Default behavior, that I need this against for, is to queue up scrolling events even if the drawing code cannot cope with them fast enough.

I'm getting segmentation fault from this code of mine:

Code: Select all

    Units_Scroller = new wxScrolled<wxPanel>(...);
    Units_ScrollSpace = new wxBoxSizer(wxVERTICAL);

    Units_Scroller->SetSizer(Units_ScrollSpace);
    Units_Scroller->SetScrollRate(0, 20);
    Units_Scroller->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent &event)
    {
        Units_Scroller->GetEventHandler()->ProcessEvent(event);
    });
Anyway, what would be good method of achieving this?

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4176
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by ONEEYEMAN » Thu Mar 02, 2017 3:43 pm

Hi,
It would be nice to have a backtrace at the time of crash.
Also, what platform you are working under? What toolkit? What wx version?

Thank you.

Tapsa
Earned some good credits
Earned some good credits
Posts: 144
Joined: Tue Dec 06, 2011 5:52 pm
Location: Helsinki

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by Tapsa » Thu Mar 02, 2017 6:47 pm

It crashes as soon as WasProcessed is called in wxEvtHandler::ProcessEvent, because the event object is destroyed?
Windows 10 64-bit, MinGW-w64 6.2.0, wx 3.1.0.

I came here in case someone had better idea altogether how to do this.
To check if window is being painted I thought to look at the scroll bar location, has it changed enough.

My theory is that if window painting code is done 100 % from start to finish, then during that time no mouse scrolling events should register, but they seem to register so I am assuming that the window painting code is done in pieces and in the middle of it mouse status is questioned. Correct me if I am wrong. How else could the scrolling events pile up and keep firing for seconds after I have stopped the mouse wheel (my wheel works, can confirm in Firefox etc any good app).

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4176
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by ONEEYEMAN » Thu Mar 02, 2017 7:23 pm

Hi,
So what is the backtrace at the time of crash?

Thank you.

Tapsa
Earned some good credits
Earned some good credits
Posts: 144
Joined: Tue Dec 06, 2011 5:52 pm
Location: Helsinki

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by Tapsa » Thu Mar 02, 2017 7:42 pm

It continues at least 20000 lines backwards (I can hold enter down and there are forever more lines to show), but here is the most recent calls:
Program received signal SIGSEGV, Segmentation fault.
0x039092db in wxEvtHandler::ProcessEvent (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1460
1460 if ( !event.WasProcessed() )
(gdb) bt
#0 0x039092db in wxEvtHandler::ProcessEvent (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1460
#1 0x658f8658 in wxScrollHelperEvtHandler::ProcessEvent (this=0x77d7528, event=...)
at ../../src/generic/scrlwing.cpp:200
#2 0x0050efc0 in AGE_Frame::<lambda(wxMouseEvent&)>::operator()(wxMouseEvent &) const (__closure=0x953ef5c,
event=...) at C:\Users\Tapsa\Documents\GitHub\Priva\AGE\AGE_Frame\Units.cpp:5258
#3 0x0055fd70 in wxEventFunctorFunctor<wxEventTypeTag<wxMouseEvent>, AGE_Frame::CreateUnitControls()::<lambda(wxMouseEvent&)> >::operator()(wxEvtHandler *, wxEvent &) (this=0x953ef58, event=...)
at C:/Cpp/wxWidgets/include/wx/event.h:484
#4 0x03843817 in wxAppConsoleBase::CallEventHandler (this=0x7768d60, handler=0x77d70f8, functor=warning: RTTI symbol not found for class 'wxEventFunctorFunctor<wxEventTypeTag<wxMouseEvent>, AGE_Frame::CreateUnitControls()::{lambda(wxMouseEvent&)#1}>'
..., event=...)
at ../../src/common/appbase.cpp:671
#5 0x0390917b in wxEvtHandler::ProcessEventIfMatchesId (entry=..., handler=0x77d70f8, event=...)
at ../../src/common/event.cpp:1381
#6 0x03909d2b in wxEvtHandler::SearchDynamicEventTable (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1831
#7 0x039095a3 in wxEvtHandler::TryHereOnly (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1574
#8 0x03942ea0 in wxEvtHandler::TryBeforeAndHere (this=0x77d70f8, event=...) at ../../include/wx/event.h:3656
#9 0x03909437 in wxEvtHandler::ProcessEventLocally (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1511
#10 0x039093d8 in wxEvtHandler::ProcessEvent (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1484
#11 0x658f8658 in wxScrollHelperEvtHandler::ProcessEvent (this=0x77d7528, event=...)
at ../../src/generic/scrlwing.cpp:200
#12 0x0050efc0 in AGE_Frame::<lambda(wxMouseEvent&)>::operator()(wxMouseEvent &) const (__closure=0x953ef5c,
event=...) at C:\Users\Tapsa\Documents\GitHub\Priva\AGE\AGE_Frame\Units.cpp:5258
#13 0x0055fd70 in wxEventFunctorFunctor<wxEventTypeTag<wxMouseEvent>, AGE_Frame::CreateUnitControls()::<lambda(wxMouseEvent&)> >::operator()(wxEvtHandler *, wxEvent &) (this=0x953ef58, event=...)
at C:/Cpp/wxWidgets/include/wx/event.h:484
#14 0x03843817 in wxAppConsoleBase::CallEventHandler (this=0x7768d60, handler=0x77d70f8, functor=warning: RTTI symbol not found for class 'wxEventFunctorFunctor<wxEventTypeTag<wxMouseEvent>, AGE_Frame::CreateUnitControls()::{lambda(wxMouseEvent&)#1}>'
..., event=...)
at ../../src/common/appbase.cpp:671
#15 0x0390917b in wxEvtHandler::ProcessEventIfMatchesId (entry=..., handler=0x77d70f8, event=...)
at ../../src/common/event.cpp:1381
#16 0x03909d2b in wxEvtHandler::SearchDynamicEventTable (this=0x77d70f8, event=...) at ../../src/common/event.cpp:1831
---Type <return> to continue, or q <return> to quit---

User avatar
doublemax
Moderator
Moderator
Posts: 14898
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by doublemax » Thu Mar 02, 2017 7:57 pm

If i had to guess, i'd say the event handler gets called recursively and you get a stack overflow.

Code: Select all

    Units_Scroller->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent &event)
    {
        Units_Scroller->GetEventHandler()->ProcessEvent(event);
    });
What's this supposed to do anyway? Shouldn't there be the code from above or something similar?

BTW: I'm not sure how your idea is supposed to work anyway. Unless you're using a secondary thread, your drawing code can never be interrupted by another scroll event.
Use the source, Luke!

Tapsa
Earned some good credits
Earned some good credits
Posts: 144
Joined: Tue Dec 06, 2011 5:52 pm
Location: Helsinki

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by Tapsa » Thu Mar 02, 2017 8:09 pm

That is skeleton code where I planned to add more things.
I have no drawing code for this part, but is the wx code interrupted for scroll events?
Maybe even Windows itself stacks the scroll calls before handing them over to my application?

User avatar
doublemax
Moderator
Moderator
Posts: 14898
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by doublemax » Thu Mar 02, 2017 8:15 pm

Code: Select all

Units_Scroller->GetEventHandler()->ProcessEvent(event);
That line is a little suspicious. Try just calling event.Skip() which should do the same.

Personally i'd first try to speed up the redraw so that all of this isn't necessary. If that's impossible, i'd try to use a timer to achieve a delayed redraw.
Use the source, Luke!

Tapsa
Earned some good credits
Earned some good credits
Posts: 144
Joined: Tue Dec 06, 2011 5:52 pm
Location: Helsinki

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by Tapsa » Fri Mar 03, 2017 9:24 am

You are the man, doublemax!
I added a timer to detect how much is scrolled after last mouse wheel event is processed, and it varies.
Instead of skipping the event I will call Scroll directly to prevent too much scrolling.
You are indeed correct that during drawing there is no other code executed, so my 200 ms timer can sometimes fire after seconds, when scrolling drawing is done. I wouldn't actually be surprised if the drawing lag causes the wheel event to think that I want to scroll faster.

Is there a way to know how much is set as scroll speed in Windows mouse settings?
With this code my scrolling became butter smooth.

Code: Select all

    Units_Scroller->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent &event)
    {
        Units_Scroller->GetViewStart(&unit_pos, &unit_pos);
        Units_Scroller->Scroll(0, event.GetWheelRotation() < 0 ? unit_pos + 3 : unit_pos - 3);
    });

User avatar
doublemax
Moderator
Moderator
Posts: 14898
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Smooth Out wxScrolled<wxPanel> Scrolling

Post by doublemax » Fri Mar 03, 2017 5:17 pm

My idea on how to use a timer was different, but good that you got it solved ;)
Is there a way to know how much is set as scroll speed in Windows mouse settings?
Not that i know of.

If it were somwhere, it would probably be in wxSystemSettings.
http://docs.wxwidgets.org/trunk/classwx ... tings.html
Use the source, Luke!

Post Reply