[Tutor] Shortening the code
Mic
o0MB0o at hotmail.se
Sat Nov 26 12:36:35 CET 2011
>> Alright! What is a fixed argument?
>Its onre that is the same every time the function is called.
>The lambda construct above is equivalent to the following which may
>make it clearer:
>def button_clicked(aButton):
# do something with aButton here
# that uses a lot of code and
# we want to reuse for any button
>Now we want to use that function as an event handler, but the function
>passed as the command in tkinter is not allowed to take an argument.
>So we create a very short function that takes no arguments but calls
>button_clicked with a fixed argument. And we do this for two buttons
>so that they can both use the button_clicked
>def button1_clicked():
> button_clicked(buttonOne)
>def button2_clicked():
> button_clicked(buttonTwo)
>and we can use these whehn creating our buttons:
>buttonOne = Button(parent, command=button1_clicked, ....)
>buttonTwo = Button(parent, command=button2_clicked, ....)
>Now a shorter way of doing that, which avoids writing lots of these very
>small functions is to use lambda, which is an operator that returns a
>function as a value.
>Thus
>def add2(x): return x+2
>can be written
>add2 = lambda x: x+2
>And if we don't really care about the name - which is
>true for the button commands we can put lambda directly
>into the widget creation:
>buttonOne = Button(parent,
command=lambda b=buttonOne: button_clicked(b), ....)
>buttonTwo = Button(parent,
command=lambda b=buttonTwo: button_clicked(b), ....)
>Note that this works because the lambda defines a default argument for
>the command. Thus Tkinter can call the function with no arguments and
>Python will insert the default value at runtime.
This was a lot of new information for me so it might take some time for it
to sink in.
Thanks for the information!
>>> While its perfectly legal Python to create a class inside a method its
>>> very unusual in practice and very restricting in the use of the class.
>>
>> Why is it restricting?
>Because the class is only available inside the function. You cannot
>create objects of that class anywhere outside the class.
And that is not good because you want to be able to create objects of a
class
outside the class mostly?
>Note you are setting text to '01' in every case. Thats probably not what
>you want?
No, that is not what I want. The text should be 1 for button one, 2 for
button two and so
on. I managed to solve that, but your solution above seems like a better
alternative to
solving that problem.
> def create_widgets(self):
> list_chair=[(0, 0), (0, 1), (0, 3), (0, 4), (1,0)]
> for row, column in list_chair:
> button = tk.Button(self)
> command = partial(button_clicked, button)
> button["command"] = command
> button.grid(row=row, column=column)
> command()
>As stated above this will result in every chair being green
>and having the text '01' It would be better to put the initial colour
>and text in your data list and configure each button directly:
Is there any difference between a list and a data list?
>def create_widgets(self):
>list_chair=[(0, 0, '01'), (0, 1, '02'),
(0, 3, '03'), (0, 4, '04'),
(1, 0, '05')]
>for row, column, name in list_chair:
>command = partial(button_clicked, button)
>button = tk.Button(self, color='green',
>command=command, text=name)
>button.grid(row=row, column=column)
This solution was better than mine since it is possible
to place the widgets where you want, which I couldn't do.
So, using your suggestions I get this:
import tkinter as tk
from functools import partial
def button_clicked(button):
if button["bg"] == "green":
button.configure(bg="red")
else:
button.configure(bg="green")
class Window(tk.Frame):
def __init__(self, master):
super (Window, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
list_chair=[(0, 0, '01'), (0, 1, '02'),
(0, 3, '03'), (0, 4, '04'),
(1, 0, '05')]
for row, column, name in list_chair:
command = partial(button_clicked, button)
button = tk.Button(self, color='green',
command=command, text=name)
button.grid(row=row, column=column)
root = tk.Tk()
root.title("Test")
root.geometry("200x200")
app = Window(root)
root.mainloop()
However, nothing happens when I run the program.
>This is one of the good habits in programming. Do it step by step. Get
>one thing working first before trying to add more features. Its a lot
>easier to debug code when you know what you changed to stop it working.
Thanks for the suggestions.
>Yes, but lets get the UI all done first, then we can add the button
>features.
UI means user interface, right?
>>> You should only ever have one Tk() object in a Tkinter program.
>> Why is that?
>Because thats how Tkinter expects to work! It builds a tree of all the
>windows and widgets in your program. If you have two trees in the same
>program it can get very confused about which widget is doing what to
>which other widgets, especially if they wind up in different trees!.
Alright, I understand. Thanks a lot for the help.
Mic
More information about the Tutor
mailing list