Building a basic GUI application step-by-step in Python with Tkinter and wxPython



Il existe une version française de ce document: There is a french translation of this document:Il existe une version française de ce document: http://sebsauvage.net/python/gui/index_fr.html

step by step

Mastering most common GUI techniques (widgets layout, GUI constraints, event binding, etc.)

Understanding each and every single method and parameter used here.

method and parameter used here. See two different major GUI toolkit and learn their differences.

Serve as a basis for building your own GUI applications.

building a GUI application class,

creating widgets,

laying them in containers,

attaching and handling events,

manipulating widgets values,

etc.

Do the same thing with Tkinter (the standard GUI toolkit provided with Python) and wxPython (an advanced, portable, popular GUI toolkit).

(the standard GUI toolkit provided with Python) and (an advanced, portable, popular GUI toolkit). Program it the right way

way Use plain english

Explicit is better than implicit ;-)

Tkinter

Tcl/tk

wxPython

wxWidgets

Table of contents

Our project





A text field ("Enter text here")

A button ("Click me !")

A blue label ("Hello !")

When ENTER is pressed in the text field, or the button is clicked, the blue label will display the text which was entered.

We want to constraint window resize so that window can only be resized horizontally.

If the window is resized, the text field and blue label will expand horizontally, like this:





Tkinter source code is in this color, on the left .



wxPython equivalent code is in this color, on the right .



like this

STEP 1 : Import the GUI toolkit module

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program."





Tkinter

wxPython

STEP 2 : Create a class

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):



Tkinter

Tkinter.Tk

wxPython

wx.Frame

STEP 3 : The constructor

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)



simpleapp_tk

Tkinter.Tk

Tkinter.Tk.__init__()

simpleapp_wx

wx.Frame

wx.Frame.__init__()

parent

wx.Frame

id

title

STEP 4 : Keep track of our parent

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

STEP 5 : Initialize our GUI

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

pass



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

self.Show(True)

creates all the GUI elements

logic

initialize()

pass

wxPython

self.Show(True)

STEP 6 : Creation of main

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

pass



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

main

Tkinter

app=simpleapp_tk()

None

app.title()

wxPyhon

app=wx.App()

frame=simpleapp_wx()

None

-1

'my application'

STEP 7 : Loop it !

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

pass



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

.mainloop()

loop indefinitely

event-driven programming

At this point, you can run both programs: They work ! At this point, you can run both programs: They work !

STEP 8 : Layout manager

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()

self.SetSizerAndFit(sizer)

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

layout managers

grid

Tkinter

self.grid()

wxPython

sizer=wx.GridBagSizer()

self.SetSizerAndFit(sizer)

STEP 9 : Adding the text entry

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)



self.SetSizerAndFit(sizer)

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

first create the widget

the widget and add it to a layout manager

create the widget

Tkinter

Entry

self.entry=Tkinter.Entry()

wxPython

TextCtrl

self.entry=wx.TextCtrl()

self

parent

TextCtrl

-1

u'Enter text here.'

self.entry=...

add them to the layout manager.

Tkinter

.grid()

column=0, row=0

sticky='EW'





wxPython

.Add()

self.entry

(0,0)

(1,1)

wx.EXPAND

At this point, you can run both programs: They work !

Hey ! The text field does not resize when I resize the window ! You lied !

column or cell

layout manager

STEP 10 : Adding the button

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')



button = Tkinter.Button(self,text=u"Click me !")

button.grid(column=1,row=0)



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))



self.SetSizerAndFit(sizer)

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

At this point, you can run both programs: They work !

STEP 11 : Adding the label

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')



button = Tkinter.Button(self,text=u"Click me !")

button.grid(column=1,row=0)



label = Tkinter.Label(self,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))



self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



self.SetSizerAndFit(sizer)

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

This is a Label object in Tkinter .

object in . This is a StaticText in wxPython .

color

In Tkinter , it's fg="white",bg="blue" .

, it's . In wxPython , we have to call two methods ( SetForegroundColour and SetBackgroundColour )

text alignment

In Tkinter , anchor="w" means that the text should be left aligned in the label .

, means that the text should be left aligned in the . In wxPython , the text is aligned to the left by default.

position

In Tkinter , this is again the .grid() method, but this time we also span it across two cells (so that it appears below the text field and the button.): This is the columnspan=2 parameter.

, this is again the method, but this time we also span it across two cells (so that it appears below the text field the button.): This is the parameter. We do the same in wxPython by specifying a span of (1,2) (which mean: span 1 cell vertically, and 2 cells horizontally ).

expansion

Again, we use sticky="EW" for Tkinter

for We use wx.EXPAND for wxPython .

At this point, you can run both programs: They work !

STEP 12 : Enable resizing

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')



button = Tkinter.Button(self,text=u"Click me !")

button.grid(column=1,row=0)



label = Tkinter.Label(self,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')



self.grid_columnconfigure(0,weight=1)



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))



self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

0

weight

At this point, you can run both programs: They work !

vertically





STEP 13 : Adding constraint

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')



button = Tkinter.Button(self,text=u"Click me !")

button.grid(column=1,row=0)



label = Tkinter.Label(self,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')



self.grid_columnconfigure(0,weight=1)

self.resizable(True,False)



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))



self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y );

self.Show(True)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

In Tkinter , we use .resizable(True,False) .

, we use . In wxPython , you can specify the maximum and minimum widths and heights of your window.

We set minimum and maximum height to our current window height ( self.GetSize().y ) so that the window cannot be resized vertically.

We leave -1, -1 for the width so that the window can be freely resized horizontally ( -1 means "No limit").

At this point, you can run both programs: They work !

STEP 14 : Adding event handlers

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')

self.entry.bind("<Return>", self.OnPressEnter)



button = Tkinter.Button(self,text=u"Click me !",

command=self.OnButtonClick )

button.grid(column=1,row=0)



label = Tkinter.Label(self,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')



self.grid_columnconfigure(0,weight=1)

self.resizable(True,False)



def OnButtonClick(self):

print "You clicked the button !"



def OnPressEnter(self,event):

print "You pressed enter !"



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)

self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.entry)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))

self.Bind(wx.EVT_BUTTON, self.OnButtonClick, button)





self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y );

self.Show(True)



def OnButtonClick(self,event):

print " You clicked the button !"



def OnPressEnter(self,event):

print "You pressed enter !"



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

Event handlers

widgets

events

button

clicked

ENTER pressed

text field

We create a OnButtonClick() method which will be called then the button is clicked.

method which will be called then the button is clicked. We create a OnPressEnter() method which will be called then ENTER is pressed in the text field.

button

In Tkinter , simply add command=self.OnButtonClick

, simply add In wxPython, we use the .Bind() method:

button is the widget on which we want to catch an event.

wx.EVT_BUTTON is the kind of event we want to catch (a click on a button)

self.OnButtonClick is the method we want to be fired when this event is catched.

text field

In Tkinter , we use a .bind() method.

"<Return>" is the key we want to catch.

self.OnPressEnter is the method we want to be fired when this event is catched.

, we use a .bind() method. is the key we want to catch. is the method we want to be fired when this event is catched. In wxPython , this is again the .Bind() method but with the wx.EVT_TEXT_ENTER event.

Clicking on the button will trigger the OnButtonClick() method.

method. Pressing ENTER in the text field will trigger the OnPressEnter() method.

At this point, you can run both programs: They work !

STEP 15 : Changing the label

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entry = Tkinter.Entry(self)

self.entry.grid(column=0,row=0,sticky='EW')

self.entry.bind("<Return>", self.OnPressEnter)



button = Tkinter.Button(self,text=u"Click me !",

command=self.OnButtonClick)

button.grid(column=1,row=0)



self.labelVariable = Tkinter.StringVar()

label = Tkinter.Label(self, textvariable=self.labelVariable,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')



self.grid_columnconfigure(0,weight=1)

self.resizable(True,False)



def OnButtonClick(self):

self.labelVariable.set("You clicked the button !")



def OnPressEnter(self,event):

self.labelVariable.set("You pressed enter !")



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)

self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.entry)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))

self.Bind(wx.EVT_BUTTON, self.OnButtonClick, button)





self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y );

self.Show(True)



def OnButtonClick(self,event):

self.label.SetLabel("You clicked the button !")



def OnPressEnter(self,event):

self.label.SetLabel("You pressed enter !")



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

Under wxPython , it's easy: simply call .SetLabel() on our label ( self.label )

, it's easy: simply call on our label ( ) Under Tkinter , this is a bit more tricky. You have to:

, this is a bit more tricky. You have to: create a special Tkinter variable ( self.labelVariable = Tkinter.StringVar()) then bind it to the widget ( textvariable=self.labelVariable) then use set() or get() to set or read its value ( self.labelVariable.set("You clicked the button !") )



At this point, you can run both programs: They work !

STEP 16 : Display the value

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entryVariable = Tkinter.StringVar()

self.entry = Tkinter.Entry(self, textvariable=self.entryVariable )

self.entry.grid(column=0,row=0,sticky='EW')

self.entry.bind("<Return>", self.OnPressEnter)

self.entryVariable.set(u"Enter text here.")



button = Tkinter.Button(self,text=u"Click me !",

command=self.OnButtonClick)

button.grid(column=1,row=0)



self.labelVariable = Tkinter.StringVar()

label = Tkinter.Label(self,textvariable=self.labelVariable,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')

self.labelVariable.set(u"Hello !")



self.grid_columnconfigure(0,weight=1)

self.resizable(True,False)



def OnButtonClick(self):

self.labelVariable.set( self.entryVariable.get()+" (You clicked the button)" )



def OnPressEnter(self,event):

self.labelVariable.set( self.entryVariable.get()+" (You pressed ENTER)" )



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)

self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.entry)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))

self.Bind(wx.EVT_BUTTON, self.OnButtonClick, button)





self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y );

self.Show(True)



def OnButtonClick(self,event):

self.label.SetLabel( self.entry.GetValue() + " (You clicked the button)" )



def OnPressEnter(self,event):

self.label.SetLabel( self.entry.GetValue() + " (You pressed ENTER)" )



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

In wxPython , this is is a matter of self.entry.GetValue()

, this is is a matter of In Tkinter , we have to create a Tkinter variable again, so that we can do self.entryVariable.get().

At this point, you can run both programs: They work !

STEP 17 : Small refinement: auto-select the text field

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entryVariable = Tkinter.StringVar()

self.entry = Tkinter.Entry(self,textvariable=self.entryVariable)

self.entry.grid(column=0,row=0,sticky='EW')

self.entry.bind("<Return>", self.OnPressEnter)

self.entryVariable.set(u"Enter text here.")



button = Tkinter.Button(self,text=u"Click me !",

command=self.OnButtonClick)

button.grid(column=1,row=0)



self.labelVariable = Tkinter.StringVar()

label = Tkinter.Label(self,textvariable=self.labelVariable,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')

self.labelVariable.set(u"Hello !")



self.grid_columnconfigure(0,weight=1)

self.resizable(True,False)

self.entry.focus_set()

self.entry.selection_range(0, Tkinter.END)



def OnButtonClick(self):

self.labelVariable.set( self.entryVariable.get()+" (You clicked the button)" )

self.entry.focus_set()

self.entry.selection_range(0, Tkinter.END)



def OnPressEnter(self,event):

self.labelVariable.set( self.entryVariable.get()+" (You pressed ENTER)" )

self.entry.focus_set()

self.entry.selection_range(0, Tkinter.END)



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)

self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.entry)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))

self.Bind(wx.EVT_BUTTON, self.OnButtonClick, button)





self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y );

self.entry.SetFocus()

self.entry.SetSelection(-1,-1)

self.Show(True)



def OnButtonClick(self,event):

self.label.SetLabel( self.entry.GetValue() + " (You clicked the button)" )

self.entry.SetFocus()

self.entry.SetSelection(-1,-1)



def OnPressEnter(self,event):

self.label.SetLabel( self.entry.GetValue() + " (You pressed ENTER)" )

self.entry.SetFocus()

self.entry.SetSelection(-1,-1)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

focus_set()

SetFocus()

selection_range()

SetSelection()

STEP 18 : Tkinter resize hiccup

#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



import Tkinter



class simpleapp_tk(Tkinter.Tk):

def __init__(self,parent):

Tkinter.Tk.__init__(self,parent)

self.parent = parent

self.initialize()



def initialize(self):

self.grid()



self.entryVariable = Tkinter.StringVar()

self.entry = Tkinter.Entry(self,textvariable=self.entryVariable)

self.entry.grid(column=0,row=0,sticky='EW')

self.entry.bind("<Return>", self.OnPressEnter)

self.entryVariable.set(u"Enter text here.")



button = Tkinter.Button(self,text=u"Click me !",

command=self.OnButtonClick)

button.grid(column=1,row=0)



self.labelVariable = Tkinter.StringVar()

label = Tkinter.Label(self,textvariable=self.labelVariable,

anchor="w",fg="white",bg="blue")

label.grid(column=0,row=1,columnspan=2,sticky='EW')

self.labelVariable.set(u"Hello !")



self.grid_columnconfigure(0,weight=1)

self.resizable(True,False)

self.update()

self.geometry(self.geometry())

self.entry.focus_set()

self.entry.selection_range(0, Tkinter.END)



def OnButtonClick(self):

self.labelVariable.set( self.entryVariable.get()+" (You clicked the button)" )

self.entry.focus_set()

self.entry.selection_range(0, Tkinter.END)



def OnPressEnter(self,event):

self.labelVariable.set( self.entryVariable.get()+" (You pressed ENTER)" )

self.entry.focus_set()

self.entry.selection_range(0, Tkinter.END)



if __name__ == "__main__":

app = simpleapp_tk(None)

app.title('my application')

app.mainloop()



#!/usr/bin/python

# -*- coding: iso-8859-1 -*-



try:

import wx

except ImportError:

raise ImportError,"The wxPython module is required to run this program"



class simpleapp_wx(wx.Frame):

def __init__(self,parent,id,title):

wx.Frame.__init__(self,parent,id,title)

self.parent = parent

self.initialize()



def initialize(self):

sizer = wx.GridBagSizer()



self.entry = wx.TextCtrl(self,-1,value=u"Enter text here.")

sizer.Add(self.entry,(0,0),(1,1),wx.EXPAND)

self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.entry)



button = wx.Button(self,-1,label="Click me !")

sizer.Add(button, (0,1))

self.Bind(wx.EVT_BUTTON, self.OnButtonClick, button)





self.label = wx.StaticText(self,-1,label=u'Hello !')

self.label.SetBackgroundColour(wx.BLUE)

self.label.SetForegroundColour(wx.WHITE)

sizer.Add( self.label, (1,0),(1,2), wx.EXPAND )



sizer.AddGrowableCol(0)

self.SetSizerAndFit(sizer)

self.SetSizeHints(-1,self.GetSize().y,-1,self.GetSize().y );

self.entry.SetFocus()

self.entry.SetSelection(-1,-1)

self.Show(True)



def OnButtonClick(self,event):

self.label.SetLabel( self.entry.GetValue() + " (You clicked the button)" )

self.entry.SetFocus()

self.entry.SetSelection(-1,-1)



def OnPressEnter(self,event):

self.label.SetLabel( self.entry.GetValue() + " (You pressed ENTER)" )

self.entry.SetFocus()

self.entry.SetSelection(-1,-1)



if __name__ == "__main__":

app = wx.App()

frame = simpleapp_wx(None,-1,'my application')

app.MainLoop()

all the time

self.geometry(self.geometry())

update()

We're done !

RAD tools and pixel coordinates

Boa Constructor

greater control

you can use grid layout managers

Ever encountered dialogs where you could not read the text because it overflowed out of a widget ? That's pixel coordinates in action.

If you use pixel coordinates, your GUI may be unusable on systems with different font sizes.

With a grid sizer, the widgets can adapt to their content.

If you use pixel coordinates, your GUI may be unusable on systems with different font sizes. With a grid sizer, the widgets can adapt to their content. Ever beeing bothered with those ridiculously small "open file" dialogs when you have a 1600x1200 screen ? That's pixel coordinates in action too.

With a grid sizer, the user can resize the window to enjoy it full screen.

Non blocking GUI ?

the GUI will be completely blocked until the event handler method has finished.

Perform only short actions in event handlers.

actions in event handlers. Use threads.

Beware that most GUI toolkit are not thread-safe.

Clearely separating the logic of your program from the GUI will greately ease the transition to multi-threaded programming.



Tkinter or wxPython ?

Tkinter / Tcl/tk :

Tkinter is provided in the standard Python distribution. Most Python users will be able to use your program straight out of the box.



No advanced widgets, altough you can use Tkinter is provided in the standard Python distribution. Most Python users will be able to use your program straight out of the box.No advanced widgets, altough you can use Pmw (Python Megawidgets).

wxPython / wxWidgets:

Uses native operating system widgets when possible (look & feel closer to the operating system's).



More advanced widgets (date selector, floating toolbars, shaped windows, treeviews, tooltips, etc.)



Not part of the standard Python distribution. Must be downloaded and installed separately. Uses native operating system widgets when possible (look & feel closer to the operating system's).More advanced widgets (date selector, floating toolbars, shaped windows, treeviews, tooltips, etc.)Not part of the standard Python distribution. Must be downloaded and installed separately.

Other GUI toolkit

Packaging to an EXE

webGobbler

About this document