[Tutor] Tkinter: binding functions to widgets

Scot W. Stevenson scot@possum.in-berlin.de
Thu, 29 Aug 2002 02:43:39 +0200


Hello Alan, 

One of the basic design principles I was taught is to keep the GUI code and 
the actual production code as separate as possible. One of the main 
reasons cited is maintenance; also, imagine you get tired of Tkinter, fall 
madly in love with Qt, and dedicate your life to writing Python programs 
for the KDE desktop. It is a lot easer to reuse your old stuff if you 
don't have to untangle the GUI code from the production code. 

Usually, you have something in the GUI that triggers an event, for example 
if you press a button. Now this widget (the Button widget, for example) 
has a parameter called "command" that you can use to point to a function. 
What you can do is tell this function to get the value out an entry field 
(such as that of an Entry widget) and pass that value to the actual logic 
code that does the real work. So the chain of events is something like:

- Button press calls function given with button command [Pure Tkinter]
- Function gets value from Entry widget and passes it on to logic function
- Logic function does the real work [No Tkinter]

Once you get down to the last level, you are free to ignore that there is 
any such thing as a GUI. 

> --a user enters a number
> --the program outputs whether or not the number was, say, greater than 0

I have some toy Tkinter code here from when I was playing with Entry fields 
that I quickly adopted to your example; it uses classes, though (which you 
can probably ignore) and because I'm not that experienced either, this 
might not be the best way of doing things (but then somebody will probably 
correct it, so we both learn something, <g>). "showinfo", in case you are 
wondering, is a pre-fab widget that is included in the tkMessageBox 
module. Note that it only accepts integers, not floats or such.

If something is not clear (or flatly doesn't work - I just renamed a few 
things, cut a few lines out, and put in the try/except part), please feel 
free to ask, and I'll see if I understand what I did back then =8).

Y, Scot

=====================================================
from Tkinter import *
from tkMessageBox import showinfo
root = Tk()

class numberchecker(Frame):
    def __init__(self, parent=None):
        Frame.__init__(self, parent)
        self.pack()

        self.entryfield = Entry(self)
        self.entryfield.insert(0, 'Type number here')
        self.entryfield.pack(side=TOP, fill=X)

        getbutton = Button(self, text='Go!', command=self.getnumber)
        getbutton.pack(side=TOP, fill=X)
        
    # Handel imput and delegate to logic function
    def getnumber(self):
        rawnumber = self.entryfield.get()

        # Make sure this is really a number
        try:
            number = int(rawnumber)
        except ValueError:
            self.entryfield.delete(0, END)
            self.entryfield.insert(0, '*** Not a number ***')
            return 

        # Call program logic and display result
        if self.check_number(number) == 1:
            self.displaygoodnews(number)
        else: 
            self.displaybadnews(number)

    # Display good news 
    def displaygoodnews(self, number):
        messagetext = 'Number %s is greater than 0!' % number
        showinfo('Hurray!', messagetext)

    # Display good news 
    def displaybadnews(self, number):
        messagetext = 'Number %s is not greater than 0!' % number
        showinfo('Oh no!', messagetext)
        
    # Actual program logic
    def check_number(self, number):
        if number > 0:
            return 1
        else:
            return 0

if __name__ == '__main__':
    test = numberchecker()
    test.mainloop()