wxGrid navigation and column tooltips

Hi,

I have a wx.Grid that I'm using for as a spreadsheet in one of my
applications. I would like to override the grid cell editor's arrow key
navigation so that when I press one of the keys, it will navigate away
from the cell I am currently editing, like MS Excel does. While I can
successfully catch the keycodes for the buttons when I am not editing a
cell, they seem to get eaten once I actually activate the editor. Is there
a way to do this?

Also, one of my users asked if I could put pop-up tooltips on the column
name when moused over. I can't find anything about mouse-over events. I
did find this excellent tutorial on grid cell tooltips:
http://wiki.wxpython.org/wxGrid_ToolTips

Unfortunately, it doesn't apply to my case. Any help one these two issues
would be appreciated.

I am using wxPython 2.8.4, Python 2.4 on Windows XP SP2. Thanks!

Mike Driscoll
Applications Specialist
MCIS - Technology Center

Mike Driscoll wrote:

Hi,

I have a wx.Grid that I'm using for as a spreadsheet in one of my
applications. I would like to override the grid cell editor's arrow key
navigation so that when I press one of the keys, it will navigate away
from the cell I am currently editing, like MS Excel does. While I can
successfully catch the keycodes for the buttons when I am not editing a
cell, they seem to get eaten once I actually activate the editor. Is there
a way to do this?

Keep in mind that when the cell editor is shown that there is another widget there, and so the grid itself doses not have the keyboard focus anymore, and so it will not be getting the key events. You can however bind your own key handler to the cell editor widget and take care of things there. Bind a handler for the EVT_GRID_EDITOR_CREATED event and in the handler you can use event.GetControl() to get a reference to the widget.

Also, one of my users asked if I could put pop-up tooltips on the column
name when moused over. I can't find anything about mouse-over events.

You can intercept the mouse events for the theGrid.GetGridColLabelWindow() and show a tip window if you sense that the mouse is hovering. Be sure to call event.Skip() so the default event handlers in the grid will still be called.

···

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

From: Robin Dunn [mailto:robin@alldunn.com]
Sent: Tuesday, October 02, 2007 2:39 PM
To: wxPython-users@lists.wxwidgets.org
Subject: Re: [wxPython-users] wxGrid navigation and column tooltips

Mike Driscoll wrote:
> Hi,
>
> I have a wx.Grid that I'm using for as a spreadsheet in one of my
> applications. I would like to override the grid cell editor's arrow
> key navigation so that when I press one of the keys, it
will navigate
> away from the cell I am currently editing, like MS Excel
does. While I
> can successfully catch the keycodes for the buttons when I am not
> editing a cell, they seem to get eaten once I actually activate the
> editor. Is there a way to do this?

Keep in mind that when the cell editor is shown that there is
another widget there, and so the grid itself doses not have
the keyboard focus anymore, and so it will not be getting the
key events. You can however bind your own key handler to the
cell editor widget and take care of things there. Bind a
handler for the EVT_GRID_EDITOR_CREATED event and in the
handler you can use event.GetControl() to get a reference to
the widget.

This worked exactly as described. I figured the editor was some kind of
"sub-widget" or something. Thanks!

>
> Also, one of my users asked if I could put pop-up tooltips on the
> column name when moused over. I can't find anything about
mouse-over events.

You can intercept the mouse events for the
theGrid.GetGridColLabelWindow() and show a tip window if you
sense that the mouse is hovering. Be sure to call
event.Skip() so the default event handlers in the grid will
still be called.

I almost have this, but I must still be missing something. I am currently
binding my grid to EVT_GRID_LABEL_LEFT_CLICK and then using the following
handler:

def onColClick(self, event):
    colNum = event.GetCol()
    col_dict = {1:'Column 1', 2:'Column 2'}
    self.myGrid.GetGridColLabelWindow().SetToolTipString(col_dict[colNum])
    event.Skip()

This works for left-clicking the column only. I tried to bind to
EVT_MOTION and EVT_ENTER_WINDOW, but those don't seem to work with the
grid since they're not grid specific events.

Thanks for any tips.

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

Mike

···

-----Original Message-----

> >
> > Also, one of my users asked if I could put pop-up tooltips on the
> > column name when moused over. I can't find anything about
> mouse-over events.
>
> You can intercept the mouse events for the
> theGrid.GetGridColLabelWindow() and show a tip window if you sense
> that the mouse is hovering. Be sure to call
> event.Skip() so the default event handlers in the grid will
still be
> called.
>

I almost have this, but I must still be missing something. I
am currently binding my grid to EVT_GRID_LABEL_LEFT_CLICK and
then using the following handler:

def onColClick(self, event):
    colNum = event.GetCol()
    col_dict = {1:'Column 1', 2:'Column 2'}
    
self.myGrid.GetGridColLabelWindow().SetToolTipString(col_dict[colNum])
    event.Skip()

This works for left-clicking the column only. I tried to bind
to EVT_MOTION and EVT_ENTER_WINDOW, but those don't seem to
work with the grid since they're not grid specific events.

Thanks for any tips.

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

It seems my reply got lost somewhere. I saw it show up in the digest
though. Anyway, I still can't find the correct event to bind to so that I
can get a grid column to display a tooltip just by hovering my mouse over
it. The closest I can get is by using EVT_GRID_LABEL_LEFT_CLICK so that I
can get the tooltip to display by left-clicking the column.

Do I need to just bind to EVT_MOTION, find the mouse position and then
somehow derive where I'm at within the grid to determine what tooltip to
show? If so, I'll just skip it.

Thanks for the help.

Mike

Mike Driscoll wrote:

Also, one of my users asked if I could put pop-up tooltips on the column name when moused over. I can't find anything about

mouse-over events.

You can intercept the mouse events for the
theGrid.GetGridColLabelWindow() and show a tip window if you sense that the mouse is hovering. Be sure to call
event.Skip() so the default event handlers in the grid will

still be

called.

I almost have this, but I must still be missing something. I am currently binding my grid to EVT_GRID_LABEL_LEFT_CLICK and then using the following handler:

def onColClick(self, event):
    colNum = event.GetCol()
    col_dict = {1:'Column 1', 2:'Column 2'}
    self.myGrid.GetGridColLabelWindow().SetToolTipString(col_dict[colNum])
    event.Skip()

This works for left-clicking the column only. I tried to bind to EVT_MOTION and EVT_ENTER_WINDOW, but those don't seem to work with the grid since they're not grid specific events.

Thanks for any tips.

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

It seems my reply got lost somewhere. I saw it show up in the digest
though. Anyway, I still can't find the correct event to bind to so that I
can get a grid column to display a tooltip just by hovering my mouse over
it. The closest I can get is by using EVT_GRID_LABEL_LEFT_CLICK so that I
can get the tooltip to display by left-clicking the column.

Do you bind the mouse events using the self.myGrid.GetGridColLabelWindow() window?

Do I need to just bind to EVT_MOTION, find the mouse position and then
somehow derive where I'm at within the grid to determine what tooltip to
show?

Yes, more or less.

···

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

From: Robin Dunn [mailto:robin@alldunn.com]
Sent: Tuesday, October 09, 2007 1:19 PM
To: wxPython-users@lists.wxwidgets.org
Subject: Re: [wxPython-users] wxGrid navigation and column tooltips

Mike Driscoll wrote:
>>>> Also, one of my users asked if I could put pop-up
tooltips on the
>>>> column name when moused over. I can't find anything about
>>> mouse-over events.
>>>
>>> You can intercept the mouse events for the
>>> theGrid.GetGridColLabelWindow() and show a tip window if
you sense
>>> that the mouse is hovering. Be sure to call
>>> event.Skip() so the default event handlers in the grid will
>> still be
>>> called.
>>>
>> I almost have this, but I must still be missing something. I am
>> currently binding my grid to EVT_GRID_LABEL_LEFT_CLICK and
then using
>> the following handler:
>>
>> def onColClick(self, event):
>> colNum = event.GetCol()
>> col_dict = {1:'Column 1', 2:'Column 2'}
>>
>>
self.myGrid.GetGridColLabelWindow().SetToolTipString(col_dict[colNum])
>> event.Skip()
>>
>> This works for left-clicking the column only. I tried to bind to
>> EVT_MOTION and EVT_ENTER_WINDOW, but those don't seem to work with
>> the grid since they're not grid specific events.
>>
>> Thanks for any tips.
>>
>>> --
>>> Robin Dunn
>>> Software Craftsman
>>> http://wxPython.org Java give you jitters? Relax with wxPython!
>>>
>>>
>
> It seems my reply got lost somewhere. I saw it show up in
the digest
> though. Anyway, I still can't find the correct event to bind to so
> that I can get a grid column to display a tooltip just by
hovering my
> mouse over it. The closest I can get is by using
> EVT_GRID_LABEL_LEFT_CLICK so that I can get the tooltip to
display by left-clicking the column.

Do you bind the mouse events using the
self.myGrid.GetGridColLabelWindow() window?

Yes. I do this: self.myGrid.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK,
self.onColClick)

and then in the handler, I do:

self.sheet.GetGridColLabelWindow().SetToolTipString('some string')

>
> Do I need to just bind to EVT_MOTION, find the mouse
position and then
> somehow derive where I'm at within the grid to determine
what tooltip
> to show?

Yes, more or less.

So, if I bind to EVT_MOTION, do I just print out the position and take
down the positions of my column headers and then test for the appropriate
values? Is there some way to use the XToCol() method for this?

Thanks!

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

Mike

···

-----Original Message-----

Mike Driscoll wrote:

though. Anyway, I still can't find the correct event to bind to so that I can get a grid column to display a tooltip just by

hovering my

mouse over it. The closest I can get is by using EVT_GRID_LABEL_LEFT_CLICK so that I can get the tooltip to

display by left-clicking the column.

Do you bind the mouse events using the
self.myGrid.GetGridColLabelWindow() window?

Yes. I do this: self.myGrid.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK,
self.onColClick)

and then in the handler, I do:

self.sheet.GetGridColLabelWindow().SetToolTipString('some string')

If you want to get the low-level mouse events for the label window then you'll have to use it for the Bind too since they will not propagate up to the main Grid window.

So, if I bind to EVT_MOTION, do I just print out the position and take
down the positions of my column headers and then test for the appropriate
values? Is there some way to use the XToCol() method for this?

Yep, although you might have to offset by the width of the row label window to get the right position. Or you could just add up the widths of the columns yourself to find which one the position is within.

···

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

Robin,

From: Robin Dunn [mailto:robin@alldunn.com]
Sent: Wednesday, October 10, 2007 4:45 PM
To: wxPython-users@lists.wxwidgets.org
Subject: Re: [wxPython-users] wxGrid navigation and column tooltips

Mike Driscoll wrote:

>>> though. Anyway, I still can't find the correct event to
bind to so
>>> that I can get a grid column to display a tooltip just by
>> hovering my
>>> mouse over it. The closest I can get is by using
>>> EVT_GRID_LABEL_LEFT_CLICK so that I can get the tooltip to
>> display by left-clicking the column.
>>
>> Do you bind the mouse events using the
>> self.myGrid.GetGridColLabelWindow() window?
>>
>
>
> Yes. I do this: self.myGrid.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK,
> self.onColClick)
>
> and then in the handler, I do:
>
> self.sheet.GetGridColLabelWindow().SetToolTipString('some string')

If you want to get the low-level mouse events for the label
window then you'll have to use it for the Bind too since they
will not propagate up to the main Grid window.

>
>
> So, if I bind to EVT_MOTION, do I just print out the
position and take
> down the positions of my column headers and then test for the
> appropriate values? Is there some way to use the XToCol()
method for this?

Yep, although you might have to offset by the width of the
row label window to get the right position. Or you could
just add up the widths of the columns yourself to find which
one the position is within.

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

That did the trick. I may have to disable resizing of columns to keep it
from breaking, though. Just to be complete for all those people watching
this conversation, here's my binding and the corresponding handler:

self.myGrid.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.onMouseOver)

def onMouseOver(self, event):
    pos = event.GetX()
    if pos > someXVal and pos < someXVal:
         self.myGrid.GetGridColLabelWindow().SetToolTipString('some
string')
    event.Skip()

Thanks again. It works great!

Mike

···

-----Original Message-----

Mike Driscoll wrote:

That did the trick. I may have to disable resizing of columns to keep it
from breaking, though.

Or you could calculate the column positions when you need them instead of doing it before, then even if the column widths are changed your code will still work.

Just to be complete for all those people watching
this conversation, here's my binding and the corresponding handler:

self.myGrid.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.onMouseOver)

def onMouseOver(self, event):
    pos = event.GetX() if pos > someXVal and pos < someXVal:
         self.myGrid.GetGridColLabelWindow().SetToolTipString('some
string')
    event.Skip()

One more step you may want to take is to remember which column you set the tooltip for last time, and then not set it again if the mouse is still in the same column.

···

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

Robin,

From: Robin Dunn [mailto:robin@alldunn.com]
Sent: Thursday, October 11, 2007 1:58 PM
To: wxPython-users@lists.wxwidgets.org
Subject: Re: [wxPython-users] wxGrid navigation and column tooltips

Mike Driscoll wrote:

> That did the trick. I may have to disable resizing of
columns to keep
> it from breaking, though.

Or you could calculate the column positions when you need
them instead of doing it before, then even if the column
widths are changed your code will still work.

> Just to be complete for all those people watching this
conversation,
> here's my binding and the corresponding handler:
>
>
> self.myGrid.GetGridColLabelWindow().Bind(wx.EVT_MOTION,
> self.onMouseOver)
>
> def onMouseOver(self, event):
> pos = event.GetX()
> if pos > someXVal and pos < someXVal:
> self.myGrid.GetGridColLabelWindow().SetToolTipString('some
> string')
> event.Skip()

One more step you may want to take is to remember which
column you set the tooltip for last time, and then not set it
again if the mouse is still in the same column.

This did occur to me, but I don't see an elegant way to do it. I have 8
columns that get specific tooltips and three that I set to blank, which
really means that no tooltip displays for them. My first awful solution is
as follows (using a type of sentinel value):

<snip>

if pos > 130 and pos < 180:
      if tooltip != 'Regular Hours':
            self.myGrid.GetGridColLabelWindow().SetToolTipString('Regular
Hours')
            tooltip = 'Regular Hours'

<snap>

Reminds me of spaghetti code, although I've seen worse. Alas, this is what
I will go with for the weekend. I'm sure there's some kind of way to use a
dictionary here and it's right on the tip of my fingers, but I just can't
quite see it yet. It'll probably hit me on Monday, or maybe someone here
will hit me upside the head with my own ignorance.

Thanks!

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

Mike

···

-----Original Message-----