1

Sizers look a little complex at first, but they can make your component layouts a lot simpler. The wx.GridSizer() is particularly well suited for a bunch of similar widgets generated with a for loop. In this case I used the gridsizer for the buttons of a simple calculator. The buttons simply keep wrapping from left to right, down a notch then left to right again ...

# create a calulator button layout with wx.GridSizer()
# then add a few things to form a tiny wxPython calculator

import wx

class MyFrame(wx.Frame):
    """make a frame, inherits wx.Frame"""
    def __init__(self):
        # create a frame/window, no parent
        wx.Frame.__init__(self, None, wx.ID_ANY, 'wx_Calc',
            pos=(300, 150), size=(185, 160))
        self.SetBackgroundColour('green')
        # main sizer
        vsizer = wx.BoxSizer(wx.VERTICAL)

        self.edit = wx.TextCtrl(self, -1, value="", size=(165, 20))

        # follows layout of calculator keys
        self.btn_list = [
        '7', '8', '9', '/', 'c',
        '4', '5', '6', '*', 'bs',
        '1', '2', '3', '-', '**',
        '0', '.', '=', '+', 'neg'
        ]

        # wx.GridSizer(rows, cols, vgap, hgap)
        gsizer = wx.GridSizer(4, 5, 2, 2)

        self.btn = range(len(self.btn_list))
        for ix, b_label in enumerate(self.btn_list):
            # set up a consecutive unique id for each button
            id = 1000 + ix
            self.btn[ix] = wx.Button(self, id, label=b_label, size=(20, 20))
            # the gridsizer fills left to right one row at a time
            gsizer.Add(self.btn[ix], 0, wx.ALL|wx.EXPAND, border=2)
            self.btn[ix].Bind(wx.EVT_BUTTON, self.btnClick)

        # now add the whole thing to the main sizer and set it
        vsizer.Add(self.edit, 0, wx.EXPAND)
        vsizer.Add(gsizer, 0, wx.EXPAND)
        self.SetSizer(vsizer)

    def btnClick(self, event):
        # get the label of the button clicked
        label = self.btn_list[event.GetId() - 1000]
        e_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            '+', '-', '*', '/', '**', '.']
        if label in e_list:
            self.edit.SetValue(self.edit.GetValue() + label)
        elif label == 'neg':
            # negate, note eval() takes care of double negate
            self.edit.SetValue('-' + self.edit.GetValue())
        elif label == 'c':
            # clear
            self.edit.SetValue('')
        elif label == 'bs':
            # backspace
            self.edit.SetValue(self.edit.GetValue()[:-1])
        elif label == '=':
            str1 = self.edit.GetValue()
            # prevent folks from being nasty with eval()
            if not str1 or str1[0] not in '0123456789-+.':
                self.edit.SetValue('unrecognized operation')
                return
            while str1[0] == '0':
                # avoid leading zero (octal) error with eval()
                str1 = str1[1:]
            if '/' in str1 and '.' not in str1:
                # turn into floating point division
                str1 = str1 + '.0'
            try:
                self.edit.SetValue(str(eval(str1)))
            except ZeroDivisionError:
                self.edit.SetValue('division by zero error')
        else:
            self.edit.SetValue('unrecognized operation')


app = wx.App(0)
# create MyFrame instance and show the frame
MyFrame().Show()
app.MainLoop()
1

I was playing around with wxPython's slider widget and found a nice application for it:

# use slider inputs to calculate cost of petrol in the USA and Europe

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour("yellow")

        # create input widgets
        # label for slider1
        label_s1 = wx.StaticText(self, wx.ID_ANY, "US cents per US Gallon:")
        # can only use integer values!!!
        # initial value = 450, min value = 300, max value = 600
        self.slider1 = wx.Slider(self, wx.ID_ANY, 450, 300, 600, size=(320, 40),
            style=wx.SL_HORIZONTAL|wx.SL_LABELS)
        # label for slider2
        label_s2 = wx.StaticText(self, wx.ID_ANY, "Euro cents per Liter:")
        # initial value = 150, min value = 100, max value = 200
        self.slider2 = wx.Slider(self, wx.ID_ANY, 150, 100, 200, size=(320, 40),
            style=wx.SL_HORIZONTAL|wx.SL_LABELS)
        # label for slider3
        label_s3 = wx.StaticText(self, wx.ID_ANY, "US cents per Euro:")
        # initial value = 160, min value = 100, max value = 200
        self.slider3 = wx.Slider(self, wx.ID_ANY, 160, 100, 200, size=(320, 40),
            style=wx.SL_HORIZONTAL|wx.SL_LABELS)

        # bind all mouse slider marker drags to the same action
        self.Bind(wx.EVT_SLIDER, self.onAction)

        # create an output widget
        self.label = wx.StaticText(self, wx.ID_ANY, "")

        # use a vertical boxsizer for the widget placement
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        sizer_v.Add(label_s1, 0, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=10)
        sizer_v.Add(self.slider1, 0, flag=wx.ALL|wx.EXPAND, border=5)
        sizer_v.Add(label_s2, 0, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=10)
        sizer_v.Add(self.slider2, 0, flag=wx.ALL|wx.EXPAND, border=5)
        sizer_v.Add(label_s3, 0, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=10)
        sizer_v.Add(self.slider3, 0, flag=wx.ALL|wx.EXPAND, border=5)
        sizer_v.Add(self.label, 0, flag=wx.ALL|wx.EXPAND, border=10)
        self.SetSizer(sizer_v)

        # show opening result
        self.onAction(None)

    def onAction(self, event):
        """ some action code"""
        s = "The result ... \n\n"
        # gives integer cents values, convert to $ and Euro
        us_price = self.slider1.GetValue()/100.0
        euro_price = self.slider2.GetValue()/100.0
        euro_cost = self.slider3.GetValue()/100.0
        # 1 US gal = 3.785 liters
        s1 = "In the USA $%.2f/gal = $%.2f/liter = %.2f Euro/liter\n" % \
            (us_price, us_price/3.785, us_price/(3.785*euro_cost))
        s2 = "In Europe  $%.2f/gal = $%.2f/liter = %.2f Euro/liter" % \
            (euro_price*euro_cost*3.785, euro_price*euro_cost, euro_price)
        self.label.SetLabel(s + s1 + s2)


app = wx.App()
# create the MyFrame instance and then show the frame
MyFrame(None, 'The petrol sliders', (350, 300)).Show()
app.MainLoop()
1

A nice looking informative about-box is easy to achieve with the wx.AboutBox() widget. The example also touches on menu construction and wxPython's wordwrap feature:

# testing the fancy wx.AboutBox() widget

import wx
from wx.lib.wordwrap import wordwrap

class MyFrame(wx.Frame):
    """
    create a frame, with a menu, statusbar and 2 about dialogs
    """
    def __init__(self):
        # create a frame/window, no parent, default to wxID_ANY
        wx.Frame.__init__(self, None, wx.ID_ANY, "wx.AboutBox test",
            pos=(300, 150), size=(300, 350))
        self.SetBackgroundColour("brown")

        # create a status bar at the bottom
        self.CreateStatusBar()
        self.SetStatusText("Click on File")

        menu = wx.Menu()
        # the optional & allows you to use alt/a
        # the last string argument shows in the status bar on mouse_over
        menu_about = menu.Append(wx.ID_ANY, "&About", "Ho-hum about box")
        menu_about2 = menu.Append(wx.ID_ANY, "About&2", "Fancy about box")
        menu.AppendSeparator()
        # the optional & allows you to use alt/x
        menu_exit = menu.Append(wx.ID_ANY, "E&xit", "Quit the program")

        # create a menu bar at the top
        menuBar = wx.MenuBar()
        # the & allows you to use alt/f
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)

        # bind the menu events to an action/function/method
        self.Bind(wx.EVT_MENU, self.onMenuAbout, menu_about)
        self.Bind(wx.EVT_MENU, self.onMenuAbout2, menu_about2)
        self.Bind(wx.EVT_MENU, self.onMenuExit, menu_exit)

    def onMenuAbout(self, event):
        """a somewhat ho-hum about box"""
        dlg = wx.MessageDialog(self,
            "a simple application using wxFrame, wxMenu\n"
            "a statusbar, and this about message.",
            "About", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onMenuAbout2(self, event):
        """use the much fancier wx.AboutBox()"""
        # first fill the info object
        info = wx.AboutDialogInfo()
        info.Name = "Bratwurst7"
        info.Version = "v.1.7.4"
        info.Copyright = "(C) copyfight 2008"
        info.Description = wordwrap(
            "The Bratwurst7 program is a software program that "
            "makes you desire a freshly grilled bratwurst and "
            "a good German beer right now!  Teaching programmers "
            "everywhere to be aware of those hidden immediate "
            "inner desires!",
            300, wx.ClientDC(self))
        info.WebSite = ("http://en.wikipedia.org/wiki/Bratwurst",
            "Bratwurst7 home")
        info.Developers = ["Carl Arm", "Carol Bein", "Candy Kisser"]
        info.License = "Wish upon a star!"
        # now call wx.AboutBox with this info object
        wx.AboutBox(info)

    def onMenuExit(self, event):
        self.Close(True)


app = wx.App()
# create the MyFrame class instance, then show the frame
MyFrame().Show()
app.MainLoop()
1

Some light wxPython stuff. The first example shows you how to bring in your own icon in the title of a frame:

# set the icon of a wx.Frame()

import wx

app = wx.App(0)

frame = wx.Frame(None, wx.ID_ANY, title='Set A New Icon')
# pick an icon image file you have ...
frame.SetIcon(wx.Icon('py.ico', wx.BITMAP_TYPE_ICO))
frame.Center()
frame.Show()
app.MainLoop()

The second example uses the wx.EVT_SIZE event to respond to changes in the size of the frame:

# use the wx.EVT_SIZE event to show the frame size
# the title itself may take up 34 pixels of the height

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent):
        # use default size and position
        wx.Frame.__init__(self, parent, wx.ID_ANY)
        self.SetBackgroundColour("yellow")
        wx.StaticText(self, wx.ID_ANY, "change the size of the frame", (5,5))

        # respond to changes in the size of the frame
        self.Bind(wx.EVT_SIZE, self.onSize)

    def onSize(self, event):
        """display the current frame size in the title"""
        self.SetTitle(str(event.GetSize()))  # eg. (400, 489)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None).Show()
app.MainLoop()
1

Some heavier wxPython stuff. I was playing around with the wx.ListCtrl() widget, and it took me quite a while to find a way to get a hold of the selected row. Here is a short example of the solution:

# exploring wxPython's
# wx.ListCtrl(parent, id, pos, size, style)
# a fancier list box with a lot of mix-in options
# some of the styles =
# wxLC_REPORT  report mode
# wxLC_HRULES  draws horizontal rules between rows in report mode
# wxLC_VRULES  draws vertical rules between columns in report mode.

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, data):
        # use default size and position
        wx.Frame.__init__(self, parent, wx.ID_ANY,
            'Test the wx.ListCtrl()',
            size=(400, 220))
        self.SetBackgroundColour("yellow")
        # make data available to the instance
        self.data = data

        # create the list control
        self.lc = wx.ListCtrl(self, wx.ID_ANY, size=(-1, 120),
             style=wx.LC_REPORT|wx.SUNKEN_BORDER|wx.LC_HRULES)
        # select an item (left mouse click on it) and bind to an action
        self.lc.Bind(wx.EVT_LIST_ITEM_SELECTED,self.onAction)

        self.loadList()

        # create an output widget
        self.label = wx.StaticText(self, wx.ID_ANY, "Select a name")

        # use a vertical boxsizer for the widget placement
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        sizer_v.Add(self.lc, 1, flag=wx.ALL|wx.EXPAND, border=10)
        sizer_v.Add(self.label, 0, flag=wx.ALL|wx.EXPAND, border=10)
        self.SetSizer(sizer_v)

    def loadList(self):
        # first the columns with header titles
        self.lc.InsertColumn(0,"Name")
        self.lc.SetColumnWidth(0, 200)
        self.lc.InsertColumn(1,"Age",wx.LIST_FORMAT_RIGHT)
        self.lc.InsertColumn(2,"Weight",wx.LIST_FORMAT_RIGHT)

        # now each data row
        for key, val in self.data.items():
            # set max_rows, change if need be
            max_rows = 1000
            # also sets/updates row index starting at 0
            index = self.lc.InsertStringItem(max_rows, val[0])
            self.lc.SetStringItem(index, 1, val[1])
            self.lc.SetStringItem(index, 2, val[2])
            # needed by GetItemData()
            self.lc.SetItemData(index, key)

    def onAction(self, event):
        """ some action code"""
        # -1 --> get the first item that matches the specified flags
        # wx.LIST_NEXT_ALL  search for subsequent item by index
        # wx.LIST_STATE_SELECTED  get the selected item
        ix_selected = self.lc.GetNextItem(item=-1,
            geometry=wx.LIST_NEXT_ALL,
            state=wx.LIST_STATE_SELECTED)
        # get the value of the key in dictionary self.data
        data_value = self.data[self.lc.GetItemData(ix_selected)]
        # pick the name (first item in the value tuple)
        name = ' --> ' + data_value[0]
        self.label.SetLabel(str(data_value) + name)


# data to load the listctrl in the form of a dictionary
# the header is ('Name', 'Age', 'Weight')
data = {
1 : ('Heidi Kalumpa', '36', '127'),
2 : ('Frank Maruco', '27', '234'),
3 : ('Larry Pestraus', '19', '315'),
4 : ('Serge Romanowski', '59', '147'),
5 : ('Carolus Arm', '94', '102'),
6 : ('Michel Sargnagel', '21', '175')
}

app = wx.App(0)
# create a MyFrame instance and then show the frame
MyFrame(None, data).Show()
app.MainLoop()
2

This might be the simplest way to display an image from a file using the wxPython GUI toolkit:

# simplest way to show an image from a file with wxPython

import wx

app = wx.App(0)
frame = wx.Frame(None, -1, "Show an image file")

# pick an image file you have in the working folder
# (can be a .jpg, .png, ,gif, .bmp image file)
image_file = 'clouds.jpg'
# create an internal image
image = wx.Bitmap(image_file)
# show the image as static bitmap
wx.StaticBitmap(frame, -1, image)

frame.Show()
app.MainLoop()

What the heck, lets make it even simpler:

import wx

app = wx.App(0)
frame = wx.Frame(None, -1, "Show an image file")
wx.StaticBitmap(frame, -1, wx.Bitmap('clouds.jpg'))
frame.Show()
app.MainLoop()
1

In a previous example we have learned how to create a wxPython canvas and draw shapes on it. If you want to save your artistic creation to one of the common image files, you have to create the canvas on top of a blank bitmap. Here is an example ...

# create a canvas on top of a blank bitmap
# this allows to save any canvas drawings
# created to a standard image file

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent=None, id=-1, title=None):
        wx.Frame.__init__(self, parent, id, title)
        self.statbmp = wx.StaticBitmap(self)
        self.draw_image()
        self.save_image()

    def draw_image(self):
        # select the width and height of the blank bitmap
        w, h = 340, 340
        # create the blank bitmap as a draw background
        draw_bmp = wx.EmptyBitmap(w, h)
        # create the canvas on top of the draw_bmp
        canvas_dc = wx.MemoryDC(draw_bmp)
        # fill the canvas white
        canvas_dc.SetBrush(wx.Brush('white'))
        canvas_dc.Clear()

        # draw a bunch of circles ...
        # pen colour
        canvas_dc.SetPen(wx.Pen('red', 1))
        # fill colour
        canvas_dc.SetBrush(wx.Brush('yellow'))
        for x in range(10, 180, 10):
            y = x
            r = x
            canvas_dc.DrawCircle(x, y, r)

        # now put the canvas drawing into a bitmap to display it
        # remember the canvas is on top of the draw_bmp
        self.statbmp.SetBitmap(draw_bmp)

    def save_image(self):
        """save the drawing"""
        finished_image = self.statbmp.GetBitmap()
        #finished_image.SaveFile("mydrawing.png", wx.BITMAP_TYPE_PNG)
        finished_image.SaveFile("mydrawing.jpg", wx.BITMAP_TYPE_JPEG)


app = wx.App(0)
MyFrame(title='draw and save').Show()
app.MainLoop()
1

Just a modification of the above scheme. This time we don't use a blank image, but an image we have and, let's say, write some fancy text on the image and then save it ...

# create a canvas on top of an image
# then draw some text on the image
# and save the finishd drawing

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent=None, id=-1, title=None):
        wx.Frame.__init__(self, parent, id, title)
        self.statbmp = wx.StaticBitmap(self)
        self.draw_image()
        self.save_image()

    def draw_image(self):
        # make sure you have the image in the working
        # directory or give the full path, load the image
        image = wx.Bitmap("roses.jpg")
        canvas_dc = wx.MemoryDC(image)
        # the image is now the background for the canvas
        canvas_dc.DrawBitmap(image, 0, 0)

        face = u'Comic Sans MS'
        font = wx.Font(22, wx.SWISS, wx.NORMAL, wx.NORMAL, False, face)
        canvas_dc.SetFont(font)
        canvas_dc.SetTextForeground('red')
        canvas_dc.DrawText("Sweet Roses!", x=80, y=10)

        # display the image drawing
        self.statbmp.SetBitmap(image)

    def save_image(self):
        """save the drawing"""
        finished_image = self.statbmp.GetBitmap()
        #finished_image.SaveFile("myimage.png", wx.BITMAP_TYPE_PNG)
        finished_image.SaveFile("myimage.jpg", wx.BITMAP_TYPE_JPEG)


app = wx.App(0)
MyFrame(title='draw on an image and save it').Show()
app.MainLoop()
Attachments roses.jpg 30.47 KB
1

In case you would ever need to fool with the wx.Frame itself. The wx.Frame default style is wx.DEFAULT_FRAME_STYLE and is normally defined as:
wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.CAPTION|
wx.CLOSE_BOX|wx.CLIP_CHILDREN
so remove wx.MAXIMIZE_BOX to disable it ...

# a wx.Frame with the max button/box disabled

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize,
            style=wx.MINIMIZE_BOX|wx.RESIZE_BORDER|wx.SYSTEM_MENU|
                  wx.CAPTION|wx.CLOSE_BOX|wx.CLIP_CHILDREN)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'Max box disabled', (400, 300)).Show()
app.MainLoop()

Here is an example of a frame without a border or title bar. Note that you have to supply your own exit button ...

# wx.Frame with no title bar

import wx

def exit(event):
    frame.Close(True)

app = wx.App(0)
# create a window, no-parent, -1 is default ID, style with no titlebar
frame = wx.Frame(parent=None, id=-1, pos=(50,100), size=(300,200), 
    style=wx.MINIMIZE_BOX)
frame.SetBackgroundColour('green')

# provide exit for a frame without titlebar
quit = wx.Button(frame, id=-1, label='Exit', pos=(0,175))
quit.Bind(wx.EVT_BUTTON, exit)

# show the window
frame.Show(True)

# start the event loop
app.MainLoop()
1

Show one of those ever popular animated gif images Zoe style ...

# use wx.animate.GIFAnimationCtrl() to show an animated gif

import wx
import wx.animate     # ..\wx\animate.py

app = wx.App(0)
frame = wx.Frame(None, wx.ID_ANY, "Show an animated gif",
    size=(250, 150))
frame.SetBackgroundColour("white")

# pick an animated GIF file you have in the working directory
# (give it the full path if located in another directory)
ag_fname = 'AG_Dog.gif'
# create the instance with this file name
ag = wx.animate.GIFAnimationCtrl(frame, wx.ID_ANY, ag_fname)
# clear the background
ag.GetPlayer().UseBackgroundColour(True)
# continuously loop through the frames of the gif file (default)
ag.Play()

frame.Show()
app.MainLoop()
Attachments AG_Dog.gif 6.58 KB
0

Just a quick look at wx.Timer(), wxPython's own timer action. There are two options a one_shot type and a continuous restart type action. Let's take a look at each ...

# a wx.Timer() one_shot example (delays for a set time) ...

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour('red')

        self.timer = wx.Timer(self)
        # interval = 2000ms (2 seconds)
        # default is oneShot=False, timer keeps restarting
        self.timer.Start(2000, oneShot=True)
        # bind EVT_TIMER event to self.onTimer() action
        self.Bind(wx.EVT_TIMER, self.onTimer)

    def onTimer(self, event):
        # establish new color
        self.SetBackgroundColour('green')
        # clear old color, set to new color
        self.ClearBackground()


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'change colour from red to green after 2 seconds',
    (640, 180)).Show()
app.MainLoop()

... and ...

# a wx.Timer() continuous restart example ...

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour('red')
        self.red_flag = True

        self.timer = wx.Timer(self)
        # interval = 2000ms (2 seconds)
        # default is oneShot=False, timer keeps restarting
        # stop the timer action with self.timer.Stop()
        self.timer.Start(2000, oneShot=False)
        # bind EVT_TIMER event to self.onTimer() action
        self.Bind(wx.EVT_TIMER, self.onTimer)

    def onTimer(self, event):
        if self.red_flag:
            # establish new color
            self.SetBackgroundColour('green')
            self.red_flag = False
        else:
            self.SetBackgroundColour('red')
            self.red_flag = True
        # clear old color, set to new color
        self.ClearBackground()


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'flip colour from red to green every 2 seconds',
    (640, 180)).Show()
app.MainLoop()
1

This short code sample shows how to add an exit confirm to your wxPython program, from either a menu exit or the title bar exit:

# confirm exit of a wxPython program

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)

        # create a status bar at the bottom
        self.CreateStatusBar()
        self.SetStatusText("Click on File")

        menu = wx.Menu()
        # just one item to test exit confirm
        # the optional & allows you to use alt/x
        # the last string argument shows in the status bar on mouse_over
        menu_exit = menu.Append(wx.ID_ANY, "E&xit", "Exit the program")

        # create a menu bar at the top
        menuBar = wx.MenuBar()
        # the & allows you to use alt/f
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)

        # bind the menu events to an action
        self.Bind(wx.EVT_MENU, self.onMenuExit, menu_exit)
        # responds to exit symbol x on frame title bar
        self.Bind(wx.EVT_CLOSE, self.onCloseWindow)

    def onMenuExit(self, event):
        # triggers wx.EVT_CLOSE event and hence onCloseWindow()
        self.Close(True)

    def onCloseWindow(self, event):
        # dialog to verify exit
        dlg = wx.MessageDialog(self, "Want to exit?", "Exit",
            wx.YES_NO|wx.ICON_QUESTION)
        if dlg.ShowModal() == wx.ID_YES:
            self.Destroy()
        dlg.Destroy()


app = wx.App(0)
# create the MyFrame instance and then show the frame
MyFrame(None, 'Confirm exit', (400, 300)).Show()
app.MainLoop()

Zoe

0

The wx.TextCtrl() widget is used to enter single line text, password text, or multiline text. It can also be used to display multline text as a scrolled output widget, editable (default) or readonly. Under Windows you can also output text in the richedit format. Here is a short example ...

# testing wxPython's
# wx.TextCtrl(parent, id, value, pos, size, style)
# a widget used for written text data input or output

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour("yellow")

        s = "Enter your name below:"
        edit_label = wx.StaticText(self, wx.ID_ANY, s)
        self.edit = wx.TextCtrl(self, wx.ID_ANY, value="",
            size=(200, 20))
        # respond to enter key when focus is on edit1
        self.edit.Bind(wx.EVT_TEXT_ENTER, self.onAction)

        s = "Enter your password below:"
        pw_label = wx.StaticText(self, wx.ID_ANY, s)
        self.pw = wx.TextCtrl(self, wx.ID_ANY, value="",
            size=(200, 20), style=wx.TE_PASSWORD)
        self.pw.SetBackgroundColour("green")
        # respond to enter key when focus is on edit1
        self.pw.Bind(wx.EVT_TEXT_ENTER, self.onAction)

        # create another text control for scrolled multiline output
        self.text_out = wx.TextCtrl(self, wx.ID_ANY, value="",
            size=(200, 70),
            style=wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY)

        sizer_v = wx.BoxSizer(wx.VERTICAL)
        sizer_v.Add(edit_label, 0, flag=wx.LEFT|wx.TOP|wx.EXPAND, border=10)
        sizer_v.Add(self.edit, 0, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND,
            border=10)
        sizer_v.Add(pw_label, 0, flag=wx.LEFT|wx.TOP|wx.EXPAND, border=10)
        sizer_v.Add(self.pw, 0, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND,
            border=10)
        sizer_v.Add(self.text_out, 0, flag=wx.ALL|wx.EXPAND, border=10)

        self.edit.SetFocus()

        self.SetSizer(sizer_v)

    def onAction(self, event):
        """ some action code"""
        name = self.edit.GetValue()
        s1 = "You entered the name: " + name + '\n'
        pw = self.pw.GetValue()
        if pw:
            s2 = "Your entered password: " + pw + '\n'
            s3 = "..... done!"
        else:
            s2 = s3 = ""
            self.pw.SetFocus()
        # text output to first, second and third line
        # play with this to your satisfaction
        self.text_out.ChangeValue(s1)
        self.text_out.AppendText(s2)
        self.text_out.AppendText(s3)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'testing wx.TextCtrl() part1', (300, 250)).Show()
app.MainLoop()
0

Just a few experiments with wxPython's label widget. It goes under the name of wx.StaticText ...

# experiment with wxPython's
# wx.StaticText(parent, id, label, pos, size, style)
# used for labels to display information or results
"""
style:
wx.ALIGN_LEFT  Align the text to the left (default)
wx.ALIGN_RIGHT  Align the text to the right
wx.ALIGN_CENTRE  Center the text (horizontally)
wx.ST_NO_AUTORESIZE Cancel the default of autosizing label to fit text
"""

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)

        # note: label will try to autosize to fit text
        text = "What time does the two o'clock bus leave?"
        label1 = wx.StaticText(self, wx.ID_ANY, text)

        # set background and text colour of label1
        label1.SetBackgroundColour("yellow")
        label1.SetForegroundColour("red")

        # note: text that does not fit on one line will wrap
        label2 = wx.StaticText(self, wx.ID_ANY, text)

        # set background and text colour label2
        label2.SetBackgroundColour("blue")
        label2.SetForegroundColour("yellow")

        # set the font of label2
        # type: wxDEFAULT, wxDECORATIVE, wxROMAN, wxSCRIPT, wxSWISS, wxMODERN
        # slant: wxNORMAL, wxSLANT or wxITALIC
        # weight: wxNORMAL, wxLIGHT or wxBOLD
        label2.SetFont(wx.Font(22, wx.MODERN, wx.SLANT, wx.BOLD))

        label3 = wx.StaticText(self, wx.ID_ANY, "", style=wx.ALIGN_CENTRE)
        # set the background colour
        # text colour defaults to black
        label3.SetBackgroundColour("white")
        # set text for label3 to label2's text
        # does not copy colours or font
        label3.SetLabel(label2.GetLabel())

        label4 = wx.StaticText(self, wx.ID_ANY, text, style=wx.ALIGN_RIGHT)
        # set the foreground/text colour
        # background defaults to system setting
        label4.SetForegroundColour("white")

        # use a box sizer to position the labels vertically
        sizer_v = wx.BoxSizer(wx.VERTICAL)
        # label1 and label2 proportions are set to fill space ratio 1:2
        # also keeps ratio on frame stretch
        sizer_v.Add(label1, proportion=1, flag=wx.EXPAND)
        sizer_v.Add(label2, proportion=2, flag=wx.EXPAND)
        sizer_v.Add(label3, proportion=0, flag=wx.EXPAND)
        sizer_v.Add(label4, proportion=0, flag=wx.EXPAND)
        self.SetSizer(sizer_v)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'test wx.StaticText()', (400, 300)).Show()
app.MainLoop()
1

Shows you how to drag one of wxPython's widgets with the mouse pointer:

# use mouse to drag the wx.Panel() widget
# wx.Panel(parent, id, pos, size, style)

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        # needed for better control
        panel = wx.Panel(self)
        panel.SetBackgroundColour("green")

        self.drag_panel = wx.Panel(panel, size=(230, 100))
        self.drag_panel.SetBackgroundColour("yellow")
        text1 = "point the mouse on the yellow panel \n"
        text2 = "press the left mouse button and drag it"
        wx.StaticText(panel, wx.ID_ANY,
            text1+text2, pos=(10, 150))

        # bind mouse events to some actions
        self.drag_panel.Bind(wx.EVT_LEFT_DOWN, self.on_left_down)
        self.drag_panel.Bind(wx.EVT_LEFT_UP, self.on_left_up)
        self.drag_panel.Bind(wx.EVT_MOTION, self.on_motion)

    def on_left_down(self, event):
        self.drag_panel.CaptureMouse()
        x, y = self.drag_panel.ClientToScreen(event.GetPosition())
        originx, originy = self.drag_panel.GetPosition()
        dx = x - originx
        dy = y - originy
        self.mp_delta = ((dx, dy))

    def on_left_up(self, event):
        if self.drag_panel.HasCapture():
            self.drag_panel.ReleaseMouse()

    def on_motion(self, event):
        if event.Dragging() and event.LeftIsDown():
            x, y = self.drag_panel.ClientToScreen(event.GetPosition())
            move_xy = (x - self.mp_delta[0], y - self.mp_delta[1])
            self.drag_panel.Move(move_xy)


app = wx.App()
# create the MyFrame instance and show the frame
MyFrame(None, 'drag the panel with the mouse', (400, 300)).Show()
app.MainLoop()
1

The information a statusbar can display can come handy:

# set up a customized statusbar with three display fields
# a statusbar is typically an information line at the bottom of a window

import wx
import time

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        # fill the top part with a panel
        panel = wx.Panel(self, wx.ID_ANY, style=wx.SUNKEN_BORDER)
        panel.SetBackgroundColour("blue")

        self.sb = wx.StatusBar(self, wx.ID_ANY)
        # set the status bar with three fields
        self.sb.SetFieldsCount(3)
        # set an absolute status field width in pixels
        # (negative indicates a variable width field)
        self.sb.SetStatusWidths([-1, -1, -1])
        self.SetStatusBar(self.sb)
        # put some text into field 0 (most left field)
        self.sb.SetStatusText("some text in field 0", 0)
        self.sb.SetStatusText("some text in field 1", 1)

        # use a timer to drive a date/time string in field 3
        # here the most right field of the statusbar
        self.timer = wx.PyTimer(self.onUpdate)
        # update every 1000 milliseconds
        self.timer.Start(1000)
        self.onUpdate()

    def onUpdate(self):
        t = time.localtime(time.time())
        st = time.strftime("%d-%b-%Y   %I:%M:%S", t)
        # put date/time display string into field 2
        self.sb.SetStatusText(st, 2)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'test the wx.StatusBar', (460, 300)).Show()
app.MainLoop()
0

The wx.media.MediaCtrl() is wxPython's answer to playing a fair number of sound and video file formats. Here is an example of how to use this versatile widget ...

# experiment with wxPython's
# wx.media.MediaCtrl(parent, id, pos, size, style, szBackend)
# the backend is usually figured out by the control itself
# wx.MEDIABACKEND_DIRECTSHOW   Windows
# wx.MEDIABACKEND_QUICKTIME    Mac OS X
# wx.MEDIABACKEND_GSTREAMER    Linux

import wx
import wx.media
import os

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour("green")

        # check if the media control is implemented
        try:
            self.mc = wx.media.MediaCtrl(self, style=wx.SIMPLE_BORDER)
        except NotImplementedError:
            self.Destroy()
            raise

        loadButton = wx.Button(self, wx.ID_ANY, "Load File")
        self.Bind(wx.EVT_BUTTON, self.onLoadFile, loadButton)

        playButton = wx.Button(self, wx.ID_ANY, "Play")
        playButton.SetToolTip(wx.ToolTip("load a file first"))
        self.Bind(wx.EVT_BUTTON, self.onPlay, playButton)

        pauseButton = wx.Button(self, wx.ID_ANY, "Pause")
        pauseButton.SetToolTip(wx.ToolTip("press Play to resume"))
        self.Bind(wx.EVT_BUTTON, self.onPause, pauseButton)

        stopButton = wx.Button(self, wx.ID_ANY, "Stop")
        stopButton.SetToolTip(wx.ToolTip("also resets to start"))
        self.Bind(wx.EVT_BUTTON, self.onStop, stopButton)

        self.slider = wx.Slider(self, wx.ID_ANY, 1000000, 0, 1000000,
            size=(380, -1),
            style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
        self.slider.Bind(wx.EVT_SLIDER, self.onSeek)

        ext = "  load  .mp3  .mpg  .mid  .wav  .au  or  .avi files"
        self.st_info = wx.StaticText(self, wx.ID_ANY, ext, size=(300,-1))

        # use a gridbagsizer to layout widgets
        sizer = wx.GridBagSizer(vgap=5, hgap=5)
        # pos=(row, column)
        # span=(rowspan, columnspan)
        sizer.Add(loadButton, pos=(1,1))
        sizer.Add(self.st_info, pos=(1,2), span=(1,2))
        sizer.Add(self.slider, pos=(2,1), span=(2,3))
        sizer.Add(playButton, pos=(4,1))
        sizer.Add(pauseButton, pos=(4,2))
        sizer.Add(stopButton, pos=(4,3))
        # for .avi .mpg video files use this lower grid area
        sizer.Add(self.mc, pos=(5,1), span=(7,3))
        self.SetSizer(sizer)

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onTimer)
        # update every 100 milliseconds
        self.timer.Start(100)

    def onLoadFile(self, evt):
        mask = "MP3 (.mp3)|*.mp3|MPG (.mpg)|*.mpg|All (.*)|*.*"
        dlg = wx.FileDialog(self, message="Choose a media file",
                            defaultDir=os.getcwd(), defaultFile="",
                            wildcard=mask, style=wx.OPEN|wx.CHANGE_DIR)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.doLoadFile(path)
        dlg.Destroy()

    def doLoadFile(self, path):
        if not self.mc.Load(path):
            wx.MessageBox("Unable to load %s: Unsupported format?" % path,
            "ERROR", wx.ICON_ERROR|wx.OK)
        else:
            folder, self.filename = os.path.split(path)
            self.st_info.SetLabel("  %s" % self.filename)
            self.mc.SetInitialSize()
            self.GetSizer().Layout()
            # set the slider range min to max
            self.slider.SetRange(0, self.mc.Length())
            self.mc.Play()

    def onPlay(self, evt):
        self.slider.SetRange(0, self.mc.Length())
        s1 = "  %s" % self.filename
        s2 = "  size: %s ms" % self.mc.Length()
        s3 = "  (%d seconds)" % (self.mc.Length()/1000)
        self.st_info.SetLabel(s1+s2+s3)
        self.mc.SetInitialSize()
        self.GetSizer().Layout()
        self.mc.Play()

    def onPause(self, evt):
        self.mc.Pause()

    def onStop(self, evt):
        self.mc.Stop()

    def onSeek(self, evt):
        """allows dragging the slider pointer to this position"""
        offset = self.slider.GetValue()
        self.mc.Seek(offset)

    def onTimer(self, evt):
        """moves the slider pointer"""
        offset = self.mc.Tell()
        self.slider.SetValue(offset)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'Play Audio and Video', (420, 400)).Show()
app.MainLoop()
0

If you need to enter a date, wxPython has a special widget for such a thing. It's quite versatile and safeguards against the entry of inappropriate dates. This little code example lets you find out how many shopping days you have till xmas, or how many days old you are amongst other things. Read the displayed text and play with the wx.DatePickerCtrl() to get familiar with its capabilities ...

# test wxPython's
# wx.DatePickerCtrl(parent, id, dt, pos, size, style)
# dt = initial date (today by default)

import wx
import datetime as dt

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, mysize):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle, size=mysize)
        self.SetBackgroundColour("yellow")

        s1 = "You can click on the month, day or year portion \n"
        s2 = "of the displayed date and use the keyboard up down \n"
        s3 = "arrows to change the highlighted part. \n"
        s4 = "   Or simply type the change in to replace the high- \n"
        s5 = "lighted part (will not acccept impossible dates). \n"
        s6 = "   Or you can click on the right side drop marker to \n"
        s7 = "show a monthly calendar and change the date that way."
        info = s1+s2+s3+s4+s5+s6+s7
        info_label = wx.StaticText(self, wx.ID_ANY, info, pos=(20, 10))

        # create input widgets
        self.datepick = wx.DatePickerCtrl(self, wx.ID_ANY,
            pos=(20, 110),
            style=wx.DP_DROPDOWN|wx.DP_SHOWCENTURY)

        # bind mouse click to an action
        self.datepick.Bind(wx.EVT_DATE_CHANGED, self.onAction)

        # create an output widget
        self.label = wx.StaticText(self, wx.ID_ANY,
            "", pos=(20, 140))

    def onAction(self, event):
        """ some action code"""
        # returned object is type wx._misc.DateTime
        selected = self.datepick.GetValue()
        month = selected.Month + 1
        day = selected.Day
        year = selected.Year
        # you could do this ...
        # date_str = "%02d/%02d/%4d" % (month, day, year)
        # ... or do some date math with module datetime
        date = dt.date(year, month, day)
        date_str = date.strftime("%m/%d/%Y")
        today = dt.date.today()
        age = date - today
        s = "  (%d days from today)" % age.days
        self.label.SetLabel("Date selected = " + date_str + s)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'testing wx.DatePickerCtrl()', (320, 210)).Show()
app.MainLoop()
0

This is an example how to create a wx.Frame() that fills the entire display screen:

# wx.DisplaySize() gives (width, height) tuple of your display screen

import wx

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, pos=(0, 0),
            size=wx.DisplaySize())
        self.SetBackgroundColour('blue')
        s = "Frame has full display size of %d x %d" % wx.DisplaySize()
        self.SetTitle(s)


app = wx.App(0)
# instantiate class MyFrame and show
MyFrame().Show(True)
app.MainLoop()
0

Here is a way to fill your full display screen with a wx.Frame() widget, that does not show a border nor a title bar. You have to give it an exit button of your own. To be mildly playful, lets cycle through the wxPython colour data base at random:

# a full screen-display wx.Frame without border and title bar
# wxPython's wx.lib.colourdb contains about 630 different
# colour names to cycle through at random

import wx
import random
import wx.lib.colourdb as cdb

class MyFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, wx.ID_ANY)
        # create a full screen display frame, no title bar
        self.ShowFullScreen(True, style=wx.FULLSCREEN_ALL)

        w, h = wx.DisplaySize()
        # create a panel to easily refresh colours
        self.panel = wx.Panel(self, wx.ID_ANY, size=(w, h))
        # supply an exit button in the upper right corner
        self.exitbutton = wx.Button(self.panel, wx.ID_ANY, label='X',
            pos=(w - 25, 5), size=(20, 15))
        self.exitbutton.Bind(wx.EVT_BUTTON, self.exitbuttonClick)

        cdb.updateColourDB()
        # create a list of all the colours in the colour data base
        self.colours = cdb.getColourList()

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onTimer, self.timer)
        # change colour every second (1000ms)
        self.timer.Start(1000)

    def onTimer(self, event):
        bg = random.choice(self.colours)
        #print bg  # test
        self.panel.SetBackgroundColour(bg)
        self.panel.Refresh()

    def exitbuttonClick(self, event):
        self.Close(True)


app = wx.App(0)
MyFrame(None).Show(True)
app.MainLoop()
0

You can use several classes in your wxPython program. This example shows you how to cross reference a widget (or variable) from one class to another:

# experiments with wxPython, reference across class instances
# from one panel class to another panel class

import wx
import time

class MakePanel1(wx.Panel):
    def __init__(self, Parent, *args, **kwargs):
        wx.Panel.__init__(self, Parent, *args, **kwargs)
        self.SetBackgroundColour('yellow')

        self.label = wx.StaticText(self, -1, " panel1 label ")

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox.Add(self.label, 0, wx.ALL, 20)
        self.SetSizer(self.hbox)


class MakePanel2(wx.Panel):
    def __init__(self, Parent, *args, **kwargs):
        wx.Panel.__init__(self, Parent, *args, **kwargs)
        self.SetBackgroundColour('green')

        self.button = wx.Button(self, label=" panel2 button ")
        self.button.Bind(wx.EVT_BUTTON, self.buttonClick )

        self.hbox = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox.Add(self.button, 0, wx.ALL, 20)
        self.SetSizer(self.hbox)

    def buttonClick(self, event=None):
        # reference panel1's label via frame.panel1
        s1 = "panel1 label ..... \n"
        s2 = "the time is " + time.strftime("%H:%M:%S", time.localtime())
        frame.panel1.label.SetLabel(s1 + s2)


class MakeFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.panel1 = MakePanel1(self)
        self.panel2 = MakePanel2(self)

        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(self.panel1,1,wx.EXPAND);
        vbox.Add(self.panel2,1,wx.EXPAND);
        self.SetSizer(vbox)
        # select a frame size so everything fits
        self.Fit()


app = wx.App(0)
# instance frame is needed for later reference
frame = MakeFrame(None)
frame.Show(True)
app.MainLoop()
0

If you like to draw things, here is an example how to draw some basic shapes on wxPython's canvas:

# draw a few well known shapes on a wx.PaintDC() canvas

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent=None, title=None):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title)
        self.panel = wx.Panel(self, size=(350, 450))
        # this sets up the painting canvas
        self.panel.Bind(wx.EVT_PAINT, self.on_paint)
        # set frame size to fit panel
        self.Fit()

    def on_paint(self, event):
        # establish the painting canvas
        dc = wx.PaintDC(self.panel)

        # draw some lines using the given pen specs
        # from points (x1, y1) to (x2, y2)
        x1 = 50
        y1 = 20
        x2 = 300
        y2 = 20
        # first pen colour is red (thickness = 5)
        dc.SetPen(wx.Pen('red', 5))
        dc.DrawLine(x1, y1, x2, y2)
        # second pen colour is white
        dc.SetPen(wx.Pen('white', 5))
        dc.DrawLine(x1, y1+5, x2, y2+5)
        # third pen colour is blue
        dc.SetPen(wx.Pen('blue', 5))
        dc.DrawLine(x1, y1+10, x2, y2+10)

        # draw a red rounded-rectangle
        # upper left corner coordinates x, y and width, height
        # make the pen colour red (thickness = 1)
        # default brush (fill) is white
        dc.SetPen(wx.Pen('red', 1))
        x = 50
        y = 50
        w = 100
        h = 100
        rect = wx.Rect(x, y, w, h)
        # corners are quarter-circles using a radius of 8
        dc.DrawRoundedRectangleRect(rect, 8)

        # draw a red circle with yellow fill
        # center coordinates x, y and radius r
        dc.SetBrush(wx.Brush('yellow'))
        x = 250
        y = 100
        r = 50
        dc.DrawCircle(x, y, r)

        # draw an arc from point x1, y1 to point x2, y2 counter
        # clockwise along a circle with center xc, yc
        # use previous pen and brush settings
        xc = 100
        yc = 220
        x1 = xc
        y1 = 170
        x2 = xc
        y2 = 270
        dc.DrawArc(x1, y1, x2, y2, xc, yc)

        # draw a polygon connecting the (x, y) points in a list
        # will also connect first and last points
        point_list = [(10, 10), (120, 20), (100, 80), (50, 100)]
        dc.DrawPolygon(point_list, xoffset=180, yoffset=170)

        # draw 2 gradient filled rectangles
        # upper left corner coordinates x, y and width, height
        x = 50
        y = 300
        w = 100
        h = 100
        dc.DrawRectangle(x, y, w, h)
        dc.GradientFillLinear((x, y, w, h), 'red', 'blue')
        # just a little different fill
        dc.DrawRectangle(x+150, y, w, h)
        dc.GradientFillConcentric((x+150, y, w, h), 'red', 'blue', (50, 50))


# test it ...
app = wx.App(0)
MyFrame(title='put some shapes on a canvas').Show()
app.MainLoop()
0

I am surprised nobody has brought up the old wx.ListBox() widget yet. Well, here it is, a fun thing to experiment with (stole the name_list from vegaseat):

# load, sort and clear a wxPython
# wx.ListBox(parent, id, pos, size, choices, style)

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, name_list):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle)
        self.SetBackgroundColour("green")
        self.name_list = list(name_list)

        self.listbox = wx.ListBox(self, wx.ID_ANY, choices=[])
        self.listbox.Bind(wx.EVT_LISTBOX, self.listboxClick)

        # create action widgets
        self.load_button = wx.Button(self, wx.ID_ANY, "load ListBox")
        self.clear_button = wx.Button(self, wx.ID_ANY, "clear ListBox")
        self.sort_button = wx.Button(self, wx.ID_ANY, "sort ListBox")
        # bind mouse event to an action
        self.load_button.Bind(wx.EVT_BUTTON, self.load_buttonClick)
        self.clear_button.Bind(wx.EVT_BUTTON, self.clear_buttonClick)
        self.sort_button.Bind(wx.EVT_BUTTON, self.sort_buttonClick)
        # create an output widget
        self.label = wx.StaticText(self, wx.ID_ANY, "")

        sizer = wx.GridBagSizer(vgap=5, hgap=5)
        # pos=(row, column)  span=(rowspan, columnspan)
        # wx.ALL puts the specified border on all sides
        sizer.Add(self.load_button, pos=(0, 0), flag=wx.ALL, border=5)
        # listbox spans 6 rows and 2 columns
        sizer.Add(self.listbox, pos=(1, 0), span=(6, 2),
            flag=wx.ALL|wx.EXPAND, border=5)
        sizer.Add(self.clear_button, pos=(7, 1), flag=wx.ALL, border=5)
        sizer.Add(self.sort_button, pos=(7, 0), flag=wx.ALL, border=5)
        sizer.Add(self.label, pos=(8, 0), flag=wx.ALL, border=5)
        self.SetSizer(sizer)

        # size the frame so all the widgets fit
        self.Fit()

    def load_buttonClick(self, event):
        """load the name list into the bistbox"""
        # use self.listbox.Set(name_list) or ...
        for name in self.name_list:
            self.listbox.Append(name)

    def clear_buttonClick(self, event):
        """clear all items from the listbox"""
        self.listbox.Clear()
        self.label.SetLabel("")

    def sort_buttonClick(self, event):
        """sort the items in the listbox"""
        # GetItems() is new in wxPython2.8
        # puts the listbox items into a list
        name_list = self.listbox.GetItems()
        name_list.sort()
        # Set() clears and reloads the listbox
        self.listbox.Set(name_list)

    def listboxClick(self, event):
        """display the selected ListBox item"""
        selected_item = self.listbox.GetStringSelection()
        s = "You selected " + selected_item
        self.label.SetLabel(s)


name_list = [
"Andreas",
"Erich",
"Udo",
"Jens",
"Bjorn",
"Heidrun",
"Klaus",
"Ulla",
"Volger",
"Helmut",
"Freja",
"Larry",
"Harry"
]

app = wx.App(0)
# create the MyFrame instance and then show the frame
MyFrame(None, 'listbox test', name_list).Show()
app.MainLoop()
0

Thanks Snee for your nice wx.ListBox() example. There is a real high tech listbox in the gizmo section of wxPython. With this one you can edit a selected item including cut, copy, paste portions of it. You can delete, or move selected items up or down in the list. Additionally you can insert, write or paste a new item into the list. You simply have to test it out to get a feel of it ...

# wxPython's amazing wx.gizmos.EditableListBox()
# you can edit (also cut, copy, paste), delete, move selected
# items up or down, and insert (also paste) a new item
# tested with Python25 and wxPython28  vegaseat  07aug2008

import wx
import  wx.gizmos

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle, name_list):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle)
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.panel.SetBackgroundColour("green")
        self.name_list = list(name_list)

        self.elistbox = wx.gizmos.EditableListBox(self.panel, wx.ID_ANY,
            label="List of Names")
        # get the actual control portion of the EditableListBox
        self.actual_listctrl = self.elistbox.GetListCtrl()
        # binds to any newly focused/selected item
        self.actual_listctrl.Bind(wx.EVT_LIST_ITEM_FOCUSED,
            self.listctrlClick)

        # create action widgets
        load_button = wx.Button(self.panel, wx.ID_ANY, "load ListBox")
        clear_button = wx.Button(self.panel, wx.ID_ANY, "clear ListBox")
        sort_button = wx.Button(self.panel, wx.ID_ANY, "sort ListBox")
        # bind mouse click event to an action
        load_button.Bind(wx.EVT_BUTTON, self.load_buttonClick)
        clear_button.Bind(wx.EVT_BUTTON, self.clear_buttonClick)
        sort_button.Bind(wx.EVT_BUTTON, self.sort_buttonClick)
        # create an output widget
        self.label = wx.StaticText(self.panel, wx.ID_ANY, "")

        sizer = wx.GridBagSizer(vgap=5, hgap=5)
        # pos=(row, column)  span=(rowspan, columnspan)
        # wx.ALL puts the specified border on all sides
        sizer.Add(load_button, pos=(0, 0), flag=wx.ALL, border=5)
        # listbox spans 6 rows and 2 columns
        sizer.Add(self.elistbox, pos=(1, 0), span=(6, 2),
            flag=wx.ALL|wx.EXPAND, border=5)
        sizer.Add(clear_button, pos=(7, 1), flag=wx.ALL, border=5)
        sizer.Add(sort_button, pos=(7, 0), flag=wx.ALL, border=5)
        sizer.Add(self.label, pos=(8, 0), flag=wx.ALL, border=5)
        # set the sizer and fit all its widgets
        self.panel.SetSizerAndFit(sizer)

        # size the frame so all its widgets fit inside
        self.Fit()

    def load_buttonClick(self, event):
        """load the name list into the bistbox"""
        self.elistbox.SetStrings(name_list)

    def clear_buttonClick(self, event):
        """clear all items from the elistbox"""
        self.elistbox.SetStrings([])
        self.label.SetLabel("")

    def sort_buttonClick(self, event):
        """sort the items in the elistbox"""
        # GetStrings() puts the elistbox items into a list
        name_list = self.elistbox.GetStrings()
        name_list.sort()
        # SetStrings() clears and reloads the elistbox
        self.elistbox.SetStrings(name_list)

    def listctrlClick(self, event):
        """display the selected listctrl item of the elistbox"""
        for n in range(self.actual_listctrl.GetItemCount()):
            state = wx.LIST_STATE_SELECTED
            if self.actual_listctrl.GetItemState(n, state):
                selected_item = self.actual_listctrl.GetItemText(n)
        s = "You selected " + selected_item
        self.label.SetLabel(s)


name_list = [
"Erich",
"Udo",
"Jens",
"Bjorn",
"Heidrun",
"Klaus",
"Zoe",
"Ulla",
"Volger",
"Helmut",
"Lisa",
"Larry",
"Andreas",
"Harry"
]

app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'elistbox test', name_list).Show()
app.MainLoop()
0

The wxPython GUI toolkit has the Open Graphics Library (OGL) integrated in its later versions. This avoids the often cumbersome download and installation of OGL. Here is an example how you can create a number of shapes and drag them around the canvas ...

# the Open Graphics Library (OGL) is now part of wxPython
# also test use of a custom class derived from ogl.PolygonShape
# tested with Python25 and wxPython28  vegaseat  08aug2008

import wx
import wx.lib.ogl as ogl

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__( self, None, wx.ID_ANY,
            "wx.lib.ogl  Demo2", size=(400,300))

        canvas = ogl.ShapeCanvas(self)
        canvas.SetBackgroundColour("yellow")

        diagram = ogl.Diagram()
        # marry the two ...
        canvas.SetDiagram(diagram)
        diagram.SetCanvas(canvas)

        # draw some standard shapes ...
        # (check how creation order affects overlap)
        circle = ogl.CircleShape(80.0) # radius
        circle.SetX(125.0)  # center x
        circle.SetY(125.0)
        # use preset pen and brush types
        # border ...
        circle.SetPen(wx.RED_PEN)
        # fill ...
        circle.SetBrush(wx.GREEN_BRUSH)
        canvas.AddShape(circle)

        rectangle = ogl.RectangleShape(100, 80) # (w, h)
        rectangle.SetX(55.0)  # center x
        rectangle.SetY(45.0)  # center y
        # use wx.Pen and wx.Brush for more options
        # wx.Pen(colour, width=1, style=wx.SOLID)
        # also wx.DOT, wx.DOT_DASH, wx.TRANSPARENT --> no border
        rectangle.SetPen(wx.Pen("blue", 2))
        # wxBrush(colour, style=wx.SOLID)
        # also wx.CROSS_HATCH, wx.CROSSDIAG_HATCH, wx.TRANSPARENT
        rectangle.SetBrush(wx.Brush("blue", wx.CROSSDIAG_HATCH))
        canvas.AddShape(rectangle)

        text = ogl.TextShape(250, 30)  # (w, h)
        text.SetX(180)  # center x
        text.SetY(240)
        text.AddText("you can drag the shapes or the text")
        canvas.AddShape(text)

        # if you have an image file
        # you can also create a shape with the image
        image_file = 'victory.jpg'
        bmp = wx.Bitmap(image_file)
        picture = ogl.BitmapShape()
        picture.SetBitmap(bmp)
        picture.SetX(330)  # center x
        picture.SetY(160)
        canvas.AddShape(picture)

        # use the custom class ...
        circle = DiamondShape(130, 100) # (w, h)
        circle.SetX(225.0)  # center x
        circle.SetY(70.0)
        circle.SetPen(wx.BLACK_PEN)
        # use no fill ...
        circle.SetBrush(wx.TRANSPARENT_BRUSH)
        canvas.AddShape(circle)

        # all the shapes are in, so show them
        diagram.ShowAll(True)

        # use a sizer
        sizer = wx.BoxSizer(wx.VERTICAL)
        # canvas will grow as frame is stretched
        sizer.Add(canvas, 1, wx.GROW)
        self.SetSizer(sizer)


class DiamondShape(ogl.PolygonShape):
    """create a diamond shaped object using a polygon"""
    def __init__(self, w=60.0, h=60.0):
        ogl.PolygonShape.__init__(self)
        points = [(0, -h/2.0), (w/2.0, 0), (0,h/2.0), (-w/2.0, 0)]
        self.Create(points)


app = wx.App(0)
ogl.OGLInitialize()
MyFrame().Show()
app.MainLoop()
Attachments Victory.jpg 4.33 KB
0

To allow just one instance of your wxPython program to run, you need to modify your application class slightly ...

# allow only one instance of a wxPython program to run

import wx

class MyFrame(wx.Frame):
    def __init__(self,parent, mytitle):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle,
            size=(300, 90))
        self.SetBackgroundColour("red")
        self.Centre()
        # more of your program code here ...


class SingleApp(wx.App):
    def OnInit(self):
        name = "SingleApp-%s" % (wx.GetUserId())
        self.instance = wx.SingleInstanceChecker(name)
        # create a title
        mytitle = name
        if self.instance.IsAnotherRunning():
            message = "Another instance of %s is running" % mytitle
            wx.MessageBox(message, "Error")
            return False
        MyFrame(None, mytitle).Show()
        return True


app = SingleApp()
app.MainLoop()
0

Radio buttons give you a fixed input, one choice at a time. If you have a series of radio buttons it's easiest to group them together with a wx.RadioBox(). The code example shows you how to do this, and also is a good example for the wx.BoxSizer() layout manager ...

# test the wx.RadioBox() widget
# wx.RadioBox(parent, id, label, pos, size, choices, majorDimension, style)
# combines a wx.StaticBox() with a wx.RadioButton()
# only one radiobutton can be selected at a time in the radiobox

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent, mytitle):
        wx.Frame.__init__(self, parent, wx.ID_ANY, mytitle)
        self.SetBackgroundColour("yellow")

        # create input widgets
        self.options1 = ['now', 'later', 'much later', 'never']
        self.radiobox1 = wx.RadioBox(self, wx.ID_ANY,
            " Select one option ",
            choices=self.options1, style=wx.VERTICAL)
        # set radio button 1 as selected (first button is 0)
        self.radiobox1.SetSelection(1)
        # bind mouse click to an action
        self.radiobox1.Bind(wx.EVT_RADIOBOX, self.onAction)

        self.options2 = ['blue', 'red', 'yellow', 'orange', 'green',
            'purple', 'navy blue', 'black', 'gray']
        # this radio box has 3 columns
        self.radiobox2 = wx.RadioBox(self, wx.ID_ANY,
            label=" What color would you like? ",
            choices=self.options2,
            majorDimension=3,
            style=wx.RA_SPECIFY_COLS)
        self.radiobox2.SetSelection(0)
        self.radiobox2.Bind(wx.EVT_RADIOBOX, self.onAction)

        # create output widgets
        self.label1 = wx.StaticText(self, wx.ID_ANY, "" )
        self.label2 = wx.StaticText(self, wx.ID_ANY, "" )

        # use box sizers to layout widgets
        # the two vertical sizers nest in the horizontal sizer
        sizer_v1 = wx.BoxSizer(wx.VERTICAL)
        sizer_v2 = wx.BoxSizer(wx.VERTICAL)
        sizer_h = wx.BoxSizer(wx.HORIZONTAL)
        # add the widgets to the corresponding vertical sizer
        sizer_v1.Add(self.radiobox1, 0, flag=wx.ALL, border=10)
        sizer_v1.Add(self.label1, 0, wx.ALL, 10)
        sizer_v2.Add(self.radiobox2, 0, wx.ALL, 10)
        # add a spacer (optional) ...
        sizer_v2.Add((0, 0), 0, wx.ALL, 10)
        sizer_v2.Add(self.label2, 0, wx.ALL, 10)
        # put the 2 vertical sizers into the horizontal sizer
        sizer_h.Add(sizer_v1, 0)
        sizer_h.Add(sizer_v2, 0)
        # it's the horizontal sizer you have to set
        # also fit the frame snuggly around the whole thing
        self.SetSizerAndFit(sizer_h)

        # show present selection
        self.onAction(None)

    def onAction(self, event):
        """show the selected choice"""
        index1 = self.radiobox1.GetSelection()
        s = "Choice = " + self.options1[index1]
        self.label1.SetLabel(s)
        # dito for radio box #2
        index2 = self.radiobox2.GetSelection()
        s = "Choice = " + self.options2[index2]
        self.label2.SetLabel(s)



app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame(None, 'testing wx.RadioBox()').Show()
app.MainLoop()
0

You can also create a radio-button like behaviour in a menu using radio-items. Take a look at this menu example ...

# experimenting with wxPython's wx.Menu()

import wx

# some needed unique ids for the radio item menu
ID_RED = 1001
ID_GREEN = 1002
ID_BLUE = 1003
ID_YELLOW = 1004
ID_WHITE = 1005

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY,
            'Click on a menubar item', size=(300, 350))

        # create a status bar at the bottom
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")

        self.createMenu()

    def createMenu(self):
        """creates all the menu items"""
        filemenu = wx.Menu()
        filemenu_save = filemenu.Append(wx.ID_ANY, "&Save",
            "Save something to file (just a dummy)")
        filemenu.AppendSeparator()
        filemenu_exit = filemenu.Append(wx.ID_ANY, "E&xit",
            "Quit the program")

        optionmenu = wx.Menu()
        self.optionmenu = optionmenu
        optionmenu.AppendRadioItem(ID_RED, "red", "")
        optionmenu.AppendRadioItem(ID_GREEN, "green", "")
        optionmenu.AppendRadioItem(ID_BLUE, "blue", "")
        optionmenu.AppendRadioItem(ID_YELLOW, "yellow", "")
        optionmenu.AppendRadioItem(ID_WHITE, "white", "")

        helpmenu = wx.Menu()
        # the optional & allows you to use alt/a
        # the last string argument shows in the status bar
        # on mouse_over
        helpmenu_about = helpmenu.Append(wx.ID_ANY, "&About",
            "About message")

        # create a menu bar at the top for the menu titles
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu, "&File")
        menuBar.Append(optionmenu, "&Option")
        menuBar.Append(helpmenu, "&Help")
        self.SetMenuBar(menuBar)

        # bind the menu events to an action method
        self.Bind(wx.EVT_MENU, self.onMenuAbout, helpmenu_about)
        self.Bind(wx.EVT_MENU, self.onMenuSave, filemenu_save)
        self.Bind(wx.EVT_MENU, self.onMenuExit, filemenu_exit)
        """
        self.Bind(wx.EVT_MENU, self.onMenuColor, id=ID_RED)
        self.Bind(wx.EVT_MENU, self.onMenuColor, id=ID_GREEN)
        self.Bind(wx.EVT_MENU, self.onMenuColor, id=ID_BLUE)
        self.Bind(wx.EVT_MENU, self.onMenuColor, id=ID_YELLOW)
        self.Bind(wx.EVT_MENU, self.onMenuColor, id=ID_WHITE)
        """
        # better give id range ...
        self.Bind(wx.EVT_MENU_RANGE, self.onMenuColor, id=ID_RED,
            id2=ID_WHITE)

        # set the preselected colour
        self.onMenuColor(self)

    def onMenuAbout(self, event):
        dlg = wx.MessageDialog(self,
            "a simple application using wxFrame, wxMenu\n"
            "a statusbar, and this about message.",
            "About", wx.OK|wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onMenuSave(self, event):
        self.SetStatusText("Not implemented yet!")

    def onMenuColor(self, event):
        for item in self.optionmenu.GetMenuItems():
            #print item, item.IsChecked(), item.GetLabel()  # test
            if item.IsChecked():
                # establish new color
                self.SetBackgroundColour(item.GetLabel())
                # now clear old color and set to new color
                self.ClearBackground()

    def onMenuExit(self, event):
        # exit via wx.EVT_CLOSE event
        self.Close(True)

app = wx.App(0)
# create class instance
MyFrame().Show()
# start the event loop
app.MainLoop()
0

The wx.grid.Grid() widget lets you present tabular data in an organized fashion, very similar to the popular spreadsheet programs. Here is a short example of it's use:

# a practical use of wxPython's wx.grid.Grid() widget
# load the grid via a list of lists
# bind cell select (mouse left click)

import wx
import wx.grid

class MyGrid(wx.grid.Grid):
    def __init__(self, parent, data_list):
        wx.grid.Grid.__init__(self, parent, wx.ID_ANY)
        self.parent = parent

        # set the rows and columns the grid needs
        self.rows = len(data_list)
        self.cols = len(data_list[0])
        self.CreateGrid(self.rows, self.cols)

        # set some column widths (default is 80) different
        self.SetColSize(0, 180)
        self.SetColSize(3, 100)
        self.SetRowLabelSize(40)  # sets leading row width

        # set column lable titles at the top
        for ix, title in enumerate(data_list[0]):
            self.SetColLabelValue(ix, title)

        # create reusable attribute objects
        self.attr = wx.grid.GridCellAttr()
        self.attr.SetTextColour('black')
        self.attr.SetBackgroundColour('yellow')
        #self.attr.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))

        # select the cell with a mouse left click
        self.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.onCellLeftClick)

        self.loadCells(data_list)

    def onCellLeftClick(self, event):
        row = event.GetRow()
        col = event.GetCol()
        self.parent.SetTitle("row=%d  col=%d  value=%s" %
            (row, col, self.GetCellValue(row, col)))
        # move the grid's cursor to frame the cell
        self.SetGridCursor(row, col)

    def loadCells(self, data_list):
        # note that title row is taken
        for row in range(1, self.rows):
            # set cell attributes for the whole row
            self.SetRowAttr(row-1, self.attr)
            for col in range(self.cols):
                value = data_list[row][col]
                self.SetCellValue(row-1, col, value)
                self.SetReadOnly(row-1, col, True)
                if col > 0:
                    self.SetCellAlignment(row-1, col,
                        wx.ALIGN_RIGHT, wx.ALIGN_CENTRE)

        self.SetCellTextColour(row, 0, 'red')
        self.SetCellBackgroundColour(row, 0, 'white')
        self.SetCellFont(row, 0, wx.Font(8, wx.ROMAN, wx.ITALIC, wx.NORMAL))
        honor = "University of Detroit Chemistry Department"
        self.SetCellValue(row, 0, honor)


# build the data_list, raw_data string is from a csv file ...
raw_data = """\
Solvent Name,  BP (deg C),  MP (deg C), Density (g/ml)
ACETIC ACID,117.9,16.7,1.049
ACETIC ANHYDRIDE,140.1,-73.1,1.087
ACETONE,56.3,-94.7,0.791
ACETONITRILE,81.6,-43.8,0.786
ANISOLE,154.2,-37,0.995
BENZYL ALCOHOL,205.4,-15.3,1.045
BENZYL BENZOATE,323.5,19.4,1.112
BUTYL ALCOHOL NORMAL,117.7,-88.6,0.81
BUTYL ALCOHOL SEC,99.6,-114.7,0.805
BUTYL ALCOHOL TERTIARY,82.2,25.5,0.786
CHLOROBENZENE,131.7,-45.6,1.111
CYCLOHEXANE,80.7,6.6,0.779
CYCLOHEXANOL,161.1,25.1,0.971
CYCLOHEXANONE,155.2,-47,0.947
DICHLOROETHANE 1 2,83.5,-35.7,1.246
DICHLOROMETHANE,39.8,-95.1,1.325
DIETHYL ETHER,34.5,-116.2,0.715
DIMETHYLACETAMIDE,166.1,-20,0.937
DIMETHYLFORMAMIDE,153.3,-60.4,0.944
DIMETHYLSULFOXIDE,189.4,18.5,1.102
DIOXANE 1 4,101.3,11.8,1.034
DIPHENYL ETHER,258.3,26.9,1.066
ETHYL ACETATE,77.1,-83.9,0.902
ETHYL ALCOHOL,78.3,-114.1,0.789
ETHYL DIGLYME,188.2,-45,0.906
ETHYLENE CARBONATE,248.3,36.4,1.321
ETHYLENE GLYCOL,197.3,-13.2,1.114
FORMIC ACID,100.6,8.3,1.22
HEPTANE,98.4,-90.6,0.684
HEXAMETHYL PHOSPHORAMIDE,233.2,7.2,1.027
HEXANE,68.7,-95.3,0.659
ISO OCTANE,99.2,-107.4,0.692
ISOPROPYL ACETATE,88.6,-73.4,0.872
ISOPROPYL ALCOHOL,82.3,-88,0.785
METHYL ALCOHOL,64.7,-97.7,0.791
METHYL ETHYLKETONE,79.6,-86.7,0.805
METHYL ISOBUTYL KETONE,116.5,-84,0.798
METHYL T-BUTYL ETHER,55.5,-10,0.74
METHYLPYRROLIDINONE N,203.2,-23.5,1.027
MORPHOLINE,128.9,-3.1,1
NITROBENZENE,210.8,5.7,1.208
NITROMETHANE,101.2,-28.5,1.131
PENTANE,36.1, -129.7,0.626
PHENOL,181.8,40.9,1.066
PROPANENITRILE,97.1,-92.8,0.782
PROPIONIC ACID,141.1,-20.7,0.993
PROPIONITRILE,97.4,-92.8,0.782
PROPYLENE GLYCOL,187.6,-60.1,1.04
PYRIDINE,115.4,-41.6,0.978
SULFOLANE,287.3,28.5,1.262
TETRAHYDROFURAN,66.2,-108.5,0.887
TOLUENE,110.6,-94.9,0.867
TRIETHYL PHOSPHATE,215.4,-56.4,1.072
TRIETHYLAMINE,89.5,-114.7,0.726
TRIFLUOROACETIC ACID,71.8,-15.3,1.489
WATER,100,0,1
XYLENES,139.1,-47.8,0.86"""

data_list = []
for line in raw_data.split('\n'):
    line_list = line.split(',')
    data_list.append(line_list)


app = wx.App(0)
# create a window/frame, no parent, use a default ID
title = "test the wx.grid.Grid()"
frame = wx.Frame(None, wx.ID_ANY, title, size=(520, 360))
# create the class instance
mygrid = MyGrid(frame, data_list)
frame.Show(True)
app.MainLoop()
1

Very nice contribution of a spreadsheet like grid Snee!

If you ever have to present a lot of widgets on a limited space, the wx.NoteBook() widget is a great solution. In this case, I used it for a distance, area and volume conversion program. A start at least, generic enough so more conversions can easily be added. Just tab your way through the pages ...

# experiments with wxPython's wx.Notebook() widget
# converting distance, area and volume units
# tested with Python25 and wxPython28 by vegaseat 11aug2008

import wx

class MyNotebook(wx.Frame):
    def __init__(self, parent, title, distD, areaD, volD):
        wx.Frame.__init__(self, parent, wx.ID_ANY, title,
            size=(460, 360))

        # style=wx.NB_TOP is default
        # could use style=wx.NB_BOTTOM
        nb = wx.Notebook(self, wx.ID_ANY)
        # MyPage(parent, conversion dictionary, preselected choice)
        self.page1 = MyPage(nb, distD, 3)
        self.page2 = MyPage(nb, areaD, 2)
        self.page3 = MyPage(nb, volD, 0)
        nb.AddPage(self.page1, "Distance Conversion")
        nb.AddPage(self.page2, "Area Conversion")
        nb.AddPage(self.page3, "Volume Conversion")
        # start with page1 active
        self.page1.SetFocus()

class MyPage(wx.Panel):
    """
    each panel instance creates the notbook page content
    from the given conversion dictionary convD
    """
    def __init__(self, parent, convD, preselect):
        wx.Panel.__init__(self, parent, wx.ID_ANY)
        oatmeal3 = '#FCFFE1'
        self.SetBackgroundColour(oatmeal3)

        self.convD = convD

        # create list of possible units
        self.options = convD.keys()

        self.radiobox1 = wx.RadioBox(self, wx.ID_ANY,
            "Select a unit to convert from",
            choices=self.options, style=wx.VERTICAL)
        # set radio button 1 as selected (first button is 0)
        self.radiobox1.SetSelection(preselect)
        # bind mouse click to an action
        self.radiobox1.Bind(wx.EVT_RADIOBOX, self.onAction)

        self.radiobox2 = wx.RadioBox(self, wx.ID_ANY,
            "Select a unit to convert to  ",
            choices=self.options, style=wx.VERTICAL)
        # set radio button 1 as selected (first button is 0)
        self.radiobox2.SetSelection(preselect)
        # bind mouse click to an action
        self.radiobox2.Bind(wx.EVT_RADIOBOX, self.onAction)

        # additional widgets
        self.label1 = wx.StaticText(self, wx.ID_ANY, "" )
        self.label2 = wx.StaticText(self, wx.ID_ANY, "" )

        self.edit1 = wx.TextCtrl(self, wx.ID_ANY, value="1.0",
            size=(150, 20))
        # respond to enter key when focus is on edit1
        self.edit1.Bind(wx.EVT_TEXT_ENTER, self.onAction)
        self.edit2 = wx.TextCtrl(self, wx.ID_ANY, value="",
            size=(150, 20))

        self.button = wx.Button(self, wx.ID_ANY, label='Convert')
        self.button.Bind(wx.EVT_BUTTON, self.onAction)

        # use box sizers to layout the widgets
        # nest the 3 vertical sizers in the horizontal sizer later
        sizer_v1 = wx.BoxSizer(wx.VERTICAL)
        sizer_v2 = wx.BoxSizer(wx.VERTICAL)
        sizer_v3 = wx.BoxSizer(wx.VERTICAL)
        sizer_h = wx.BoxSizer(wx.HORIZONTAL)
        # add the widgets to the corresponding vertical sizer
        sizer_v1.Add(self.radiobox1, 0, flag=wx.ALL, border=10)
        sizer_v1.Add(self.label1, 0, wx.LEFT|wx.RIGHT|wx.TOP, 10)
        sizer_v1.Add(self.edit1, 0, wx.LEFT|wx.RIGHT, 10)
        # add a spacer to position the button lower ...
        sizer_v2.Add((0, 225), 0, wx.ALL, 10)
        sizer_v2.Add(self.button, 0, wx.ALL, 10)
        sizer_v3.Add(self.radiobox2, 0, wx.ALL, 10)
        sizer_v3.Add(self.label2, 0, wx.LEFT|wx.RIGHT|wx.TOP, 10)
        sizer_v3.Add(self.edit2, 0, wx.LEFT|wx.RIGHT, 10)
        # put the 3 vertical sizers into the horizontal sizer
        sizer_h.Add(sizer_v1, 0)
        sizer_h.Add(sizer_v2, 0)
        sizer_h.Add(sizer_v3, 0)
        # it's the horizontal sizer you have to set
        self.SetSizer(sizer_h)

        # show present selection
        self.onAction(None)

    def onAction(self, event):
        """show the selected choice"""
        index1 = self.radiobox1.GetSelection()
        unit1 = self.options[index1]
        #print unit1  # test
        s = "Enter a value (%s):" % unit1
        self.label1.SetLabel(s)
        # dito for radio box #2
        index2 = self.radiobox2.GetSelection()
        unit2 = self.options[index2]
        #print unit2  # test
        s = "Result (%s):" % unit2
        self.label2.SetLabel(s)

        value = float(self.edit1.GetValue())
        factor1 = self.convD[unit1]
        factor2 = self.convD[unit2]
        result = factor2 * value/factor1
        self.edit2.ChangeValue(str(result))


# these are the conversion dictionaries ...
# (note that units won't appear in that order)
distD ={}
# all scale factors are relative to the first unit below
distD['meter'] = 1.0
distD['micron'] = 1000000.0
distD['millimeter'] = 1000.0
distD['centimeter'] = 100.0
distD['kilometer'] = 0.001
distD['inch'] = 100.0/2.54
distD['foot'] = 100.0/30.48
distD['yard'] = 100.0/91.44
distD['mile'] = 0.001/1.609344
distD['rod'] = 1.0/5.029

areaD = {}
# all scale factors are relative to the first unit below
areaD['sq meter'] = 1.0
areaD['sq millimeter'] = 1000000.0
areaD['sq centimeter'] = 10000.0
areaD['sq kilometer']  = 0.000001
areaD['hectare'] = 0.0001
areaD['sq inch'] = 1550.003
areaD['sq foot'] = 10.76391
areaD['sq yard'] = 1.19599
areaD['acre'] = 0.0002471054
areaD['sq mile'] = 0.0000003861022

volD = {}
# all scale factors are relative to the first unit below
volD['cubic meter'] = 1.0
volD['microliter'] = 1000000000.0
volD['milliliter'] = 1000000.0
volD['liter'] = 1000.0
volD['pint(US)'] = 2113.376
volD['quart(US)'] = 1056.688
volD['gallon(US)'] = 264.172
volD['cubic inch'] = 61023.74
volD['cubic foot'] = 35.31467
volD['cubic yard'] = 1.307951


app = wx.App(1)
MyNotebook(None, "testing wx.Notebook()", distD, areaD, volD).Show()
app.MainLoop()
Votes + Comments
Thank you for the tutorials.
This question has already been answered. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.