EVT_MOTION does not work for wxGrid

Using wxPython 2.6

import wx.grid as gridlib
class TestGrid(gridlib.Grid):
    def __init__(self, parent):
        gridlib.Grid.__init__(self, parent, -1)
        self.CreateGrid(2, 2)
        self.Bind(
            wx.EVT_MOTION,
            self.OnMotion,
            self
        )
    def OnMotion(self,event):
        print "Motion"
        event.Skip()

OnMotion never gets called. I would like to determine which cell is above the mouse, whenever the user moves the mouse.
I wanted to use XToCol and YToCol but I could not catch the event.
What am I doing wrong?
Thank you,

  Les

László Nagy wrote:

Using wxPython 2.6

import wx.grid as gridlib
class TestGrid(gridlib.Grid):
   def __init__(self, parent):
       gridlib.Grid.__init__(self, parent, -1)
       self.CreateGrid(2, 2)
       self.Bind(
           wx.EVT_MOTION,
           self.OnMotion,
           self
       )
   def OnMotion(self,event):
       print "Motion"
       event.Skip()

OnMotion never gets called. I would like to determine which cell is above the mouse, whenever the user moves the mouse.
I wanted to use XToCol and YToCol but I could not catch the event.
What am I doing wrong?

You need to bind to the GridWindow:
     def __init__(self, parent):
         gridlib.Grid.__init__(self, parent, -1)
         self.CreateGrid(2, 2)
         self.GetGridWindow().Bind(
             wx.EVT_MOTION,
             self.OnMotion,
             self
         )

Hope this helps

···

--
Paul McNett
http://paulmcnett.com
http://dabodev.com

Paul McNett wrote:

You need to bind to the GridWindow:
    def __init__(self, parent):
        gridlib.Grid.__init__(self, parent, -1)
        self.CreateGrid(2, 2)
        self.GetGridWindow().Bind(
            wx.EVT_MOTION,
            self.OnMotion,
            self
        )

Oops:

      def __init__(self, parent):
          gridlib.Grid.__init__(self, parent, -1)
          self.CreateGrid(2, 2)
          self.GetGridWindow().Bind(wx.EVT_MOTION, self.OnMotion)

···

--
Paul McNett
http://paulmcnett.com
http://dabodev.com

You need to bind to the GridWindow:
    def __init__(self, parent):
        gridlib.Grid.__init__(self, parent, -1)
        self.CreateGrid(2, 2)
        self.GetGridWindow().Bind(
            wx.EVT_MOTION,
            self.OnMotion,
            self
        )

Hope this helps

Opps, works only if you pass it to Bind too:

        self.GetGridWindow().Bind(
            wx.EVT_MOTION,
            self.OnMotion,
            self.GetGridWindow()
        )

But how do you know of this? GetGridWindow is not documented (at least not on the wxPython docs installed with 2.6).
What is GetGridWindow?

Thank you!

   Les

László Nagy wrote:

Opps, works only if you pass it to Bind too:

       self.GetGridWindow().Bind(
           wx.EVT_MOTION,
           self.OnMotion,
           self.GetGridWindow()
       )

Yep, see my second message which also does the trick.

But how do you know of this? GetGridWindow is not documented (at least not on the wxPython docs installed with 2.6).
What is GetGridWindow?

Nope, it isn't documented anywhere I can find either, other than in "import wx.grid;help(wx.grid.Grid.GetGridWindow)". I know of it only after innumerable sessions of whacking my head and pulling my hair out trying to wrestle wx.Grid down to something I could use for Dabo's dGrid control, which provides a much simpler and easier to use interface. For example, to do the motion binding in Dabo's dGrid, you would issue:

grid.bindEvent(dEvents.GridMouseMove, self.onMotion)

and dGrid works out which wx event to bind to, in this case binding to the undocumented GetGridWindow() object.

For completeness sake, there are a few of these underdocumented windows:

GetGridColLabelWindow:
the "Header". In Dabo, it is expressed as grid.Header

GetGridCornerLabelWindow:
I can only guess it is the intersection between rows and columns, that little thing in the corner. I suppose you could put some text or an icon there or something.

GetGridRowLabelWindow:
The vertical window that comprises the row labels.

GetGridWindow:
The actual window where the grid cells are drawn.

The "Grid" is really a container of the above windows, and as such won't always receive events that are generated from the child windows.

Everything I say here is based 100% on observation. I've never looked at the wxPython or wxWidgets source.

···

--
Paul McNett
http://paulmcnett.com
http://dabodev.com

Paul,

First of all, thank you for your help. I needed a guru like you. :slight_smile:
Now I'm trying to determine the cell position from the mouse position.

    def OnMotion(self,event):
        x,y = event.GetX(),event.GetY()
        self.curcol,self.currow = self.XToCol(x),self.XToCol(y)
        print "[%s,%s]"%(self.curcol,self.currow)
        event.Skip()

This works for the first two rows and cols. But over that, it always writes out 0 or 1. What am I doing wrong?
Sorry for the silly questions. :frowning: This is the first time I use wx.Grid.

   Les

László Nagy wrote:

First of all, thank you for your help. I needed a guru like you. :slight_smile:

I'm no guru, just a student of wx like you.

Now I'm trying to determine the cell position from the mouse position.

   def OnMotion(self,event):
       x,y = event.GetX(),event.GetY()
       self.curcol,self.currow = self.XToCol(x),self.XToCol(y)
       print "[%s,%s]"%(self.curcol,self.currow)
       event.Skip()

This works for the first two rows and cols. But over that, it always writes out 0 or 1. What am I doing wrong?
Sorry for the silly questions. :frowning: This is the first time I use wx.Grid.

Well, right off, you have a spelling error. I think you want:

self.curcol, self.currow = self.XToCol(x), self.YToRow(y)

Also, put more than 2 rows and cols in your test grid, maybe 3 cols and 7 rows. That way, you catch silly errors like that right away. When the only possible value of row or col is 0 or 1, it isn't easy to see what could be wrong. Set up your tests so you can easily find the errors.

···

--
Paul McNett
http://paulmcnett.com
http://dabodev.com

Well, right off, you have a spelling error. I think you want:

self.curcol, self.currow = self.XToCol(x), self.YToRow(y)

Sorry. Yes, I had a spelling error. But it is still bad if the grid is scrolled to some position.
Finally, I found this in the wxPython demos (column and row drag example):

        # the x,y coordinates here are Unscrolled coordinates. They must be changed
        # to scrolled coordinates.
        x, y = self.CalcUnscrolledPosition(x, y)
        # now we need to get the row and column from the grid
        # but we need to first remove the RowLabel and ColumnLabel
        # bounding boxes
        # Why this isn't done for us, I'll never know...
        x = x - self.GetGridRowLabelWindow().GetRect().width
        y = y - self.GetGridColLabelWindow().GetRect().height
        col = self.XToCol(x)
        row = self.YToRow(y)

Looks like Robin (or the person who wrote this) also did not know why it is so messy.
I don't know why he substracted self.GetGridRowLabelWindow().GetRect().width and
self.GetGridColLabelWindow().GetRect().height because it is not needed. (???)

The one that is working for me:

    def HitCellTest(self,x,y):
        x, y = self.CalcUnscrolledPosition(x, y)
        return self.XToCol(x),self.YToRow(y)

Can we have a wxPython method in wx.Grid, called 'CellHitTest' or something similar?
I believe many wxPython users will want the same functionality. It is too annoying to have 2 lines of
code for such a primitive function. It would be a great improvement to wx.Grid and it would save
hours for many of us.

   Les