I' m trying to see if it is possible to write a keyboard only wxpython program. All of the tutorials I'm finding on the web when run have no focused control at all. That's fine if you expect the user to click with a mouse.

I'll try to give a small example of what I want done.

I have small form with a panel on the left and another on the right.

Each panel has several buttons on it.

Using only a keyboard scroll through the buttons on the panel with focus using the arrow keys. Tab between the panels with the tab key.

I already know how to do hot keys for the entire form. I just need control over the visual part of the screen.

I was able to set the focus on btnFred with wx.CallAfter(btnFred.SetFocus).

The default behaviour lets me tab through controls on a single panel with the tab key.

Since I need to tab between panels I need to find a way to change the default navigation key to the arrow key for each panel.

Or use the arrow keys to change the panel focus.

This gets me a long way to my goal I think.

I worked out some code. This works more or less on one panel only. I think I could write a hot key routine to move focus from one panel to the other.

Tab and Shift-Tab work to navigate the buttons. Home, End, Page Up and Page down scroll the window.

For some reason the arrow key does not work. in the demos in ~/Documents/python/wxPython-2.8.4.0/demo/ the arrow keys are used as you would expect.

I have not figured out why and I'm not sure I care at the moment.

Here is the code: (I hope)

""" 
this code is modified from the following link:

http://www.blog.pythonlibrary.org/2009/08/29/wxpython-catching-key-and-char-events/

the site appears to be down at the moment - search google for:
Key Press Tutorial 2 "# Add a panel so it looks the correct on all platforms" will get a cached version

code is also based on my own previous work on the current problem

"""

import wx
import sys

class RedirectText:
    def __init__(self, statusbar):
        self.statusbar = statusbar

    def write(self,string):
        string = string.strip()
        if len(string) > 0:
            new_string = "You selected button " + string
            self.statusbar.SetStatusText(new_string)

def scale_bitmap(bitmap, width, height):
        image = wx.ImageFromBitmap(bitmap)
        image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
        result = wx.BitmapFromImage(image)
        return result

class TestForm(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "new start on picker", pos=(75,75), size=(870,550))

        self.statusbar = self.CreateStatusBar()
        # Add a panel so it looks the correct on all platforms
        panel = wx.ScrolledWindow(self, -1, size=(20,20), style=wx.TAB_TRAVERSAL)
        panel.SetScrollRate(10, 10)

        sizer = wx.FlexGridSizer(cols=3, hgap=10, vgap=10)
        panel.SetSizer(sizer)

        image_file = "blank.jpg"
        img1 = wx.Bitmap(image_file, wx.BITMAP_TYPE_ANY)
        #not needed here but useful for making buttons all the same size regardless of image size
        #img1=scale_bitmap(img1, 256, 192)

        Button_Array=[]
        count = 0

        for button_name in range(0, 23):
            # not a zero based array
            count += 1
            New_Button=wx.wx.BitmapButton(panel, count, img1, name=str(button_name))
            New_Button.Bind(wx.EVT_SET_FOCUS, self.OnFocus)
            Button_Array.append(New_Button)
            sizer.Add(New_Button, 0, wx.ALL, 4)

        wx.CallAfter(Button_Array[12].SetFocus)

    def onWidgetSetup(self, widget, event, handler, sizer):
        widget.Bind(event, handler)
        sizer.Add(widget, 0, wx.ALL, 5)
        return widget

    def OnFocus(self, event):
       # tab or shift tab has set focus on this bitmap button
       # eid was set in for loop that created the buttons
       eid = event.GetId()
       redirection = RedirectText(self.statusbar)
       sys.stdout = redirection
       print eid

# Run the program
if __name__ == "__main__":

    app = wx.PySimpleApp()
    frame = TestForm()
    frame.Show()
    app.MainLoop()
This article has been dead for over six months. Start a new discussion instead.