Is it necessary to call Tk() when writing a GUI app with Tkinter?

R

Rick Johnson

I have changed the example to do that. I also showed the alternate to
initialize a widget. Here is the current version, tested on Windows 3.2..2.
import tkinter as tk
class Application(tk.Frame):
     def __init__(self, master=None):
         tk.Frame.__init__(self, master)
         self.pack()

With all due respect, I would also recommend against "self packing" a
widget. And i can speak from experience on this issue. There was a
time when i was self-packing lots of custom compund widgets; then i
realized later the shortcomings of such action; what if you need to
use the grid or place geometry mangers instead? So remove the
self.pack line and add a line to the bottom:
root = tk.Tk()
app = Application(master=root)
app.pack() # <-- added this line
app.mainloop()
There is a minor problem left. The hi_there Button text has underscores
because if I use spaces instead, tk surrounds the text with {bra ces}.
This seems bizarre. Is there any way to have Button text with spaces and
no braces?

Not sure what is happening on your end, but i don't see any braces. In
any event, here is a slightly modified version of your code that
follows PEP8 and removes some inconsistencies.

## START CODE ##
# Python < 3.0
import Tkinter as tk
from Tkconstants import TOP, BOTTOM
from tkMessageBox import showinfo

class Application(tk.Frame):
     def __init__(self, master=None):
         tk.Frame.__init__(self, master)
         self.createWidgets()

     def createWidgets(self):
         self.hi_there = tk.Button(self)
         self.hi_there["text"] = "Hello_World\n(click_me)"
         self.hi_there["command"] = self.say_hi
         self.hi_there.pack() # !!!
         self.qbutton = tk.Button(self, text="Close Application",
                                  fg="red", command=root.destroy)
         self.qbutton.pack() # !!!

     def say_hi(self):
         showinfo('Modal Dialog', "hi there, everyone!", parent=self)
         print("hi there, everyone!")

if __name__ == '__main__':
    root = tk.Tk()
    app = Application(master=root)
    app.pack()
    app.mainloop()
## END CODE ##

Opps, i just realized that "App" is actually a Tkinter.Frame and not a
Tkinter.Toplevel. So the line:

showinfo('Modal Dialog', "hi there, everyone!", parent=self)

....is broken. Since we don't have a reference to the root window from
inside the scope of this Frame class, we can use
"self.winfo_toplevel()" to fetch a reference.

showinfo('Modal Dialog', "hi there, everyone!",
parent=self.winfo_toplevel())

....ahhh! That should work perfectly now!
 
J

John Salerno

EXAMPLE 1: (this works, but is flawed!)
root = tk.Tk()
b = tk.Button(master=None, text='Sloppy Coder')
b.pack()
root.mainloop()

EXAMPLE 2: (This is how to write code!)
root = tk.Tk()
widgetframe = tk.Frame(root)
b = tk.Button(master=None, text='Sloppy Coder')
b.pack()
root.mainloop()

EXAMPLE 3: (OOP style)
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
# something should happen here to justify using OOP
# or here

class AppFrame(tk.Frame):
def __init__(self, master, **kw):
tk.Frame.__init__(self, master, **kw)
self.createWidgets()

def createWidgets(self):
b = tk.Button(master=None, text='Push Me')
b.pack()

if __name__ == '__main__':
app = App()
frame = AppFrame(app)
frame.pack()
app.mainloop()

Why is the master argument for Button set to None? Shouldn't it be the Frame object? And shouldn't it also have self as the first argument?
 
R

Rick Johnson

Why is the master argument for Button set to None? Shouldn't it be the Frame object? And shouldn't it also have self as the first argument?

Hmm, it seems as though i am the latest victim of the "copy/paste
error"! Oh well, if you were going to absorb my teachings, you would
have absorbed them by now. I am moving on unless a new subject needs
explaining.
 
T

Terry Reedy

Not sure what is happening on your end, but i don't see any braces.

Are you saying that if you change "Hello_World\n(click_me)" to
"Hello World\n(click me)", you see

Hello World
(click me)

as I expected, instead of

{Hellow World
(click me)}

as I do see? What OS are you running? And what tk version? (I have 8.5.9
in Win7)
 
J

John Salerno

Hmm, it seems as though i am the latest victim of the "copy/paste
error"! Oh well, if you were going to absorb my teachings, you would
have absorbed them by now. I am moving on unless a new subject needs
explaining.

Well, I've certainly absorbed your recommendation to always create the rootexplicitly, but you still haven't really explained WHY. Telling me that I will eventually find out as I become more proficient isn't very helpful.

I like being explicit, so I will create the Tk option like you suggest (although I don't see the need to subclass it first), but I also like knowing WHY I do what I do, so it would help to have some reason why it's better to create the root explicitly rather than allow Tkinter to do it.
 
M

Mark Roseman

Rick Johnson said:
Book authors and Doc authors are not always the most well informed; as
we have witnessed by this very thread! Obviously these tutorials are more
like: "What NOT to do when coding Tkinter GUIs!" No wonder everyone hates Tkinter. :)

Indeed. One of the things that motivated me to write the tutorial at
http://www.tkdocs.com is the rather poor state (in terms of being out of
date, incorrect, or demonstrating poor practices) of most Tkinter
documentation.

Call it self-serving, but I think the Tkinter world would be a happier
place if everyone just pointed to TkDocs. ;-)

To your point about explicit root, etc. I'll make the general
observation that lots of different things work in a given situation,
which is just fine for quick little hacky things. If people are doing
anything more than a throwaway however, they'd be better served by
spending a bit of time learning the conceptual underpinnings (e.g.
http://www.tkdocs.com/tutorial/concepts.html) after which the "right"
thing to do will be more obvious.

Mark
 
J

John Salerno

Indeed. One of the things that motivated me to write the tutorial at
http://www.tkdocs.com is the rather poor state (in terms of being out of
date, incorrect, or demonstrating poor practices) of most Tkinter
documentation.

Call it self-serving, but I think the Tkinter world would be a happier
place if everyone just pointed to TkDocs. ;-)

To your point about explicit root, etc. I'll make the general
observation that lots of different things work in a given situation,
which is just fine for quick little hacky things. If people are doing
anything more than a throwaway however, they'd be better served by
spending a bit of time learning the conceptual underpinnings (e.g.
http://www.tkdocs.com/tutorial/concepts.html) after which the "right"
thing to do will be more obvious.

Mark

Nice. I shall be spending some time at your website. I actually like wxPython, but I decided to learn a little Tkinter because it's already included and would be an easier and quicker option for small interfaces.
 
T

Terry Reedy

Are you saying that if you change "Hello_World\n(click_me)" to
"Hello World\n(click me)", you see

Hello World
(click me)

as I expected, instead of

{Hellow World
(click me)}

as I do see? What OS are you running? And what tk version? (I have 8.5.9
in Win7)

The problem was another subtle bug in the current example":
self.hi_there["text"] = "Hello",

The spurious comma at the end makes the value of the 'text' attribute a
one-elememt tuple and not just a string. I presume tcl-based tk handles
that in the manner appropriate for the tcl equivalent. I believe tcl
uses spaces rather than commas to separate items, so the braces serve as
'quotes' to indicate that the contents are one item, not three. Removing
the comma solves the problem.
 
M

Mel Wilson

Terry said:
The problem was another subtle bug in the current example":
self.hi_there["text"] = "Hello",

The spurious comma at the end makes the value of the 'text' attribute a
one-elememt tuple and not just a string. I presume tcl-based tk handles
that in the manner appropriate for the tcl equivalent. I believe tcl
uses spaces rather than commas to separate items, so the braces serve as
'quotes' to indicate that the contents are one item, not three. Removing
the comma solves the problem.

That looks like it. Tcl is the 'LISP of strings' Composite-object things
like indexing work on space-separated strings.


Mel.
 
J

John Salerno

After that, you can nest as
many frames, toplevels, and blah widgets under that root window as you
so desire. Actually you don't even need a "frame", you can pack
widgets directly into a Toplevel or Tk widget.

This is interesting. I completely understand your point about always calling (and using) the instance of Tk as the root. Given that, what is the pointof creating a Frame object at all? I tried NOT doing it, like you said, and it seemed to work fine with my simple example. But is there a benefit to using a Frame object to group the widgets together? Or is it cleaner to just use the Tk object?
 
R

Rick Johnson

what is the point of creating a Frame object at all? I tried NOT
doing it, like you said, and it seemed to work fine with my simple
example. But is there a benefit to using a Frame object to group the
widgets together? Or is it cleaner to just use the Tk object?

You will no doubt need to use frames to group widgets from time to
time. My previous point was simply: "don't use frames superfluously!".

Here is an example of creating a custom compound widget by sub-
classing frame (psst: this widget already exists in the Tix extension.

## START CODE ##
import Tkinter as tk
from Tkconstants import LEFT, YES, X, N

class LabelEntry(tk.Frame):
def __init__(self, master, text='LE', **kw):
tk.Frame.__init__(self, master, **kw)
self.label = tk.Label(self, text=text, font=('Courier New',
12))
self.label.pack(side=LEFT)
self.entry = tk.Entry(self)
self.entry.pack(side=LEFT, fill=X, expand=YES)

def get(self):
return self.entry.get()

def set(self, arg):
self.entry.delete(0, 'end')
self.entry.set(arg)

if __name__ == '__main__':
root = tk.Tk()
for blah in (' Name:', 'Address:', ' Phone:'):
w = LabelEntry(root, text=blah)
w.pack(fill=X, expand=YES, anchor=N, padx=5, pady=5)
root.mainloop()
## END CODE ##
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top