2

I have these bindings in an application:

bind $::app     <Control_L><o>      {FileOpen}
bind $::app     <Control_L><O>      {FileOpen}

FileOpen is a proc.

I press Ctrl+o in a text widget and FileOpen is launched fine, but first a newline is inserted into the text widget at insertion point.

I know that Ctrl+o is a default binding for inserting a newline in text widgets, but shouldn't my binding override that?

I have also tried the following:

bind $::app         <Control_L><o>      {}
bind $::app         <Control_L><O>      {}
bind $::app.text    <Control_L><o>      {}
bind $::app.text    <Control_L><O>      {}
bind $::app         <Control_L><o>      {FileOpen}
bind $::app         <Control_L><O>      {FileOpen}

Still no success. What is going on?

Tcl/Tk 8.5.10 on Ubuntu.

1 Answers1

5

Tk groups bindings into collections called “binding tags” (or bindtags for short). Each widget starts with four bindtags defined on it:

  1. the bindtag for the widget itself (with the same name as the widget),
  2. the bindtag for the widget's class,
  3. the bindtag for the toplevel containing the widget, and
  4. the “all” bindtag for global bindings.

(Toplevels have just three bindtags.) The first argument to bind is not actually a widget name, but rather a bindtag name. You can get and manipulate the list of bindtags for a widget using the bindtags command, though that's a very far-reaching change to apply to a widget; you probably want to avoid changing the bindtags unless you're digging into the depths. (In effect you're changing the stack of controllers applied to a particular view; very subtle stuff to modify.)

When processing a GUI event sent to a widget, the bindtags for that widget are considered in order, and exactly one entry in the binding table attached to that bindtag is found (or the table is skipped if there are no matches) and evaluated after substitutions are applied. Then the binding table for the next bindtag is evaluated, unless the binding script evaluation produces a break exception. If a binding evaluation wishes to prevent consideration of further scripts attached to binding tags further on the stack, it needs to finish with a break.

Which all sounds rather complicated, but isn't. In the simplest case, put break on the end of a widget binding script to stop a later class, toplevel or global binding script from applying.

bind $::app      <Control_L><o> {FileOpen}
bind $::app      <Control_L><O> {FileOpen}
bind $::app.text <Control_L><o> {SpecificOperation; break}
bind $::app.text <Control_L><O> {SpecificOperation; break}

OK, so SpecificOperation might be nothing at all. You'll have to tune however you want.


You can also put the logic for doing the break into SpecificOperation, which is great when you need to only do the break sometimes, but to make a procedure issue a break to its caller you have to do it like this:

return -code break
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215