[Q] How to destroy a TkToplevel window

Hello,

I want to make a dialog using Tk (and I don’t want to use TkDialog
because it would be more difficult to explain). I’m having trouble
destroying a TkToplevel window. My entire code is included below.

I have a main window with a button called ‘Callback’. If you click on
it you get the dialog, which has a ‘Cancel’ button, which simply calls
the ‘destroy’ method on the TkToplevel window. When you click on it
though, I get an error pop-up saying:

Error: invalid command name
".w0005.w0006"

Does anyoone know what I’m doing wrong? Or is there an easier way to do
what I want? Here is my code:

require ‘tk’

def callback
dialog = TkToplevel.new() { title “Add Contact” }

    button_quit = TkButton.new(dialog)   { text "Cancel"  }
    button_quit.bind("ButtonRelease-1")  { dialog.destroy }
    button_quit.pack("side" => "bottom")

end

root = TkRoot.new() {title “Hello World”}

Callback

button_add = TkButton.new(root) { text “Callback” }
button_add.bind(“ButtonRelease-1”) { callback }
button_add.pack(“side” => “left”)

Quit button.

button_quit = TkButton.new(root) { text “Quit” }
button_quit.bind(“ButtonRelease-1”) { exit }
button_quit.pack(“side” => “left” )

Tk.mainloop

Hmm, this is an interesting puzzle. The direct cause of the error
message you’re seeing is that the Tk widget ID (".w0005.w0006") is
out of scope at the time the command is invoked. But exactly why
it’s out of scope is another question, which I can’t answer.

The good news is that I have a solution for you:

class Dialog < TkToplevel
def initialize(master, &block)
super
button_quit = TkButton.new(dialog) { text “Cancel” }
# Generally you should use the ‘command’ option for Button
# widgets. You can still use a custom binding if you need
# special behavior.
button_quit.configure(“command” => Proc.new { destroy })
button_quit.pack(“side” => “bottom”)
end
end

‘master’ argument should be the root window

def callback(master)
Dialog.new master { title “Add Contact” }
end

I wish I could explain better what’s going on, but I haven’t been
doing much Ruby lately, and it’s dinnertime. Hope this helps.

···

On 11 Mar 2003 at 10:26, Daniel Carrera wrote:

I want to make a dialog using Tk (and I don’t want to use TkDialog
because it would be more difficult to explain). I’m having trouble
destroying a TkToplevel window. My entire code is included below.

I have a main window with a button called ‘Callback’. If you click on
it you get the dialog, which has a ‘Cancel’ button, which simply calls
the ‘destroy’ method on the TkToplevel window. When you click on it
though, I get an error pop-up saying:

Error: invalid command name
".w0005.w0006"

Does anyoone know what I’m doing wrong? Or is there an easier way to do
what I want? Here is my code:


Matt Gushee
Englewood, CO USA

Hi,

···

From: Daniel Carrera dcarrera@math.umd.edu
Subject: [Q] How to destroy a TkToplevel window
Date: Tue, 11 Mar 2003 10:26:14 +0900
Message-ID: 20030311012607.GA3973@math.umd.edu

I have a main window with a button called ‘Callback’. If you click on
it you get the dialog, which has a ‘Cancel’ button, which simply calls
the ‘destroy’ method on the TkToplevel window. When you click on it
though, I get an error pop-up saying:

Error: invalid command name
".w0005.w0006"

Does anyoone know what I’m doing wrong? Or is there an easier way to do
what I want? Here is my code:

The reason of this problem is the rule of binding operation of Tk.
Please see the explanation of ‘BindTag’ on Tcl/Tk documents.
You binded your callback operation to the ‘Cancel’ button.
When ‘ButtonRelease-1’, the operation is executed at first,
because the operation is binded to the widget.
And the button will be destroyed the the toplevel widget.
But, based on BindTag rule, Button widget binding is executed
after the widget binding. It executes the ‘command’ option
procedure (in this case, NULL procedure) of destroyed button widget.

There are two ways to avoid this problem.
One is to use command option instead of binding.

    button_quit.command { dialog.destroy }

And the other is to use Tk.callback_break to stop callback operations.

    button_quit.bind("ButtonRelease-1")  { 
      dialog.destroy
      Tk.callback_break
    }


Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)

Actually, just replacing:

button_quit.bind(“ButtonRelease-1”) { dialog.destroy }

by

button_quit.configure(“command” => Proc.new { dialog.destroy } )

Works. I wonder why that is.

···

On Tue, Mar 11, 2003 at 12:10:24PM +0900, mgushee@havenrock.com wrote:

Hmm, this is an interesting puzzle. The direct cause of the error
message you’re seeing is that the Tk widget ID (".w0005.w0006") is
out of scope at the time the command is invoked. But exactly why
it’s out of scope is another question, which I can’t answer.

The good news is that I have a solution for you:


Daniel Carrera
Graduate Teaching Assistant. Math Dept.
University of Maryland. (301) 405-5137

Well, I believe in the first case dialog.destroy gets evaluated at
the time the binding is set. But then you would think that the dialog
should never get displayed at all. So I’m not quite sure what’s going
on there.

In my experiment, it also seemed to make a difference whether you
pass the command as an argument to the constructor or in a separate
call to Button::configure. That shouldn’t have any effect on the
behavior of the command; I’ve been working with Tk for several years
in Tcl and Python, and I’m pretty sure it doesn’t make a difference
in either of those languages, so maybe it’s a bug in Ruby/Tk. Or
maybe you have to vary the syntax a little due to some peculiarity of
blocks in Ruby.

···

On 11 Mar 2003 at 13:02, Daniel Carrera wrote:

Actually, just replacing:

button_quit.bind(“ButtonRelease-1”) { dialog.destroy }

by

button_quit.configure(“command” => Proc.new { dialog.destroy } )

Works. I wonder why that is.


Matt Gushee
Englewood, CO USA