No comment on ESC?

In my app, I consistently use the Esc key to backout of controls
and windows. Its a very convenient key for this purpose.
Doesn't work on WinXP.

http://lists.wxwidgets.org/pipermail/wxpython-users/2008-May/075573.html
http://lists.wxwidgets.org/pipermail/wxpython-users/2008-May/075578.html

I'd like someone to tell me: yeah and it ain't gonna work before I change
everything to another hotkey.

Thanks.

For other windows try to catch wx.EVT_KEY_DOWN and in the event
handler do something like this:

    def OnKeyDown(self, event):
        keycode = event.GetKeyCode()
        if event.CmdDown() and keycode == wx.WXK_ESCAPE:
            self.Close() #or EndModal(False) for modal dialogs
        event.Skip()

Thanks, but unfortunately the below, which also works on
Kubuntu, does NOT work on WinXp.

def itmframe(s):
        s.f = item.ItemFrame(None, -1, 'Add Item')
        s.f.Bind(wx.EVT_KEY_DOWN,s.OnKeyDown)
def OnKeyDown(s,event):
        k = event.GetKeyCode()
        if k == wx.WXK_ESCAPE: s.escexit(0)

Phillip,

For other windows try to catch wx.EVT_KEY_DOWN and in the event
handler do something like this:

    def OnKeyDown(self, event):
        keycode = event.GetKeyCode()
        if event.CmdDown() and keycode == wx.WXK_ESCAPE:
            self.Close() #or EndModal(False) for modal dialogs
        event.Skip()

Thanks, but unfortunately the below, which also works on
Kubuntu, does NOT work on WinXp.

def itmframe(s):
        s.f = item.ItemFrame(None, -1, 'Add Item')
        s.f.Bind(wx.EVT_KEY_DOWN,s.OnKeyDown)
def OnKeyDown(s,event):
        k = event.GetKeyCode()
        if k == wx.WXK_ESCAPE: s.escexit(0)

Maybe I'm missing something, but this works for me. Here's my sample code:

<code>

import wx

class myFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, title='Test')
        panel = wx.Panel(self, wx.ID_ANY)

        panel.Bind(wx.EVT_KEY_DOWN, self.onKey)

    def onKey(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_ESCAPE:
            print 'You hit ESC!'
            self.Close()

if __name__ == '__main__':
    app = wx.PySimpleApp()
    myFrame().Show()
    app.MainLoop()

</code>

I'm using wxPython 2.8.7.1 (msw-unicode), Python 2.5 on Windows XP SP3.

Mike

Phillip Watts wrote:

Ok, I figured out glade (stupid me)
and got the following code then added keydown.
Works fine on Kubuntu, prints 27 when I press escape.
Does nothing on WinXP.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# generated by wxGlade 0.6.3 on Mon May 12 14:48:41 2008
import wx

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.panel_1 = wx.Panel(self, -1)
        self.button_1 = wx.Button(self.panel_1, -1, "button_1")
        self.button_2 = wx.Button(self.panel_1, -1, "button_2")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("frame_1")
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3.Add(self.button_1, 0, 0, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_4.Add(self.button_2, 0, 0, 0)
        sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
        self.panel_1.SetSizer(sizer_2)
        sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()
        # end wxGlade

# end of class MyFrame

def keydown(event):
    k = event.GetKeyCode()
    print k

if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    f = MyFrame(None, -1, "")
    app.SetTopWindow(f)
    f.Show()

    f.panel_1.Bind(wx.EVT_KEY_DOWN,keydown)
    app.MainLoop()

AND BTW. That do_layout section. That's what I can't do manually.
The tutorials don't even come close and NOTHING explains all
those methods and every example looks different.
No glade = No wxPython.

It looks like the button(s) are somehow eating the keydown events. On my PC, my speakers make a boinking noise when the keys are pressed, which confirms my suspicions. I have a feeling there's a way around this by either resetting the focus to the parent or binding the keys to the buttons and re-raising the event somehow. Maybe someone else has an idea?

I found this interesting thread about a similar problem that may help you:

Or maybe we need to bind to EVT_CHAR as this thread indicates? Hmmm...

Looks like the wiki has something to say about the difference between the two types of events:
http://wiki.wxpython.org/CharacterCodesAndKeyboards

As for sizers, what do you want to know? I don't mind writing a tutorial of some sort if I knew what needed to be written.

Mike

python@bdurham.com wrote:

Mike,

As for sizers, what do you want to know? I don't mind writing a tutorial of some sort if I knew what needed to be written.
    
Apologies for jumping in on this thread but thought I comment on your
offer to Phillip.

If you're looking for ideas on sizer tutorials, how about a list of
common real-world layout patterns and the associated high level sizers
to use?

Example: Simple data collection form where icon and text are right
justified along the vertical axis of colons.

<icon> <title>
<separator>
<icon> text: <single line input control>
<icon> text: <multi-line text/list control that stretches vertically>
<separator>
<ok> <cancel>

Another idea would be to explain how to set min/max sizes for various
widgets so that a group of widgets is sized correctly. For example, if
the above example didn't have a vertically stretching control, how/where
would one place the code to prevent a user from vertically resizing the
dialog since vertically resizing doesn't make sense.

Malcolm

I'll look into this and see what I can come up with. Then I'll post it or put it in the wiki and let you guys give me suggestions for improvement.

Mike

I'll look into this and see what I can come up with. Then I'll post it
or put it in the wiki and let you guys give me suggestions for improvement.

Mike

This a fairly simple one generated by glade:
The mystery _1 for the frame, then a panel with
1 vertical and 2 horizontal

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3.Add(self.text_ctrl_1, 0, 0, 0)
        sizer_3.Add(self.text_ctrl_2, 0, 0, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_4.Add(self.text_ctrl_3, 0, 0, 0)
        sizer_4.Add(self.button_1, 0, 0, 0)
        sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
        self.panel_1.SetSizer(sizer_2)
        sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()

Careful reading reveals the hierarchy, but its not as intuitive
as Tkinter pack().
The panel is added to the top level, I guess I get that.
The two SetSizers(), and only two, I don't get.
I don't know what the Fit() and Layout() do because all
the tutorials are inconsistent and the docs are no help.
And some example have functions which apparently glade
doesn't use.

I'm not asking you to comment on the above. Just giving my
comments for your proposed tutorials.

If you look at the xml generated by wxglade, attached,
even though its not easy to read, the hierarchy is very obvious.

t.wxg (3.33 KB)

Phillip Watts wrote:

I'll look into this and see what I can come up with. Then I'll post it
or put it in the wiki and let you guys give me suggestions for improvement.

Mike

This a fairly simple one generated by glade:
The mystery _1 for the frame, then a panel with
1 vertical and 2 horizontal

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_3.Add(self.text_ctrl_1, 0, 0, 0)
        sizer_3.Add(self.text_ctrl_2, 0, 0, 0)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_4.Add(self.text_ctrl_3, 0, 0, 0)
        sizer_4.Add(self.button_1, 0, 0, 0)
        sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
        self.panel_1.SetSizer(sizer_2)
        sizer_1.Add(self.panel_1, 1, wx.EXPAND, 0)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
        self.Layout()

Careful reading reveals the hierarchy, but its not as intuitive
as Tkinter pack().
The panel is added to the top level, I guess I get that.
The two SetSizers(), and only two, I don't get.
I don't know what the Fit() and Layout() do because all
the tutorials are inconsistent and the docs are no help.
And some example have functions which apparently glade
doesn't use.

I'm not asking you to comment on the above. Just giving my
comments for your proposed tutorials.

If you look at the xml generated by wxglade, attached,
even though its not easy to read, the hierarchy is very obvious.

I'm going to comment regardless since I probably won't get to work on my tutorials until at least tomorrow or the weekend.

SetSizer tells the container widget which sizer to use. So the first one tells the panel to use sizer_2 and the second SetSizer tells the frame to use sizer_1.

Layout() forces a size event, which should (as I understand it) cause the sizers to calculate the best size of the widgets that they contain and refresh the screen appropriately. So, if you add or remove/hide a widget and then call Layout(), it will force the sizers to resize dynamically to fit the widgets.

Fit() on the other hand will use the minimum size of all the contained windows and resize appropriately. I usually don't use it unless I want the frame to be tiny.

And yes, sizers are complicated. I'm glad it's been abstracted as much as it has, but it's still hard to grasp. Just an FYI, but there's a SizerControls addon to help in laying out widgets at a higher level. You might take a look at that. Or XRC.

Mike

Phillip Watts wrote:

Ok, I figured out glade (stupid me)
and got the following code then added keydown.
Works fine on Kubuntu, prints 27 when I press escape.
Does nothing on WinXP.

Key events are only sent to the widget that has the focus. On Windows the panel will automatically pass the focus to the first child that can accept the focus (the first button in this case) if there is one. It's supposed to work that way on wxGTK too but I've noticed that sometimes it won't always do that when the application initially starts. If the button has the focus then binding the event handler to the panel will not result in any key events, this is by design. To learn more about event routing and how to decide where to do the binding:

http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind

···

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

Mike Driscoll wrote:

Layout() forces a size event, which should (as I understand it) cause the sizers to calculate the best size of the widgets that they contain and refresh the screen appropriately. So, if you add or remove/hide a widget and then call Layout(), it will force the sizers to resize dynamically to fit the widgets.

Fit() on the other hand will use the minimum size of all the contained windows and resize appropriately. I usually don't use it unless I want the frame to be tiny.

To put it another way, Layout causes the sizer to run its algorithm for calculating position and size of the managed items, and then to actually make those changes. If any of the changes cause an item to change size and if that item also has a sizer then that sizer's Layout will also be called.

Fit, on the other hand, will just query the sizer (recursively if appropriate) for the minimum size needed for the items managed by the sizer, and will then set the size of the window owning the sizer to that min size. If the size actually changes then there will be a size event which will then cause Layout to be called using the new size of the window.

···

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