how to create a modeless dialog in tcl/tk

756 views Asked by At

I'm trying to make a modeless dialog, since whenever a dialog appears stops the real time process that is running in the main gui, after some reasearch i realize that the problem that is causing the real time part to stop is the "vwait" command in the dialog procedure. How could I make the my current dialog modeless so it doesn't affect the real time process in the back? Should I put the msgDialog in a different thread everytime i call the proc ? or what other way can I do it?

TCL CODE:

proc MsgDialog {w message type icon} \
{


if {![winfo exists $w]} { 
    set dialColor white

    image create photo .alert -format PNG -file alertIcon.png -width 40
    image create photo .question -format PNG -file questionicon.png

    toplevel $w -borderwidth 2 -relief raised -background $dialColor
    wm overrideredirect $w 1
    set x [expr { ( [winfo vrootwidth  $w] - 350  ) / 2 }]
    set y [expr { ( [winfo vrootheight $w] - 190 ) / 2 }]
    wm geometry $w 350x190+${x}+${y}


    frame $w.msgPnl -relief flat -borderwidth 1 -background $dialColor -width 280 -height 140
    place $w.msgPnl -x 0 -y 0

    frame $w.imgPnl -relief flat -borderwidth 1 -background $dialColor -width 50 -height 140 
    place $w.imgPnl -x 285 -y 0

    frame $w.btnPnl -relief flat -borderwidth 1 -background $dialColor -width 300 -height 50
    place $w.btnPnl -x 0 -y 130

    label $w.msgPnl.message -text $message -background $dialColor -justify center -wraplength 270 -font dialogFont
    pack $w.msgPnl.message -anchor center -pady 20 -padx 10 -expand 1 -fill both

    if {$type == "ok"} {

        button $w.btnPnl.okbut -text "OK" -background black -foreground white -relief flat -command {set _res "ok"} -width 8 -height 2 -highlightthickness 2 -font boldFont
        grid $w.btnPnl.okbut -row 1 -column 1 -padx 125

    } elseif {$type == "yesno"} {

        button $w.btnPnl.yes -text "Yes" -background black -foreground white -relief flat -command {set _res "yes"} -width 8 -height 2 -highlightthickness 2 -font boldFont
        button $w.btnPnl.no -text "No" -background black -foreground white -relief flat -command {set _res "no"} -width 8 -height 2 -highlightthickness 2 -font boldFont
        grid $w.btnPnl.yes -row 1 -column 1 -padx 50
        grid $w.btnPnl.no -row 1 -column 2

    } else {

        button $w.btnPnl.okbut -text "OK" -background $btnColor -relief flat -command {set _res "ok"} -width 8 -height 2
        pack $w.btnPnl.okbut -side top -anchor center
    }

    if {$icon == "alert"} {
        label $w.imgPnl.alertI -image .alert -compound top -background $dialColor
        pack $w.imgPnl.alertI -fill both -expand 1 -pady 20

    } elseif {$icon == "question"} {
        label $w.imgPnl.quest -image .question -compound top -background $dialColor
        pack $w.imgPnl.quest -fill both -expand 1 -pady 20
    } else {
        label $w.imgPnl.alertI -image .alert -compound top -background $dialColor
        pack $w.imgPnl.alertI -fill both -expand 1 -pady 20
    }

    raise $w
    vwait _res
    destroy $w
    return $::_res
}
}

I was trying something like this, but when i get invalid command name MsgDialog

 set tid [thread::create {thread::wait}]
 ::thread::send -async $tid {MsgDialog .dialog "Are you ready for measurement ?" yesno question} answer
 vwait answer

if {$answer == yes} {
 #do something
}
2

There are 2 answers

4
Erik Johnson On BEST ANSWER

Your dialog proc is fundamentally modal, since it returns a value. It therefore blocks until the user responds, because it can't return its value until the user gives it one.

To make it modeless, build it to just create itself and return. The buttons all then need to call procs (either global or with some fully qualified name) that will set the user value in some place you're waiting for it, then destroy the dialog properly.

This means that your "return" value must be global, the window ID variable must be global, the handler proc/procs must be global, and you'll need to trigger whatever processing you want the value for in some way that's too application specific for me to guess. It's a fair bit of work, but it's easier than trying to incorporate the threading library.

1
Bryan Oakley On

Have you tried simply removing the vwait? The difference between a modal dialog and a non-modal one is really nothing more than the modal dialog calling vwait and then doing a grab on the keyboard and mouse.