tkinter: making widgets instance or not?

J

John Salerno

This is from the Tkinter tutorial:

from Tkinter import *

class App:

def __init__(self, master):

frame = Frame(master)
frame.pack()

self.button = Button(frame, text="QUIT", fg="red",
command=frame.quit)
self.button.pack(side=LEFT)

self.hi_there = Button(frame, text="Hello", command=self.say_hi)
self.hi_there.pack(side=LEFT)

def say_hi(self):
print "hi there, everyone!"

root = Tk()
app = App(root)
root.mainloop()

I'm wondering, why is frame created as a local variable, and the buttons
as instance variables? What is the difference? Can you make frame an
instance variable, or vice versa? (I tried it with the buttons and it
seems 'self.' isn't necessary, but is this just good practice for larger
programs?)
 
F

Fredrik Lundh

John said:
I'm wondering, why is frame created as a local variable, and the buttons
as instance variables? What is the difference? Can you make frame an
instance variable, or vice versa?

Tkinter maintains its own widget hierarchy, and widgets don't go away
unless you explicitly destroy them (by calling "destroy" on a widget or
a widget parent), so you don't really need to keep references to them.

however, if you need to access a widget later on, it might be a good
idea to save a reference to it somewhere...

</F>
 
J

John Salerno

Fredrik said:
however, if you need to access a widget later on, it might be a good
idea to save a reference to it somewhere...

To follow up on that point, I have the following code now. I have two
questions about it:

1. Can I somehow make the passing of 'master' to the draw_entry method
automatic, so I don't have to type it each time I call the function?

2. Related to your comment, the obvious problem here is that it doesn't
save references to the text box names, so I can't access them later. Is
there still a way to automate the process like I've done, but have each
entry field have a separate name?

Thanks.

---------------

import Tkinter as tk


class App:

def __init__(self, master):
self.draw_entry(master, 'First Name:')
self.draw_entry(master, 'Last Name:')

def draw_entry(self, master, label_text):
frame = tk.Frame(master, bd=4)
frame.pack()
self.label = tk.Label(frame, text=label_text, width=10)
self.label.pack(side=tk.LEFT)
self.entry = tk.Entry(frame)
self.entry.pack(side=tk.LEFT)


root = tk.Tk()
app = App(root)
root.resizable(width=False, height=False)
root.mainloop()
 
J

John Salerno

John said:
2. Related to your comment, the obvious problem here is that it doesn't
save references to the text box names, so I can't access them later. Is
there still a way to automate the process like I've done, but have each
entry field have a separate name?

A thought about this: maybe I can pass in the name of what I'd like the
entry field to be called as another parameter, then after the entry
object is created I can say something like:

self.<myname> = self.entry

Of course, I'm not sure how to write the left side, because I assume I'd
have to pass in my new name as a string, but a string wouldn't work as
an instance variable.

Also, would there be any problems with this kind of assignment? Any
weird reference problems that makes this not really work?
 
J

John McMonagle

To follow up on that point, I have the following code now. I have two
questions about it:

1. Can I somehow make the passing of 'master' to the draw_entry method
automatic, so I don't have to type it each time I call the function?

2. Related to your comment, the obvious problem here is that it doesn't
save references to the text box names, so I can't access them later. Is
there still a way to automate the process like I've done, but have each
entry field have a separate name?

Thanks.

---------------

import Tkinter as tk


class App:

def __init__(self, master):
self.draw_entry(master, 'First Name:')
self.draw_entry(master, 'Last Name:')

def draw_entry(self, master, label_text):
frame = tk.Frame(master, bd=4)
frame.pack()
self.label = tk.Label(frame, text=label_text, width=10)
self.label.pack(side=tk.LEFT)
self.entry = tk.Entry(frame)
self.entry.pack(side=tk.LEFT)


root = tk.Tk()
app = App(root)
root.resizable(width=False, height=False)
root.mainloop()
--


Try this:

import Tkinter as tk

class App:

def __init__(self, master):
self.parent = master
self.entry1 = self.draw_entry('First Name:')
self.entry2 = self.draw_entry('Last Name:')

def draw_entry(self, label_text):
frame = tk.Frame(self,parent, bd=4)
frame.pack()
label = tk.Label(frame, text=label_text, width=10)
label.pack(side=tk.LEFT)
entry = tk.Entry(frame)
entry.pack(side=tk.LEFT)
return entry

root = tk.Tk()
app = App(root)
root.resizable(width=False, height=False)
root.mainloop()
 
J

John McMonagle

Try this:

import Tkinter as tk

class App:

def __init__(self, master):
self.parent = master
self.entry1 = self.draw_entry('First Name:')
self.entry2 = self.draw_entry('Last Name:')

def draw_entry(self, label_text):
frame = tk.Frame(self,parent, bd=4)

Sorry - typo. Should reas self.parent not self,parent
 
J

John Salerno

John said:
def __init__(self, master):
self.parent = master
self.entry1 = self.draw_entry('First Name:')
self.entry2 = self.draw_entry('Last Name:')

Genius! :) Looks like you solved both of my problems! Thanks!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,010
Latest member
MerrillEic

Latest Threads

Top