Two naive Tkinter questions

Discussion in 'Python' started by Andrew Koenig, Nov 2, 2003.

  1. from Tkinter import *

    class Application(Frame):

    def setcolor(self):
    self["bg"] = "blue"

    def createWidgets(self):
    self.b1 = Button(self, bg = "red", command = self.setcolor)
    self.b1.place(height = 50, width = 50)

    self.b2 = Button(self, text = "Exit", command = self.quit)
    self.b2.place(height = 50, width = 50, x = 50)

    def __init__(self, master=None):
    Frame.__init__(self, master)
    self.place(height = 50, width = 100)
    self.createWidgets()

    app = Application()
    app.mainloop()


    1) When I run this program, it displays two buttons. When I click the
    button on the left, I would like the color of that button to change from red
    to blue. This code is obviously the wrong way to accomplish this, because
    when setcolor is called, it gets the button's parent, not the button itself.
    How do I arrange for setcolor to get the right object?

    2) The window in which these buttons appear is the wrong size, and does not
    depend on the height and width given to self.place in __init__. Yet the
    height and width arguments do something, because if I set width to 75, it
    cuts off half the right-hand button. How do I say how large I want the
    window to be?
     
    Andrew Koenig, Nov 2, 2003
    #1
    1. Advertising

  2. "Andrew Koenig" <> writes:

    > 1) When I run this program, it displays two buttons. When I click the
    > button on the left, I would like the color of that button to change from red
    > to blue. This code is obviously the wrong way to accomplish this, because
    > when setcolor is called, it gets the button's parent, not the button itself.
    > How do I arrange for setcolor to get the right object?


    In the specific example, you could just *know* that setcolor deals
    with self.b1. In the more general example, you can create dynamic
    callback functions:

    self.b1 = Button(self, bg = "red",
    command = lambda: self.b1.config(bg="blue"))

    This uses a number of tricks: the lambda function has no arguments,
    yet it uses self - so it is a nested function. Also, inside a lambda
    function, you can have only expressions, so self.b1['bg']='blue' would
    not be allowed. In the general case, and not assuming nested
    functions, you would write

    def createWidgets(self):
    def b1_setcolor(self=self):
    self.b1['bg']='blue'
    self.b1 = Button(self, bg = "red", command=b1_setcolor)

    > 2) The window in which these buttons appear is the wrong size, and does not
    > depend on the height and width given to self.place in __init__. Yet the
    > height and width arguments do something, because if I set width to 75, it
    > cuts off half the right-hand button. How do I say how large I want the
    > window to be?


    The problem is that there is another toplevel widget around your
    frame; the frame itself has the size you have specified. You could
    either use Toplevel instead of Frame as a base, or you could adjust
    the size of the root window, e.g. through

    app.master.wm_geometry("100x50")

    HTH,
    Martin
     
    Martin v. =?iso-8859-15?q?L=F6wis?=, Nov 2, 2003
    #2
    1. Advertising

  3. > In the specific example, you could just *know* that setcolor deals
    > with self.b1. In the more general example, you can create dynamic
    > callback functions:
    >
    > self.b1 = Button(self, bg = "red",
    > command = lambda: self.b1.config(bg="blue"))
    >
    > This uses a number of tricks: the lambda function has no arguments,
    > yet it uses self - so it is a nested function. Also, inside a lambda
    > function, you can have only expressions, so self.b1['bg']='blue' would
    > not be allowed. In the general case, and not assuming nested
    > functions, you would write
    >
    > def createWidgets(self):
    > def b1_setcolor(self=self):
    > self.b1['bg']='blue'
    > self.b1 = Button(self, bg = "red", command=b1_setcolor)


    I worked out something similar, but I must confess that it appears
    needlessly complicated. I was hoping for a simpler solution, such as a
    variation of the "command" attribute that would cause its associated
    argument to be called with the button rather than its parent.

    Your first suggestion, knowing that setcolor deals with self.b1, doesn't
    work with my application because I'm going to have lots of these buttons,
    and I want to be able to set their colors independently.

    >
    > > 2) The window in which these buttons appear is the wrong size, and does

    not
    > > depend on the height and width given to self.place in __init__. Yet the
    > > height and width arguments do something, because if I set width to 75,

    it
    > > cuts off half the right-hand button. How do I say how large I want the
    > > window to be?

    >
    > The problem is that there is another toplevel widget around your
    > frame; the frame itself has the size you have specified. You could
    > either use Toplevel instead of Frame as a base, or you could adjust
    > the size of the root window, e.g. through
    >
    > app.master.wm_geometry("100x50")


    Gotcha -- thanks.
     
    Andrew Koenig, Nov 2, 2003
    #3
  4. Andrew Koenig

    Peter Otten Guest

    Andrew Koenig wrote:

    > work with my application because I'm going to have lots of these buttons,
    > and I want to be able to set their colors independently.


    If you have many buttons with similar functionality, I'd suggest using a
    subclass, e. g.:

    import Tkinter as tk

    class ColorButton(tk.Button):
    def __init__(self, master, text, color):
    tk.Button.__init__(self, master, text=text, command=self.execute)
    self.color = color
    def execute(self):
    self["background"] = self.color


    root = tk.Tk()
    for color in "red green blue yellow".split():
    ColorButton(root, text=color.capitalize(), color=color).pack()
    root.mainloop()

    Peter
     
    Peter Otten, Nov 2, 2003
    #4
  5. Andrew Koenig

    Alan Gauld Guest

    On Sun, 02 Nov 2003 21:32:12 GMT, "Andrew Koenig" <>
    wrote:
    > Your first suggestion, knowing that setcolor deals with self.b1, doesn't
    > work with my application because I'm going to have lots of these buttons,
    > and I want to be able to set their colors independently.


    A slight variant on the technique using lambda is:

    def setcolor(self,widget=self):
    widget['bg']='blue'
    def createWidgets(self):
    self.b1 = Button(self, bg = "red",
    command=lambda: self.setcolor(self.b1))

    Here we use the lambda to call the setcolor method with
    the widget parameter and use that within the setcolor method.

    This way you keep one method but call it from several places.
    The downside is you introduce an extra function call, but in
    a GUI event handler that's not going to be a problem!

    HTH,

    Alan G.




    Author of the Learn to Program website
    http://www.freenetpages.co.uk/hp/alan.gauld
     
    Alan Gauld, Nov 3, 2003
    #5
  6. On Sun, 2003-11-02 at 21:32, Andrew Koenig wrote:
    > > In the specific example, you could just *know* that setcolor deals
    > > with self.b1. In the more general example, you can create dynamic
    > > callback functions:
    > >
    > > self.b1 = Button(self, bg = "red",
    > > command = lambda: self.b1.config(bg="blue"))
    > >
    > > This uses a number of tricks: the lambda function has no arguments,
    > > yet it uses self - so it is a nested function. Also, inside a lambda
    > > function, you can have only expressions, so self.b1['bg']='blue' would
    > > not be allowed. In the general case, and not assuming nested
    > > functions, you would write
    > >
    > > def createWidgets(self):
    > > def b1_setcolor(self=self):
    > > self.b1['bg']='blue'
    > > self.b1 = Button(self, bg = "red", command=b1_setcolor)

    >
    > I worked out something similar, but I must confess that it appears
    > needlessly complicated. I was hoping for a simpler solution, such as a
    > variation of the "command" attribute that would cause its associated
    > argument to be called with the button rather than its parent.
    >
    > Your first suggestion, knowing that setcolor deals with self.b1, doesn't
    > work with my application because I'm going to have lots of these buttons,
    > and I want to be able to set their colors independently.
    >



    For this I would use a callback class and it's __call__ method

    (untested)

    class Callback:
    def __init__(self, button, colour):
    self.button = button
    self.colour = colour


    def __call__(self):
    self.button.config(background = self.colour)





    self.b1 = Button(self, background = "red")
    self.b1.config(command = Callback(self.b1, "blue"))
    self.b1.pack(.....)



    Regards
    Martin


    --
    Martin Franklin <>
     
    Martin Franklin, Nov 3, 2003
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?a2Q=?=

    Naive question: Crystal reports in ASP.NET

    =?Utf-8?B?a2Q=?=, May 28, 2005, in forum: ASP .Net
    Replies:
    1
    Views:
    426
    Peter van der Goes
    May 28, 2005
  2. Terran Melconian

    Naive idiom questions

    Terran Melconian, Jan 31, 2008, in forum: Python
    Replies:
    10
    Views:
    533
    kdwyer
    Feb 2, 2008
  3. Victor Reyes
    Replies:
    5
    Views:
    120
    Victor Reyes
    Sep 15, 2004
  4. J Krugman
    Replies:
    7
    Views:
    173
    Ben Morrow
    Jun 14, 2004
  5. Worky Workerson

    Naive threading performance questions

    Worky Workerson, Oct 26, 2006, in forum: Perl Misc
    Replies:
    15
    Views:
    203
Loading...

Share This Page