One possibility would be to use a wx.Timer. This could capture changes of selection whether made by the mouse, keyboard or programmatically. It would probably be necessary to tweak the timer interval to make it responsive enough, without putting too much load on the system.
Here is a simple demo:
import wx
TEXT = (
"Lorem IPSUM dolor sit amet, consectetur adipiscing elit, "
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
"Vestibulum lectus mauris ultrices eros in cursus turpis. "
"Dui vivamus arcu felis bibendum ut. "
"Ac turpis egestas integer eget aliquet nibh praesent tristique magna. "
"Mauris ultrices eros in cursus turpis massa tincidunt dui. "
"Mi bibendum neque egestas congue. "
"Nunc sed augue lacus viverra vitae congue eu consequat. "
"Consectetur adipiscing elit pellentesque habitant morbi. "
"Pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at. "
"Ut lectus arcu bibendum at varius. "
"Pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio. "
"Eget aliquet nibh praesent tristique. "
"Sit amet aliquam id diam maecenas ultricies mi eget. "
"Iaculis nunc sed augue lacus viverra vitae congue eu. "
"Fames ac turpis egestas sed tempus urna. A diam maecenas sed enim ut sem. "
"Aenean pharetra magna ac placerat vestibulum lectus mauris ultrices. "
"Velit egestas dui id ornare arcu odio ut sem nulla. "
"Placerat duis ultricies lacus sed. "
"Libero enim sed faucibus turpis in eu mi bibendum. "
)
# milliseconds
TIMER_INTERVAL = 200
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((500, 300))
self.SetTitle("frame")
self.panel = wx.Panel(self, wx.ID_ANY)
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl = wx.TextCtrl(self.panel, wx.ID_ANY, "", style=wx.TE_MULTILINE)
main_sizer.Add(self.text_ctrl, 1, wx.ALL | wx.EXPAND, 4)
self.panel.SetSizer(main_sizer)
self.Layout()
self.text_ctrl.SetValue(TEXT)
self.selection_len = 0
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer)
self.timer.Start(TIMER_INTERVAL)
def OnClose(self, _event):
self.timer.Stop()
self.Destroy()
def OnTimer(self, _event):
current_len = len(self.text_ctrl.GetStringSelection())
if current_len != self.selection_len:
print(current_len)
self.selection_len = current_len
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()