On Wed, 13 Jul 2005 08:13:42 +0000
Joseph Quigley <[EMAIL PROTECTED]> wrote:

> Hi, 
>       what's the **kw stand for, used for? What does it mean?
> 

**kw means that there is an optional list of keyword arguments that you can 
pass to __init__
(for example: main = Main(background="black") ). Keyword, because there is 
defined set of keywords that may be used.

> > Here's what I would do:
> >
> > class Main(Frame):
> >    def __init__(self, master=None, **kw):
> >        Frame.__init__(self, master, **kw)
> >
> >        showquote = Label(self, text=random.choice(quotes.quote))
> >        showquote.pack()
> >
> >        # etc
> >
> > if __name__ == '__main__':
> >    root = Tk()
> >    main = Main(root)
> >    main.pack(fill=BOTH, expand=True)
> >    root.mainloop()
> > ###
> >
> > Do you see what I am doing there, and why it is different from your 
> > approach?
> Uh, not really, no. I'm very new to GUI. So you're saying that If I make the 
> class actually do something (I edited and example in:
> An into to Tkinter, Fredrik Lundh).

O.k., let's try it in more detail

    class Main(Frame):
        def __init__(self, master=None, **kw):
            Frame.__init__(self, master, **kw)

This defines a new class "Main"; the construct "Main(Frame)" means that "Main" 
is a subclass of Frame
and so inherits all methods and other attributes of a Frame (like pack(), 
configure() and so on).
The second line defines the classes __init__() method, which is called 
everytime you create a new instance of
the Main class with e.g. " main = Main() ". There are three arguments passed to 
__init__() : "self" is the first,
because everytime you call a class method, the first argument that is passed to 
the call is the class instance
that does the call, e.g if you do " root.mainloop() ", the mainloop() method 
gets called with your root window
as first argument. You actually don't need to call this variable "self", you 
could as well call it "joe", but
everyone uses "self", and this makes sense, because it points to what is meant.
The third line now is the first thing __init__() does: it calls the Frame's 
__init__()
and passes "self" as first argument to it, so now actually when you do:

main = Main()

your variable "main" is set to what your __init__() method returns and this is 
at this point nothing else
as that what Frame.__init__() returns - a newly created Frame instance. You 
see, all arguments
that are passed to __init__() are passed to Frame.__init__(), so after these 
three lines
The "Main" class is nothing more (or less) than a Frame.

I hope this made sense so far.
Now you are ready to add some useful features to your class, to make it "more" 
than a standard Frame;
e.g. start with adding some widgets and one new class method:

    class Main(Frame):
        def __init__(self, master=None, **kw):
            Frame.__init__(self, master, **kw)
            self.label = Label(self, text="Hello")
            self.label.pack()
            self.button = Button(self, text="Change quote", 
command=self.change_quote)
            self.button.pack()

        def change_quote(self):
            if self.label['text'] == "Hello":
                self.label.configure(text="World")
            else:
                self.label.configure(text="Hello")

You see, we added a Button and a Label to the Frame. As first argument we 
passed "self" to the widgets,
which, you remember, is a Frame instance; by calling the variable "self.label" 
instead of just "label" however you did some more:
you added a new attribute to the Frame instance. the advantage is that you now 
can access the label from the outside:

  root = Tk()
  main = Main(root)
  main.pack()
  main.label.configure(text="Foo")
  root.mainloop()

changes the Label's text.

The last thing is that you defined a new class method for the "Main" class: 
change_quote()
You see, change_quote() is defined *outside* of __init__() (note the 
indentation level), 
so it becomes another class attribute, just as __init__() itself and all the 
methods inherited from Frame.
You can try:

  root = Tk()
  main = Main(root)
  main.pack()
  root.after(3000, main.change_quote)
  root.mainloop()

Here when you call "main.change_quote" the class instance is passed as first 
argument to the method,
that's why you have to pass "self" as argument in the class method definition, 
basically the same as with __init__(),
and that's why you have to use "self.change_quote" as command for the button.

I hope this still made sense.


> >    def changeQuote():
> >        currQuote = showquote.cget('config')  # Get the current quote
> >        newQuote = random.choice(quotes.quote)
> >        while newQuote == currQuote:          # Make sure the new quote 
> > differs
> >            newQuote = random.choice(quotes.quote)
> >        showquote.config(text=newQuote)
> >    Button(self, text='Show another quote', command=changeQuote).pack()
> 
> Aaag. I'm confused... I just tried you changeQuote example with out the above 
> stuff... didn't work. My error message:
>       AttributeError: 'NoneType' object has no attribute 'config'
> 

Just a guess: a common mistake among Tkinter beginners is:

    mylabel = Label(parent, text="Hello").pack()

The problem here is, because pack() returns None you don't have a reference to 
the Label,
but set the "mylabel" variable to None. If this is what happened, you need to 
split the above into two lines:

    mylabel = Label(parent, text="hello")
    mylabel.pack()



> so I edited it a little, still didn't work (same error). I tried the  class 
> Main(Frame) and didn't get it to work either. Do you think you could make it 
> a little bit simpler? If you can't that's ok, I'll try to study it more.
> 

The changeQuote() method in the example contains a typo:

    currQuote = showquote.cget('config')  # Get the current quote
                                ^^^^^^
this must be:

    currQuote = showquote.cget('text')

I hope this helps

Michael
_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to