Mailing List Archive

tkMessageBox returns 'can't invoke "frame" command:' error
import Tkinter
import tkMessageBox

def askyesno():
if tkMessageBox.askyesno("Testing Askyesno",
"Click on something!"):
print 'You clicked on Yes!';

rootWindow = Tkinter.Tk()

button1 = Tkinter.Button(rootWindow,
text="Askyesno",
command=askyesno)
button1.pack()

button2 = Tkinter.Button(rootWindow,
text="QUIT",
command=rootWindow.quit)
button2.pack()

rootWindow.mainloop()



I wrote a script similar to the one shown above. Here are my questions:

1) If I import my script above for the first time, my script runs fine.
However, after I quit my script and try to reload my script at the
Python interpreter by typing reload(myscriptname), I get the error
message: "TclError: Can't invoke "frame" command:". Actually, it is
quite a long-winded error message, I'm just giving the last line.
What's going on and how do I fix this?

2) I even tried including a frame in def askyesno(), like this:

frame1 = Tkinter.Frame(rootWindow)
if tkMessageBox.askyesno("Testing Askyesno",
"Click on something!"):
print 'You clicked on Yes!';
frame1.pack()

However, I still get the same problem. I'm using Tkinter for the first
time and this "Can't invoke "frame" command" error message has been
frustrating me tremendously whenever I try to use one of tkMessageBox's
standard dialogs. I must be doing something wrong, and I would
appreciate it if someone could give some pointers on how to use
tkMessageBox.

3) Also, how do you quit a Tkinter script? Whenever I try to close a Tk
window, I can't get back to the Python interpreter ">>>" prompt.
Instead, my Python shell hangs and I have to do a CTRL-ALT-DEL and
end-task. Surely, there are better ways of closing a Tk window.

I'm running Windows 95 on a Pentium class computer. My Python
interpreter is version 1.5.2 and my Tcl/Tk interpreter is the same one
that is installed automatically by the Python 1.5.2 installer.

Thanks in advance.

Raymond Tong Leng Ng




Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
tkMessageBox returns 'can't invoke "frame" command:' error [ In reply to ]
The actuall error is caused by the Tk mainloop cannot be restarted,
obviously Tkinter was never designed to support what you're doing
here. The cause of your problem seems be partly that you actually
expected this to work, putting lots of code in a module initialisation
is not good style. If you post a description of what you are trying
to do I can give you a correct and better style solution.

--
Tim Evans
tkMessageBox returns 'can't invoke "frame" command:' error [ In reply to ]
In article <c75so7lklce.fsf@pc142.cosc.canterbury.ac.nz>,
Timothy R Evans <tre17@cosc.canterbury.ac.nz> wrote:
> The actuall error is caused by the Tk mainloop cannot be restarted,
> obviously Tkinter was never designed to support what you're doing
> here.

Oh, you mean I can't reload my script if my script contains Tkinter
calls? How do you test your Tkinter scripts then? What I usually do is,
I write my Python script in a text editor, switch to the Python
interpreter and reload my script to see if my script is working. Since
I can't do this with Tkinter scripts, does that mean everytime I want
to retest my Tkinter scripts, I have to quit Python and restart Python?

> The cause of your problem seems be partly that you actually
> expected this to work, putting lots of code in a module
> initialisation is not good style.

That bit about "putting lots of code in a module initialisation" just
went over my head. What did I do that constitutes "module
initialisation"? I've reposted my sample script below so you can point
it out to me easily.

-----
def askyesno():
if tkMessageBox.askyesno("Testing Askyesno",
"Click on something!"):
print 'You clicked on Yes!';

rootWindow = Tkinter.Tk()

button1 = Tkinter.Button(rootWindow,
text="Askyesno",
command=askyesno)
button1.pack()

button2 = Tkinter.Button(rootWindow,
text="QUIT",
command=rootWindow.quit)
button2.pack()

rootWindow.mainloop()
-----

> If you post a description of what you are trying
> to do I can give you a correct and better style solution.
>
> --
> Tim Evans

What I'm trying to do is pretty simple. I want to display a menu of
several buttons. When Button1 is clicked, it will use Windows Notepad
to open a text file and display a askyesno dialog box. If user is
satisfied with what he sees in the text file, he clicks yes and the
file will be uploaded to a server. If not, program quits. Clicking on
Button2 will open up another menu of several buttons which will run
other scripts. All the other buttons are variations of the above and
all the scripts to be called by the buttons have already by written. I
just need to write the Tkinter menu screen. I chose to use
tkMessageBox's standard dialogs because I'm new to Tkinter and the
standard dialogs pretty much cover what I need.

Thanks for your post, Tim

Raymond Tong Leng Ng


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
tkMessageBox returns 'can't invoke "frame" command:' error [ In reply to ]
tlng@phileo.com.my wrote:
> If I import my script above for the first time, my script runs fine.
> However, after I quit my script and try to reload my script at the
> Python interpreter by typing reload(myscriptname), I get the error
> message: "TclError: Can't invoke "frame" command:". Actually, it is
> quite a long-winded error message, I'm just giving the last line.

you could try passing the root window to askyesno, like
this:

reply = tkMessageBox.askyesno("foo", "bar!", master=rootWindow)

no guarantees, though.

> > The actuall error is caused by the Tk mainloop cannot be restarted,
> > obviously Tkinter was never designed to support what you're doing
> > here.
>
> Oh, you mean I can't reload my script if my script contains Tkinter
> calls? How do you test your Tkinter scripts then?

well, dejanews has the answer, as usual:

> "Incidently, in a recent project, we successfully used a combination of
> random generators, chimps, and 3-year olds to produce the actual code
> base, while the engineers concentrated their efforts on testing."

(since then, all the engineers have quit. go figure...)

> What I usually do is, I write my Python script in a text editor, switch
> to the Python interpreter and reload my script to see if my script is
> working. Since I can't do this with Tkinter scripts, does that mean
> everytime I want to retest my Tkinter scripts, I have to quit Python
> and restart Python?

I usually type ctrl-C twice to test my code. maybe you
could train your editor to do something similar for you?

> > The cause of your problem seems be partly that you actually
> > expected this to work, putting lots of code in a module
> > initialisation is not good style.
>
> That bit about "putting lots of code in a module initialisation" just
> went over my head. What did I do that constitutes "module
> initialisation"? I've reposted my sample script below so you can point
> it out to me easily.

code that's not in a def or a class are executed when you
run your program as a script, *and* if you import your pro-
gram as a module. it's usually better to put the important
stuff in a function instead, by various reasons (it runs faster,
it's easier to deal with the day you decide to turn your code
into a module, etc, etc).

</F>
tkMessageBox returns 'can't invoke "frame" command:' error [ In reply to ]
Fredrik Lundh <fredrik@pythonware.com> wrote:
: tlng@phileo.com.my wrote:
:> If I import my script above for the first time, my script runs fine.
:> However, after I quit my script and try to reload my script at the
:> Python interpreter by typing reload(myscriptname), I get the error
:> message: "TclError: Can't invoke "frame" command:". Actually, it is
:> quite a long-winded error message, I'm just giving the last line.

: you could try passing the root window to askyesno, like
: this:

: reply = tkMessageBox.askyesno("foo", "bar!", master=rootWindow)

: no guarantees, though.

:> > The actuall error is caused by the Tk mainloop cannot be restarted,
:> > obviously Tkinter was never designed to support what you're doing
:> > here.
:>
:> Oh, you mean I can't reload my script if my script contains Tkinter
:> calls? How do you test your Tkinter scripts then?

: well, dejanews has the answer, as usual:

:> "Incidently, in a recent project, we successfully used a combination of
:> random generators, chimps, and 3-year olds to produce the actual code
:> base, while the engineers concentrated their efforts on testing."

: (since then, all the engineers have quit. go figure...)

:> What I usually do is, I write my Python script in a text editor, switch
:> to the Python interpreter and reload my script to see if my script is
:> working. Since I can't do this with Tkinter scripts, does that mean
:> everytime I want to retest my Tkinter scripts, I have to quit Python
:> and restart Python?

: I usually type ctrl-C twice to test my code. maybe you
: could train your editor to do something similar for you?

:> > The cause of your problem seems be partly that you actually
:> > expected this to work, putting lots of code in a module
:> > initialisation is not good style.
:>
:> That bit about "putting lots of code in a module initialisation" just
:> went over my head. What did I do that constitutes "module
:> initialisation"? I've reposted my sample script below so you can point
:> it out to me easily.

: code that's not in a def or a class are executed when you
: run your program as a script, *and* if you import your pro-
: gram as a module. it's usually better to put the important
: stuff in a function instead, by various reasons (it runs faster,
: it's easier to deal with the day you decide to turn your code
: into a module, etc, etc).

: </F>

I haven't been following this thread too closely, but in general, I
believe that as long as you call the "quit" method of any Tkinter
widget, then "mainloop()" is restartable. (Having just redesigned the
underlying Tcl/Tk/Tkinter modules, I've seen how this works.) If you
instead call the "destroy" method, then it is unlikely that you can
restart the event loop (the Tk object has usually been destroyed, but
not always).

-Arcege
tkMessageBox returns 'can't invoke "frame" command:' error [ In reply to ]
Hai Raymond,

though I'm new to python and Tkinter myself, I think I know what the
problem is. I tried it out at my site and it seems to work. And if
there is any truth in what I am going to tell (please you higher
gods, correct me if i'm wrong) I have finally fathomed the difference
between quit and destroy whilst figuring out your bug:).

The point is that you repeatedly try to initialise Tkinter without
properly finishing up prior uses. You correctly call widget.quit(), but
this doesn't destroy the widget, it merely exits the widget.mainloop().
This can easily be seen: after finishing the first import of your code
in the interactive interpretor by pressing the 'quit' button, you will
notice that the window doesn't disappear. Though this window is kind of
dead in not reacting to clicking it is still there. And so is your
invocation of Tkinter. If at this point you reload your script you might
notice that the default window label now reads "Tk #2" to remind you of
the fact that you now have a second invocation of Tkinter running at the
same time.

The way out is simple, you have to explicitly destroy your widgets.
a simple "rootWindow.destroy()" after the call to mainloop will do.


As for your error message complaining about the frame command not working
because the application has been destroyed, that's a little trickier.
Just where should I start...

First, Tkinter keeps track of the current Tk invocation using the var
Tkinter._default_root, initially this equals None, and upon invocing
Tk() it gets initialised. Unfortunately Tkinter doesn't reset this
var to None upon termination of Tk through an appropriate destroy()!
(maybe this should be considered a bug? who should know about it?)

Second, many (all?) widget commands have None as default for the master
keyword-arg. And if you don't specify an explicit master for the widget
the before mentioned Tkinter._default_root will be used. But elas,
the second time around (reloading your script) this still refers to the
now obsolete Tk instantiation. Hence the Tcl error: that Tk doesn't
exist anymore.

There are two ways to remedy this:
1) add something like "master=rootWindow" to constructor calls of MessageBox
widgets.
2) do what Tkinter should have done, i.e. "Tkinter._default_root==None"
but only do this after you have destroyed the root window with something
like "rootWindow.destroy()", the latter is done automatically upon
pressing the root-window-close-button, but has to be programmed otherwise.

Hope this helps, and sure hope it's correct:}

--
groetjes, carel
tkMessageBox returns 'can't invoke "frame" command:' error [ In reply to ]
Carel Fellinger <cfelling@iae.nl> wrote:
> though I'm new to python and Tkinter myself, I think I know what the

so, I'm new and reacted to soon

> As for your error message complaining about the frame command not working
> because the application has been destroyed, that's a little trickier.
> Just where should I start...

> First, Tkinter keeps track of the current Tk invocation using the var
> Tkinter._default_root, initially this equals None, and upon invocing
> Tk() it gets initialised. Unfortunately Tkinter doesn't reset this
> var to None upon termination of Tk through an appropriate destroy()!
> (maybe this should be considered a bug? who should know about it?)

I know, I should have read the source. Or the docs.
In Tkinter.py I found that Tk.destroy() *does* reset Tkinter._default_root
when appropriate. But elas, this function doesn't get called when you
press the window-close-button without having redefined the window-close
protocol:(. Still a bug in my opinion, but a subtle one. The Tkinter C
module (_tk) provides its own window-close handler. And this one, as can
be read in Lund's excellent albeit slowly growing Tkinter Introduction
docs, doesn't tidy-up the python/tk widget hiearchy. But even if it did,
and according to Lund's docs in future versions it will, this wouldn't
reset Tkinter._default_root to None.

So all in all, just use rootWindow.destroy instead of rootWindow.quit
as command for buttons used to end your script. And use rootWindow.destroy
as the command for the window-close protocol (see Lund's docs).

I sure hope I have it right this time:)

--
groetjes, carel