Question

I have a proc that creates a new window, asking the user to give a database name.. And I want the function, after it's closed to return a value.

How do I make a window to return a value to it's calling proc? I tried calling it using:

puts "dbug:: [set top [new_db_window]]"

The puts is to see the result. It doesn't work. Prints an empty sting ("dbug::") as the window is created and an error "can't read "::new_db_window": no such variable" when I hit the 'ok' button.

The code for the proc is:

proc new_db_window {} {

    toplevel .new_db_menu


    wm title .new_db_menu "New Data Base"

    # Main Frame
    frame       .new_db_menu.frm -relief "groove" -bd 2
    grid        .new_db_menu.frm

    if {[info exists db_name]} {
        unset db_name
    }
    set ::new_db_window:db_name "Data_Base"

    # The Name Entry
    set frm_top [frame  .new_db_menu.frm.top]
    set lbl     [label  .new_db_menu.frm.top.label  -text "Database Name:" -width 15]
    set entr    [entry  .new_db_menu.frm.top.entry  -textvariable ::new_db_window:db_name -width 15]

    # The buttons
    set b_ok    [button .new_db_menu.frm.ok     -image icon_v   -command {return [new_db_ok_button]}]
    set b_no    [button .new_db_menu.frm.cancel -image icon_x   -command {new_db_cancel_button}]
    set sep_w   [label  .new_db_menu.frm.sep_w  -text ""        -width 1]
    set sep_e   [label  .new_db_menu.frm.sep_e  -text ""        -width 1]


    grid $lbl       -row 1  -column 1   -sticky w
    grid $entr      -row 1  -column 2   -sticky w
    grid $frm_top   -row 1  -column 1   -columnspan 4
    grid $sep_w     -row 2  -column 1   -sticky w
    grid $b_ok      -row 2  -column 2   -sticky w
    grid $b_no      -row 2  -column 3   -sticky e
    grid $sep_e     -row 2  -column 4   -sticky e



    bind    .new_db_menu    <Key-KP_Enter>  {return [new_db_ok_button]}
    bind    .new_db_menu    <Return>        {return [new_db_ok_button]}
    bind    .new_db_menu    <Escape>        {new_db_cancel_button}

    # catch presses on the window's `x` button
        wm protocol .new_db_menu WM_DELETE_WINDOW {
        new_db_cancel_button
    }

    # make the top window unusable
    focus $entr
    grab release .
    grab set .new_db_menu


}

proc new_db_ok_button {} {
    new_db_cancel_button
    return "$::new_db_window:db_name"
}
proc new_db_cancel_button {} {
    grab set .
    destroy .new_db_menu

}
Was it helpful?

Solution

One way would be to just use tkwait window $yourwindow to wait until the user closes the window. The window itself should probably use some variable passed to it by the client code to manage user input. For instance, if you need the user to input a database name, use the entry widget and bind it to a variable using its -textvariable option. After the window is closed, and tkwait in the client code returns, read the value of that variable.

Another approach is to not use modal windows and turn into event-driven control flow. That is, make your inquiry window to receive the name of a procedure which should be called when the user accepts its input (and that input is validated) and do any further processing there instead of posting a window and waiting until the user deals with it.

The relevant manual pages are: tkwait and options (for -textvariable).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top