Capturing mouse position in top level windows with children

I have a top level wx.Frame that contains a single wx.Panel as a child. I would like to capture the position of the mouse cursor in the top level frame, display the mouse coords in a status bar, and then pass this positional data to the child panel for further processing. However, if I bind the EVT_MOTION event to the top level frame, nothing happens (I assume because the panel takes up all the available window area and it doesn’t inherit the event handler from the parent frame). If I move this binding to be within the child panel, I am able to capture data from within this panel, but not for the whole frame.

Is there a way to capture the mouse position in the top level parent frame and propagate it downstream to child window event handlers as necessary?

My code:

import wx

class myPanel(wx.Panel):

def init(self, parent):

wx.Panel.init(self, parent)

fancy painting code to go here

class myWindow(wx.Frame):

def init(self, parent):

wx.Frame.init(self, parent, -1, “hello”, size=(500,500))

self.CreateStatusBar()

self.pan = wx.Panel(self)

self.Bind(wx.EVT_MOTION, self.onMouseMove)

def onMouseMove(self, event): #never called because mouse is always on the panel?

position = event.GetPosition()

self.SetStatusText(“Mouse X: %d Y: %d” %(position.x, position.y))

if name == ‘main’:

app = wx.App(redirect=False)

frame = myWindow(None)

frame.Show(True)

app.MainLoop()

rasbx8@gmail.com wrote:

I have a top level wx.Frame that contains a single wx.Panel as a child.
I would like to capture the position of the mouse cursor in the top
level frame, display the mouse coords in a status bar, and then pass
this positional data to the child panel for further processing. However,
if I bind the EVT_MOTION event to the top level frame, nothing happens
(I assume because the panel takes up all the available window area and
it doesn't inherit the event handler from the parent frame). If I move
this binding to be within the child panel, I am able to capture data
from within this panel, but not for the whole frame.

Is there a way to capture the mouse position in the top level parent
frame and propagate it downstream to child window event handlers as
necessary?

Not simply. Events in wx tend to work the other way around, traveling up the containment hierarchy in search of a handler. But since mouse events are not command events they don't even do that much, they are only sent to the widget in which they happen. For mouse events that means that they are only sent to the widgets on the top of the z-order.

It takes a little more brute force but you can still do something like what you want. Basically you would need to Bind() the EVT_MOTION event to every widget contained within the frame (a recursive traversal using GetChildren would be a good way to do it) and bind them to a method in the frame. If that method calls event.Skip() then the event system will still look for a handler in the widget class and call it if there is one. Keep in mind that the coordinates in the mouse events will be relative to the widget not the frame, but you can use something like this to translate them to be relative to the frame if you need it:

self.ScreenToClient(event.GetEventObject().ClientToScreen(event.GetPos()))

···

--
Robin Dunn
Software Craftsman

Love it!

···

On 2/25/2014 9:06 PM, Robin Dunn wrote:

self.ScreenToClient(event.GetEventObject().ClientToScreen(event.GetPos()))