[wxPython] Problems with focus events

I tried to send this a few days ago, but it seems I managed to
foul up. Apologies if you get it twice...

I want to be able to move between some grids in a wxFlexGridSizer
using Ctrl-Arrow, and that works ok, but I also want things to
happen in the grids that I leave and arrive to... It doesn't... :frowning:
I assumed the correct thing would be to use OnSetFocus and OnKillFocus.

The code below illustrates the problem.

I obviously set focus to diffeent grids using .SetFocus(), but
no EVT_SET_FOCUS or EVT_KILL_FOCUS seem to occur until I close
the application. Only then I get the print outs from OnSetFocus
and OnKillFocus. They seem to print the id for the grid where I
have my focus when the app is closed, but on the other hand, they
never point to the same object as wxWindow_FindFocus()!

Why doesn't this work? Doesn't the grid get the focus? Is it
a cell in the grid that gets the focus? What do I do?

class MyGrid(wxGrid):
聽聽聽聽聽def __init__(self, parent, id, x, y):
聽聽聽聽聽聽聽聽聽[snip]
聽聽聽聽聽聽聽聽EVT_SET_FOCUS(self, self.OnSetFocus)
聽聽聽聽聽聽聽聽聽EVT_KILL_FOCUS(self, self.OnKillFocus)

聽聽聽聽聽def OnSetFocus(self, evt):
聽聽聽聽聽聽聽聽聽print "Set focus", self
聽聽聽聽聽聽聽聽聽print "Focus", wxWindow_FindFocus()

聽聽聽聽聽def OnKillFocus(self, evt):
聽聽聽聽聽聽聽聽聽print "Kill focus", self
聽聽聽聽聽聽聽聽聽print "Focus", wxWindow_FindFocus()

Can anyone enlighten me please?

Platform is Win2k, ActivePython 2.1.1 (running from cmd line) and
wxPython 2.3.1.

TIA

Magnus

Entire program:

#evt_demo.py
#Magnus Lyck氓, Thinkware AB, 2001

from wxPython.wx import *
from wxPython.grid import *

def invertDict(d):
聽聽聽聽聽result = {}
聽聽聽聽聽for key, value in d.items():
聽聽聽聽聽聽聽聽聽result[value] = key
聽聽聽聽聽return result

class MyFrame(wxFrame):
聽聽聽聽聽def __init__(self, parent, id, title):
聽聽聽聽聽聽聽聽聽wxFrame.__init__(self, parent, id, title,
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽wxPoint(100, 100), wxSize(600, 400))
聽聽聽聽聽聽聽聽聽self.locationOfGrids = {} # Used for movement between grids.

聽聽聽聽聽def AddGrids(self, gridArray):
聽聽聽聽聽聽聽聽聽#grid array contains a list of lists.
聽聽聽聽聽聽聽聽聽#Each inner list is a row of grids to
聽聽聽聽聽聽聽聽聽#be positioned from top to bottom.
聽聽聽聽聽聽聽聽聽assert type(gridArray)==type([])
聽聽聽聽聽聽聽聽聽self.rows = len(gridArray)
聽聽聽聽聽聽聽聽聽self.cols = len(gridArray[0])
聽聽聽聽聽聽聽聽聽self.sizer = wxFlexGridSizer(self.rows, self.cols, 1, 1)
聽聽聽聽聽聽聽聽聽for i in range(self.cols):
聽聽聽聽聽聽聽聽聽聽聽聽聽self.sizer.AddGrowableCol(i)
聽聽聽聽聽聽聽聽聽for i in range(self.rows):
聽聽聽聽聽聽聽聽聽聽聽聽聽self.sizer.AddGrowableRow(i)
聽聽聽聽聽聽聽聽聽self.SetSizer(self.sizer)
聽聽聽聽聽聽聽聽聽for row, y in zip(gridArray,range(self.rows)):
聽聽聽聽聽聽聽聽聽聽聽聽聽assert type(row) == type([])
聽聽聽聽聽聽聽聽聽聽聽聽聽assert len(row) == self.cols
聽聽聽聽聽聽聽聽聽聽聽聽聽for grid, x in zip(row, range(self.cols)):
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽self.locationOfGrids[grid] = (x,y)
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽self.sizer.AddWindow(grid, 0, wxGROW>wxALIGN_CENTER_VERTICAL|wxALL, 5)
聽聽聽聽聽聽聽聽聽self.sizer.Fit(self)
聽聽聽聽聽聽聽聽聽self.SetAutoLayout(true)

聽聽聽聽聽def GoTo(self, callingGrid, direction):
聽聽聽聽聽聽聽聽聽assert direction in ['up', 'down', 'right', 'left'], \
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽"GoTo doesn't understand direction %s" % str(direction)
聽聽聽聽聽聽聽聽聽print "Moving", direction
聽聽聽聽聽聽聽聽聽print "Focus", wxWindow_FindFocus()
聽聽聽聽聽聽聽聽聽x,y = self.locationOfGrids[callingGrid]
聽聽聽聽聽聽聽聽聽if direction == 'up':
聽聽聽聽聽聽聽聽聽聽聽聽聽if y == 0:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽return
聽聽聽聽聽聽聽聽聽聽聽聽聽else:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽y -= 1
聽聽聽聽聽聽聽聽聽elif direction == 'down':
聽聽聽聽聽聽聽聽聽聽聽聽聽if y == self.rows - 1:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽return
聽聽聽聽聽聽聽聽聽聽聽聽聽else:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽y += 1
聽聽聽聽聽聽聽聽聽elif direction == 'left':
聽聽聽聽聽聽聽聽聽聽聽聽聽if x == 0:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽return
聽聽聽聽聽聽聽聽聽聽聽聽聽else:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽x -= 1
聽聽聽聽聽聽聽聽聽else: #right
聽聽聽聽聽聽聽聽聽聽聽聽聽if x == self.cols - 1:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽return
聽聽聽聽聽聽聽聽聽聽聽聽聽else:
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽x += 1
聽聽聽聽聽聽聽聽聽gridInLocation = invertDict(self.locationOfGrids)
聽聽聽聽聽聽聽聽聽newGrid = gridInLocation[(x,y)]
聽聽聽聽聽聽聽聽聽newGrid.SetFocus()

class MyGrid(wxGrid):
聽聽聽聽聽def __init__(self, parent, id, x, y):
聽聽聽聽聽聽聽聽聽self.parent = parent
聽聽聽聽聽聽聽聽聽wxGrid.__init__(self, parent, id, wxDefaultPosition,
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽wxSize(x, y),
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽wxWANTS_CHARS)
聽聽聽聽聽聽聽聽聽self.CreateGrid(10, 4)
聽聽聽聽聽聽聽聽聽self.SetColLabelSize(0)
聽聽聽聽聽聽聽聽聽self.SetRowLabelSize(0)
聽聽聽聽聽聽聽聽聽EVT_KEY_DOWN(self, self.OnKeyDown)
聽聽聽聽聽聽聽聽聽EVT_SET_FOCUS(self, self.OnSetFocus)
聽聽聽聽聽聽聽聽聽EVT_KILL_FOCUS(self, self.OnKillFocus)

聽聽聽聽聽def OnSetFocus(self, evt):
聽聽聽聽聽聽聽聽聽print "Set focus", self
聽聽聽聽聽聽聽聽聽print "Focus", wxWindow_FindFocus()

聽聽聽聽聽def OnKillFocus(self, evt):
聽聽聽聽聽聽聽聽聽print "Kill focus", self
聽聽聽聽聽聽聽聽聽print "Focus", wxWindow_FindFocus()

聽聽聽聽聽def OnKeyDown(self, evt):
聽聽聽聽聽聽聽聽聽directions = {WXK_LEFT: 'left',
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽WXK_UP: 'up',
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽WXK_RIGHT: 'right',
聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽WXK_DOWN: 'down'}
聽聽聽聽聽聽聽聽聽keyCode, ctrl = evt.KeyCode(), evt.ControlDown()
聽聽聽聽聽聽聽聽聽if keyCode in directions.keys() and ctrl:
聽聽聽聽聽聽聽聽聽聽聽聽聽self.DisableCellEditControl()
聽聽聽聽聽聽聽聽聽聽聽聽聽self.parent.GoTo(self, directions[keyCode])
聽聽聽聽聽聽聽聽聽else:
聽聽聽聽聽聽聽聽聽聽聽聽聽evt.Skip()

class MyApp(wxApp):
聽聽聽聽聽def OnInit(self):
聽聽聽聽聽聽聽聽聽self.frame = MyFrame(NULL, -1, "This is an event demo")
聽聽聽聽聽聽聽聽聽self.idCnt = 6000
聽聽聽聽聽聽聽聽聽g = [[self.newGrid(),self.newGrid(),self.newGrid()],
聽聽聽聽聽聽聽聽聽聽聽聽聽聽[self.newGrid(),self.newGrid(),self.newGrid()],
聽聽聽聽聽聽聽聽聽聽聽聽聽聽[self.newGrid(),self.newGrid(),self.newGrid()]]
聽聽聽聽聽聽聽聽聽self.frame.AddGrids(g)
聽聽聽聽聽聽聽聽聽self.frame.Show(true)
聽聽聽聽聽聽聽聽聽self.SetTopWindow(self.frame)
聽聽聽聽聽聽聽聽聽return true
聽聽聽聽聽def newGrid(self):
聽聽聽聽聽聽聽聽聽self.idCnt += 1
聽聽聽聽聽聽聽聽聽return MyGrid(self.frame, self.idCnt, 200, 100)

def main():
聽聽聽聽聽app = MyApp(0)
聽聽聽聽聽app.MainLoop()

if __name__ == '__main__':
聽聽聽聽聽main()

路路路

--
Magnus Lyck氓, Thinkware AB
脛lvans v盲g 99, SE-907 50 UME脜
tel 070-582 80 65, fax: 070-612 80 65
http://www.thinkware.se/ mailto:magnus@thinkware.se

I obviously set focus to diffeent grids using .SetFocus(), but
no EVT_SET_FOCUS or EVT_KILL_FOCUS seem to occur until I close
the application.

The wxGrid is actually composed of several windows, one for the row and
column label areas, one for the grid itself, one of the bit in the corner,
and one to handle the scrolling. If you attach your events to the grid
window (which is accessible with theGrid.GetGridWindow()) then you'll
probably get closer to the functionality you are after.

路路路

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

Splendid! Just what I needed.

   Thanks,

   Magnus

P.S. Am I blind, or is there an ommission in the docs here?

路路路

At 17:10 2001-10-11 -0700, Robin Dunn wrote:

> I obviously set focus to diffeent grids using .SetFocus(), but
> no EVT_SET_FOCUS or EVT_KILL_FOCUS seem to occur until I close
> the application.

The wxGrid is actually composed of several windows, one for the row and
column label areas, one for the grid itself, one of the bit in the corner,
and one to handle the scrolling. If you attach your events to the grid
window (which is accessible with theGrid.GetGridWindow()) then you'll
probably get closer to the functionality you are after.

--
Magnus Lyck氓, Thinkware AB
脛lvans v盲g 99, SE-907 50 UME脜
tel 070-582 80 65, fax: 070-612 80 65
http://www.thinkware.se/ mailto:magnus@thinkware.se

I was happy for a minute, but now it crashes on program
exit in Win 98 SE. :frowning:

聽聽聽聽聽def OnKillFocus(self, evt):
聽聽聽聽聽聽聽聽聽self.SetGridLineColour(wxBLACK)

The grid has already been removed from the screen when
self.SetGridLineColour(wxBLACK) is executed so I get an
illegal page error.

How do I check for this? It wasn't as easy as "if self:" :slight_smile:

Is there a good general solution to this, or is there a chance
that I might have to litter event methods with guards?

/Magnus

路路路

--
Magnus Lyck氓, Thinkware AB
脛lvans v盲g 99, SE-907 50 UME脜
tel 070-582 80 65, fax: 070-612 80 65
http://www.thinkware.se/ mailto:magnus@thinkware.se

I was happy for a minute, but now it crashes on program
exit in Win 98 SE. :frowning:

     def OnKillFocus(self, evt):
         self.SetGridLineColour(wxBLACK)

The grid has already been removed from the screen when
self.SetGridLineColour(wxBLACK) is executed so I get an
illegal page error.

How do I check for this? It wasn't as easy as "if self:" :slight_smile:

Is there a good general solution to this, or is there a chance
that I might have to litter event methods with guards?

There's a cookbook entry in the wiki about this, but it is dead at the
moment... The problem is that on wxMSW if a window has the focus when it is
destroyed then Windows sends a kill focus message. Since the Python object
still exists at that time you get a crash when you try to do anything with
the C++ object.

Possible workarounds:

1. Set a flag when closing and check it in your OnKillFocus.

2. Explicitly set focus to some other control before closing the app.

3. Disconnect the kill focus event before closing the app.
"grid.GetGridWindow().Disconnect(-1,-1,wxEVT_KILL_FOCUS)"

路路路

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