Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

howto forget bindings in text widget

Status
Not open for further replies.

japskar

Programmer
Feb 13, 2002
27
0
0
When I build a GUI in Tcl/tk, I usually bind the <Return> key to the [OK] button and <ESC> key to the [CANCEL] button. But invoking the [OK] button is exactly what you don't want when you're typing in a Text widget and want to begin a new line.

I wonder if is it possible to temporarily &quot;forget&quot; this binding when the text widget has the focus, so that pressing return begin s a newline.

Can anyone help me to a solution?

Best regards,
Jasper van Dijk

 
I'm sure you're way ahead of me on this but....
You could try being more specific on the location of the bindings. That is, you could bind <Return> to specific frames and not the toplevel. Specifically, you could bind it to everything (tedious but possible) but the text widget.
I ususally bind <Return> to entry widgets with the specific action being different depending on the variable entered. Bob Rashkin
rrashkin@csc.com
 
May be this is suitable solution
Code:
  bind .text_widget_path <Return> {}
[\code]
 
I'm assuming that japskar is employing a rather common Tcl technique of binding the KeyPresses he mentioned to the toplevel window, for example:

Code:
button .ok -text &quot;Ok&quot; -command {
    puts &quot;You clicked: Ok&quot;
}
button .cancel -text Cancel -command {
    puts &quot;You clicked: Cancel&quot;
}
pack .ok .cancel -pady 2
bind . <KeyPress-Return> {
    .ok flash
    .ok invoke
}
bind . <KeyPress-Escape> {
    .cancel flash
    .cancel invoke
}

This causes these keyboard &quot;shortcuts&quot; to be active in the entire window, no matter which widget has keyboard focus. It works because of the way events are handled in Tcl. By default, when a widget receives an event, it fires bindings matching the event that are installed in any of the following locations (referred to as binding tags):

[ol][li]On the widget itself (for example, &quot;.t&quot;)[/li]
[li]On the widget's class (for example, &quot;Text&quot; for a text widget)[/li]
[li]On the toplevel window containing the widget (for example, &quot;.&quot;)[/li]
[li]On a symbolic binding tag named &quot;all&quot;[/li][/ol]

By default, Tcl examines those binding tags in the order listed above, and at each step executes any matching binding. Thus, a single event on a widget could trigger 4 separate binding actions, one from each binding tag.

Tcl, being the flexible beast that it is, allows you to modify this behavior. One way is by including a break command in a binding action. This stops the propagation of the event to subsequent binding tags. This might lead you to believe that we've found the solution to japskar's problem. If the text widget in question is named &quot;.t&quot;, you might try this:

Code:
bind .t <KeyPress-Return> {
    break
}

Unfortunately, this breaks our text widget because much of a text widget's behavior is controled by bindings installed in the Text class binding tag. By suppressing the propagation of the <KeyPress-Return> event to the Text binding tag, we don't fire the binding that actually inserts the &quot;\n&quot; into the text widget.

In this case, a better solution is to use another Tcl command called bindtags to actually change the order in which the widget's binding tags are examined. If you execute bindtags with only a widget name as an argument, it returns a list of the current binding tags. For example:

[tt]% bindtags .t
.t Text . all[/tt]

We can change the binding tags for a widget by providing a new list as a second argument to the bindtags command. For example, the following command causes our text widget, .t, to look for bindings in the Text class first, followed by bindings on the widget, then the toplevel window, and finally &quot;all&quot;:

Code:
bindtags .t [list Text .t . all]

Now, if we have the binding on .t that executes break in response to a <KeyPress-Return> event, everything works fine. The Text class bindings fire first, inserting the &quot;\n&quot; into the widget. Then, the .t binding fires, which executes break and stops the further propagation of the event.

In general, the bindtags command is a very powerful tool. In conjunction with the bind command, it allows you to create new, symbolic binding tags that you can insert in the binding path of any widget. This is a great technique for implementing &quot;modes&quot; in your application, or creating sets of bindings that you can install easily on collections of widgets. To do so, create your bindings on a new symbolic binding tag. Then use bindtags to install the set of bindings on any widget you like. For example:

Code:
bind highlight <Enter> {
    # When the mouse enters a widget,
    # highlight it by changing its
    # background color to red.

    # Save the old background color

    set oldbg [%W cget -bg]
    %W configure -bg red
}
bind highlight <Leave> {
    # &quot;Unhighlight&quot; a widget by restoring
    # its original bacground color

    %W configure -bg $oldbg
}

# Insert the new bindtag into the path
# of whatever widgets we like

bindtags .ok [concat highlight [bindtags .ok]]
bindtags .cancel [concat highlight [bindtags .cancel]]
- Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top