Get scrolled position of wx.TextCtrl after mousewheel scrolling ?

Hi all,
I'd like to ask about the standard way to handle the wx.EVT_MOUSEWHEEL
on a TextCtrl widget.
This is a part of the problem described in
http://lists.wxwidgets.org/pipermail/wxpython-users/2009-January/083217.html
It seems, that, the function to determine the scrolled position (using
HitTest) can be called directly for wx.EVT_LEFT_UP and wx.EVT_KEY_UP;
for wx.EVT_SCROLLWIN it must be called via wx.CallAfter(),
but for wx.EVT_MOUSEWHEEL neither of these approaches works well. -
the mouswheel event is probably sent at the beginning of scrolling or
with some lower frequency, hence the reported position values don't
always correspond with the definitive position after the scrolling.

The following way seems to work, but it involves setting a custom
timeout, the position is periodically compared to the previous state
and finally the checking function is called using wx.CallLater (which
actually corrects the delayed results).

The part I am most concerned about, is setting the intervalls, the
needed values probably depend on the hardware parameters and while it
seems to work on computers I tested, I'm not sure, how tu make it work
generaly.

I'd be very interested in ways, how to achieve this in a better or
more general way.
(now using win XP, Python 2.54, wxPython 2.8.9.1, but the solution
should work cross platform).
Is the Timer the right thing to use here?

thanks in advance,
   Vlasta

···

###########################

#! Python
# -*- coding: utf-8 -*-

import wx

class TextFrame(wx.Frame):
    def __init__(self, parent, id=-1, *args, **kwargs):
        wx.Frame.__init__(self, parent, id, *args, **kwargs)
        self.txtField = wx.TextCtrl(self, -1, style = wx.TE_MULTILINE

wx.TE_RICH2)

        self.txtField.SetValue("\n".join((str(x).zfill(9) for x in
range(0,1001))))
        self.szrTxt = wx.BoxSizer(wx.HORIZONTAL)
        self.szrTxt.Add(self.txtField, 1, wx.EXPAND)
        self.SetSizer(self.szrTxt)
        self.txtField.Bind(wx.EVT_MOUSEWHEEL, self.on_mousewheel)

    def on_mousewheel(self, evt):
        evt.Skip()
        self.handle_mousewheel(evt, self.show_pos_txt)

    def handle_mousewheel(self, evt, function_to_call):
        """
        Should ensure, that the bound function is also called after
the scrolling was done.
        """
        evt.Skip()
        self.saved_position = None
        self.timer = None
        self.rate = 100 # <-- finetune??
        self.function_to_call = function_to_call
        self.scrolling_widget = evt.GetEventObject()
        self.start_scroll_check()

    def show_pos_txt(self, evt=None):
        self.SetTitle("mousewheel - scrolling position - " +
str(self.scrolling_widget.HitTest((5, 5))))

    def scroll_pos_check(self, widget, evt=None):
        if self.saved_position == self.show_pos_txt():
            self.stop_scroll_check()
            wx.CallLater(self.rate * 5, self.function_to_call) # <--
approx. intervall ??
        else:
            self.saved_position = self.show_pos_txt()
            self.function_to_call()

    def start_scroll_check(self):
        if not self.timer:
            self.saved_position = self.show_pos_txt()
            self.timer = wx.Timer(self.scrolling_widget)
            self.scrolling_widget.Bind(wx.EVT_TIMER,
self.scroll_pos_check, id=self.timer.GetId())
            self.timer.Start(self.rate)

    def stop_scroll_check(self):
        if self.timer:
            self.timer.Stop()
            self.scrolling_widget.Disconnect(self.timer.GetId())
            self.timer.Destroy()
            self.timer = None
            self.saved_position = None
            self.function_to_call()

if __name__ == '__main__':
    appl = wx.App(redirect=False)
    frm = TextFrame(None, -1, "mousewheel - scrolling position - ??")
    frm.Show()
    appl.MainLoop()

###########################

Vlastimil Brom wrote:

Hi all,
I'd like to ask about the standard way to handle the wx.EVT_MOUSEWHEEL
on a TextCtrl widget.

There isn't a standard way. The native widgets handle the low level events (or not) their own way and wx makes no guarantees about behaviors when intercepting them yourself.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!