TKinter, buttonwidget response problem(1) and all btns the same size(2)!

7stud bbxx789_05ss at yahoo.com
Fri Apr 4 23:26:13 EDT 2008


On Apr 4, 7:06 pm, skanem... at yahoo.se wrote:
> 1st question:
>
> when i run this program 1 will be printed into the interpreter when i
> run it BUT without me clicking the actual button.
> when i then click the button "1", nothing happens.
>
> obv i dont want any output when i dont push the button but i want it
> when i do.
>
> what am i doing wrong here?
>
> 2nd question:
>
> i want all the buttons to have the same size. i thought i should use
> row/columnspan but i dont get that to work.
> how should i do?
>
> [code]
> #! /usr/bin/env python
> from Tkinter import *
> import tkMessageBox
>
> class GUIFramework(Frame):
>     """This is the GUI"""
>
>     def __init__(self,master=None):
>         """Initialize yourself"""
>
>         """Initialise the base class"""
>         Frame.__init__(self,master)
>
>         """Set the Window Title"""
>         self.master.title("Calculator")
>
>         """Display the main window"
>         with a little bit of padding"""
>         self.grid(padx=10,pady=10)
>         self.CreateWidgets()
>
>     def CreateWidgets(self):
>
>         self.enText = Entry(self)
>         self.enText.grid(row=0, column=0, columnspan=8, padx=5,
> pady=5)
>
>         self.enText = Entry(self)
>         self.enText.grid(row=1, column=0, columnspan=8, padx=5,
> pady=5)
>
>         self.btnDisplay = Button(self, text="1",
> command=self.Display(1))
>         self.btnDisplay.grid(row=3, column=0, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="2", default=ACTIVE)
>         self.btnDisplay.grid(row=3, column=1, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="3", default=ACTIVE)
>         self.btnDisplay.grid(row=3, column=2, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="+", default=ACTIVE)
>         self.btnDisplay.grid(row=3, column=3, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="4", default=ACTIVE)
>         self.btnDisplay.grid(row=4, column=0, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="5", default=ACTIVE)
>         self.btnDisplay.grid(row=4, column=1, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="6", default=ACTIVE)
>         self.btnDisplay.grid(row=4, column=2, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="-", default=ACTIVE)
>         self.btnDisplay.grid(row=4, column=3, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="7", default=ACTIVE)
>         self.btnDisplay.grid(row=5, column=0, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="8", default=ACTIVE)
>         self.btnDisplay.grid(row=5, column=1, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="9", default=ACTIVE)
>         self.btnDisplay.grid(row=5, column=2, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="*", default=ACTIVE)
>         self.btnDisplay.grid(row=5, column=3, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="0", default=ACTIVE)
>         self.btnDisplay.grid(row=6, column=0, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="C", default=ACTIVE)
>         self.btnDisplay.grid(row=6, column=1, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="r", default=ACTIVE)
>         self.btnDisplay.grid(row=6, column=2, padx=5, pady=5)
>
>         self.btnDisplay = Button(self, text="/", default=ACTIVE)
>         self.btnDisplay.grid(row=6, column=3, padx=5, pady=5)
>
>     def Display(self, xbtn):
>         if xbtn==1:
>             print 1
>
> if __name__ == "__main__":
>     guiFrame = GUIFramework()
>     guiFrame.mainloop()
>
> [/code]



If you have this function:

def f():
   print 1
   return 10

and you write:

result = f()

The '()' is the function execution operator; it tells python to
execute the function.  In this case, the function executes, and then
the return value of the function is assigned to the variable result.
If a function does not have a return statement, then the function
returns None by default.

The same thing is happening in this portion of your code:

command = self.Display(1)

That code tells python to execute the Display function and assign the
function's return value to the variable command.  As a result Display
executes and 1 is displayed.  Then since Dispay does not have a return
statement, None is returned, and None is assigned to command.
Obviously, that is not what you want to do.

What you want to do is assign a "function reference" to command so
that python can execute the function sometime later when you click on
the button.  A function reference is just the function name without
the '()' after it.  So you would write:

command = self.Display

But writing it like that doesn't allow *you* to pass any arguments to
Display().  In addition, *tkinter* does not pass any arguments to
Display when tkinter calls Display in response to a button click.  As
a result, there is no way to pass an argument to Display.

However, there is another way to cause a function to execute when an
event, like a button click, occurs on a widget: you use the widget's
bind() function:

my_button.bind('<Button-1>', someFunc)

The first argument tells tkinter what event to respond to.
'<Button-1>' is a left click.  Check the docs for the different
strings that represent the different events that you can respond to.
The second argument is a function reference, which once again does not
allow you to pass any arguments to the function.  However, when you
use bind() to attach a function to a widget, tkinter calls the
function and passes it one argument: the "event object".  The event
object contains various pieces of information, and one piece of
information it contains is the widget upon which the event occurred,
e.g. the button that was clicked.  To get the button, you write:

Display(self, event_obj):
    button = event_obj.widget

Once you have the button, you can get the text on the button:

Display(self, event_obj):
    button = event_obj.widget
    text = button.cget("text")

    if text=="1":
        print 1



Another thing you should be aware of: self is like a class wide
bulletin board. If you are writing code inside a class method, and
there is data that you want code inside another class method to be
able to see, then post the data on the class wide bulletin board, i.e.
attach it to self.  But in your code, you are doing this:

self.btnDisplay = Button(self, text="7", default=ACTIVE)
self.btnDisplay.grid(row=5, column=0, padx=5, pady=5)

self.btnDisplay = Button(self, text="8", default=ACTIVE)
self.btnDisplay.grid(row=5, column=1, padx=5, pady=5)

As a result, your code continually overwrites self.btnDisplay.  That
means you aren't preserving the data assigned to self.btnDisplay.
Therefore, the data does not need to be posted on the class wide
bulletin board for other class methods to see.  So just write:

btnDisplay = Button(self, text="7", default=ACTIVE)
btnDisplay.grid(row=5, column=0, padx=5, pady=5)

btnDisplay = Button(self, text="8", default=ACTIVE)
btnDisplay.grid(row=5, column=1, padx=5, pady=5)


As for the button sizing problem, your buttons are all the same size
and line up perfectly on mac os x 10.4.7.





More information about the Python-list mailing list