I (Will Sadkin) wrote:
1) I need to have clicking in any part of the row select
the entire row, and I need to enforce that only one row
be selected at a time. I thought I had a solution for this,
but it doesn't work right.
[...]In the code using the class, I've also registered a handler on
EVT_GRID_RANGE_SELECT, to wit:
EVT_GRID_RANGE_SELECT(self.mygrid, self.OnSelectRule)def OnSelectRule(self, event=None):
print 'parent's OnSelectRule'
[...]but it *never fires*, even though I'm clearly calling evt.skip()...
So I don't understand why the GRID_RANGE_SELECT event doesn't
propagate up the event handler chain, so the parent can take action
when the row selection changes.Can anyone tell my why this doesn't work, or what I have to do
to get it to work?
[...]
Well, I found a workaround for this issue (1 of 3).
The behavior I'm seeing would be explained if the
EVT_GRID_RANGE_SELECT event was not derived from wxCommandEvent
(like it says it is in the documentation), and so isn't pushed
up the event chain like (at least many) other wxGrid events.
I don't have ready access to the C++, so I can't tell for sure,
but it seems plausible...
However, wxPython is nothing if not flexible, so...
I invented my own EVT_GRID_ROW_SELECTED event, and now fire
that from the grid's internal EVT_GRID_RANGE_SELECT routine.
I also had to change the code to use wxCallAfter to get the
row selection to work properly. so, the code is now of
the form:
wxEVT_GRID_ROW_SELECTED = wxNewEventType()
def EVT_GRID_ROW_SELECTED(win, id, func):
"""Used to trap events indicating that the current
row selection of the control has been changed."""
win.Connect(id, -1, wxEVT_GRID_ROW_SELECTED, func)
class wxGridRowSelectedEvent(wxPyCommandEvent):
def __init__(self, id, row = 0, object=None):
wxPyCommandEvent.__init__(self,
wxEVT_GRID_ROW_SELECTED, id)
self.__row = row
self.SetEventObject(object)
def GetRow(self):
"""Retrieve the value of the control at the time
this event was generated."""
return self.__row
class myGrid(wxGrid):
def __init__(self, parent, id=-1, pos=wxDefaultPosition,
size=wxDefaultSize, style=wxWANTS_CHARS):
wxGrid.__init__(self, parent, id, pos=pos, size=size)
self.SetSelectionMode(wxGrid.wxGridSelectRows)
self.__leftClickRow = None
[...]
EVT_GRID_RANGE_SELECT(self, self.OnRangeSelect)
def OnRangeSelect(self, evt):
top_left, bottom_right = evt.GetTopLeftCoords(), \
evt.GetBottomRightCoords()
if top_left[0] != bottom_right[0] and evt.Selecting():
if self.__leftClickRow is not None:
# pick last row selected
if top_left[0] == self.__leftClickRow:
selectrow = bottom_right[0]
else:
selectrow = top_left[0]
self.__leftClickRow = None # reset for next event
else:
# pick top left (arbitrarily)
selectrow = top_left[0]
else:
selectrow = top_left[0]
selected = self.GetSelectedRows()
if( evt.Selecting() and len(selected) != 1
or (len(selected) == 1 and selected[0] != selectrow)):
wxCallAfter(self.SelectRow, selectrow )
evt.Skip()
def SelectRow(self, i):
wxGrid.SelectRow(self, i)
try:
self.GetEventHandler().ProcessEvent(
wxGridRowSelectedEvent( self.GetId(), i, self ) )
except RangeError:
return
It'd be nice if someone could confirm my suspicions re:
EVT_GRID_RANGE_SELECT and let me know if I should file a
bugreport about this. Also, if there's an easier way to
get the effect I want, I'm all ears!
(Note: I'm still looking for answers on my other two wxGrid
questions.)
Regards,
/Will Sadkin
Parlance Corporation