Jason Diamond wrote:
But it won't as soon as there are other controls on the dialog. Key events are only sent to the window that has the focus, so if there is a textctrl that has the focus then the dialog won't get the key events.
Are you implying that this is only the case for dialogs and not frames?
No, it is the same everywhere. Only the widget with the focus will get the key events.
I tried adding a text control to the dialog. Even though I could see plenty of blank dialog space and tried clicking on it, the text control wouldn't give up the focus.
Actually, the dialog is just handing the focus back to it's child that had it last. wx.Panel's will do the same.
So hitting RETURN and DELETE (what Craig was testing for in his original sample) was swallowed up by the text control.
When I changed the dialog into a frame (and then added a sizer so the text control didn't auto-expand to the full size of the frame), I was able to click outside the text control and onto the frame to give the frame focus which did cause the key events to caught by the frame.
Because the frame doesn't do the give-back of the focus like dialogs and panels do. Normally you woudl have the entire client area of the frame covered by child windows anyway so the frame normally would never get the focus and have to do anything with it.
That's probably not a very realistic example of what would happen in the real world, though--I'm just trying to understand as much as I can about how the framework works. I suspect that even adding a panel (which you almost always do with frames) would cause the frame to never receive the key events.
Correct.
I've never tried it with dialogs, but the way you would normally handle this is to use wx.AcceleratorTable and associate it with the dialog. Also, dialogs have a special feature that turns ESC key presses into a button event with an ID of wx.ID_CANCEL, and RETURN keys are turned into a button event with an ID of wx.ID_OK, perhaps that is enough? The wx.Dialog class binds these events to default behaviours, but you can bind them too.
I tried adding an accelerator table to a frame and it was able to capture both return and delete key events even when the text control had focus. When I tried it with the dialog, only the delete key events made it through. Maybe wx.Dialog is eating the return key events up before the accelerator table is getting a crack at them.
Probably. It's going to search for a button with ID wx.ID_OK and will cause it to send a EVT_BUTTON event. BTW, there is a bit of platform differences here, in the wxGTK version the Accelerator for RETURN will be activated.
The code included below is Craig's original, modified to include the accelerator table. OnReturn never gets called.
import wx
class Dialog(wx.Dialog):
def __init__(self, parent, id, title):
wx.Dialog.__init__(self, parent, id, title, (300, 200), (300, 200))
aTable = wx.AcceleratorTable(
[
(wx.ACCEL_NORMAL, wx.WXK_RETURN, 10001),
(wx.ACCEL_NORMAL, wx.WXK_DELETE, 10002)
])
self.SetAcceleratorTable(aTable)
textCtrl = wx.TextCtrl(self)
ok = wx.Button(self, wx.ID_OK, "OK")
ok.SetDefault()
cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(textCtrl, 0, wx.ALL, 5)
sizer.Add(ok, 0, wx.ALL, 5)
sizer.Add(cancel, 0, wx.ALL, 5)
self.SetSizer(sizer)
self.Layout()
wx.EVT_MENU(self, 10001, self.OnReturn)
wx.EVT_MENU(self, 10002, self.OnDelete)
wx.EVT_BUTTON(self, wx.ID_OK, self.OnButton)
def OnReturn(self, event):
print 'OnReturn'
def OnDelete(self, event):
print 'OnDelete'
def OnButton(self, evt):
print "Ok Button"
app = wx.PySimpleApp()
dlg = Dialog(None, 10000, 'Hello, AcceleratorTable!')
val = dlg.ShowModal()
dlg.Destroy()
app.MainLoop()
···
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!