[Tutor] Updating Label widgets in Tkinter

Michael P. Reilly arcege@speakeasy.net
Wed, 27 Feb 2002 20:32:41 -0500

On Tue, Feb 26, 2002 at 11:21:07PM -0600, Tim Wilson wrote:
> Hi everyone,
> I'm hoping there's a Tkinter expert or two out there who can offer some
> help with the following:
> I'm working through a number of the Tkinter tutorials and John Grayson's
> book "Python and Tkinter Programming," but I continue to be stymied by
> the problem of updating the text of a label widget based on some
> calculation that's bound to a button. I'm including some code that draws
> a very simple screen that presents an entry widget. The user is supposed
> to enter a number, click calculate, and be presented with the square
> root of the number they typed. I've tried a bunch of things at this
> point, but everything's starting to blur. Can anyone point me in the
> right direction?

First, you need to save the widget as a member of the Calculator instance.
We'll use that later in the calc() method.  You will also have to
do that to the Entry widget if you cant the value to be cleared.  But
the essential component is that you change the 'text' attribute of
the widget.  You can do this with the config() method or by changing
the the value by subscripting.

You've got a few other errors too, which I've corrected.

> from Tkinter import *
> from math import sqrt
> class Calculator(Frame):
>     def __init__(self):
>         """Create an instance of a very simple calculator."""
>         Frame.__init__(self)
>         self.pack(expand=YES, fill=BOTH)
>         self.master.title('Square Root Calculator')
>         self.master.iconname('Sqrt')
>         fInput = Frame(self)
>         fInput.pack()
>         Label(fInput, text='x = ').pack(side=LEFT)
>         number = StringVar()
>         Entry(fInput, textvariable=number).pack(side=LEFT)
>         fOutput = Frame(self)
>         fOutput.pack()
>         fOutput.pack(padx=5, pady=5)
>         result = Label(fOutput, 
>                        text='Waiting for a number...').pack(pady=10)
          # 'Label().pack()' returns None, so result gets set to that.
          self.result = Label(fOutput, text='Waiting for a number...')

>         buttons = Frame(self)
>         buttons.pack(padx=5, pady=5)
>         Button(buttons, text='Calculate', 
>                command=self.calc(number)).pack(side=LEFT, padx=3)
                 command=lambda c=self.calc, n=number: c(n)
                ).pack(side=LEFT, padx=3)
          # the 'command=self.calc(number)' will attempt to calculate
          # the number now, not when the button is pressed, we can put
          # it in a lambda to let it be evaluated later.

>         Button(buttons, text='Quit', 
>                command=self.quit).pack(side=LEFT, padx=3)
>     def calc(self, number):
>         """Update the label named 'result' to say 'The square root of 
>         <insert original number> is <square root of that number>' 
>         and then clear the contents of the entry box."""
            numb = int(number.get())
          except ValueError:
            return  # do nothing
            text='The square root of %d is %d' % (numb, sqrt(numb))
          number.set("")  # clear the StringVar displayed in the Entry widget

> Calculator().mainloop()

These are just the simple corrections; there are other improvement that
can be made.  Those can be addressed later if you like.