原文:
10.5. How do I bind keyboard keys?
There are many default key bindings built in to the widgets of perl/Tk. Making proper use of them often involves setting up the right callback. (You may wish to consult the examples in BindTable.pod for help with this subject.)
The basic idea is:
$widget -> bind('<keyname>' => action);
Where $widget is the tag or ID of the widget for which the bindings are to hold (note for global bindings you have to bind to <All>, for semi-global bindings you need to bind to all the relevant widgets in your application), '<keyname>' can be things like:
<Key> or <KeyPress> or <Any-KeyPress>
<KeyRelease>
<Button> or <ButtonPress>
<ButtonRelease>
<Button-1> or <B1>
<Double-1>
<Enter>
<Leave>
<Motion>
To figure out what names perl/Tk uses for such <bindings> use the "binder-finder" on a widget's .pm file. For example, you could find bindings hidden inside of Button.pm by typing this at your shell prompt:
perl -ne 'print if s/.*(<[^>]*>).*/$1/g;' Button.pm
while in the directory where Button.pm is located (and if you are not there then simply specify the /path/to/Button.pm). Note that due to inheritance (e.g.the type of script bindings that are being discussed here) what the binder-finder turns up may not be the last word on a given widget's behaviour. This may be especially true for a widget inside of a compound/composite widget. Note also that the binder-finder will turn up things like <FILEHANDLES> as well as honest <Bindings>. Discrimination in its use is called for (and while your at it you could have just as easily used an editor and actually examined the code directly now couldn't you?).
To get an idea of what the code is for a key that you are interested in try running the xlib_demo that comes in your perl/Tk build directory. Hold your mouse pointer over the window that appears and simply type the key that you are interested in. The code should appear in the window. If you do not have perl/Tk up and running yet try "xmodmap -pk" or look directly at the /usr/include/X11/keysymdef.h file where keysym names are given with an XK_ pre-pended. Do not try things like the Tcl/Tk %k symbols in perl scripts. %Ks will be mis-interpreted as non-existant perl hashes. Instead look at the Xevent function.
Ali Corbin mailto:corbin@adsw.fteil.ca.boeing.com recently posted a great little script for determining keyboard key bindings on a MainWindow:
#!/usr/local/bin/perl -w
use Tk;
$top = MainWindow->new();
$frame = $top->Frame( -height => '6c', -width => '6c',
-background => 'black', -cursor => 'gobbler' );
$frame->pack;
$top->bind( '<Any-KeyPress>' => sub
{
my($c) = @_;
my $e = $c->XEvent;
my( $x, $y, $W, $K, $A ) = ( $e->x, $e->y, $e->K, $e->W, $e->A );
print "A key was pressed:\n";
print " x = $x\n";
print " y = $y\n";
print " W = $K\n";
print " K = $W\n";
print " A = $A\n";
} );
MainLoop();
To bind the action of one widget to that of another try taking a look at the .pm file for the widget of interest - is there a binding function already defined? If so you may use it. An example would be the use of "Up" & "Down" Buttons for a Listbox: one could bind the Buttons to call Tk::Listbox::UpDown, however, Guy Decoux describes a much more clever way to use the <Up> and <Down> already defined in Listbox.pm (this does not work with Tk-b9.01):
#!/usr/local/bin/perl
use Tk;
$top = MainWindow->new;
$lb = $top->Listbox(-height => 10);
for($i=0; $i < 120; $i++) {
$lb->insert('end', $i);
}
$f = $top->Frame;
$up = $f->Button(
-text => "Up",
-command => [ $lb->bind(ref $lb, '<Up>'), $lb]
);
$down = $f->Button(
-text => "Down",
-command =>sub {&{$lb->bind(ref $lb, '<Down>')}($lb)}
);
$up->pack(-side => 'left');
$down->pack;
$f->pack;
$lb->pack;
MainLoop;
译文:
10.5. 如何绑定键盘上的按键?
Perl/Tk有很多内置的按键绑定,但你需要适当的设定的回应函数才能正确的使用它们。(可以参考BindTable.pod中的例子)
最基本的用法如下:
$widget -> bind(‘<keyname>’=> action);
其中$widget是所要被设置绑定的组件的标签(tag)或ID(注:对于全局绑定,你必须设置绑定为<All>,而对于半全局的绑定,你则需要给所有你的应用程序中的相关组件设置绑定);‘<keyname>’可以是下面的任何一个:
<Key> 或 <KeyPress> 或 <Any-KeyPress>
<KeyRelease>
<Button> 或 <ButtonPress>
<ButtonRelease>
<Button-1> 或 <B1>
<Double-1>
<Enter>
<Leave>
<Motion>
要想知道某个组件的.pm文件中已经设定了哪些绑定,可以对它们使用“绑定搜索器”。例如,我们可以通过在命令行中键入下面的命令来找出Button.pm中隐藏的绑定:
perl -ne 'print if s/.*(<[^>]*>).*/$1/g;' Button.pm (译者注:在windows系统中需要把单撇号[']替换为双撇号["]才能使用)
上面的命令需要在Button.pm文件所在的目录中使用,否则你必须指定正确的路径。注意,由于继承性的缘故,我们给出的这个“绑定搜索器”所发现的结果可能不是某个给定的组件的所有绑定(例如这里我们讨论的绑定类型)。尤其是对于那些混合的或组合的组件。另外,请注意,这个“绑定搜索器”在发现真正的绑定的同时可能还会输出诸如<FILEHANDLES>这样的文件句柄读入语句。它们的区别就是后面是否有函数调用,所以你可以通过直接用文本编辑器实际的查看脚本代码来很容易的区分它们。
要想知道你所感兴趣的按键的具体代码是什么,可以运行你的Perl/Tk安装目录中的xlib_demo程序。把鼠标放在出现的窗口上,然后只要按下你所感兴趣的按键,它的代码就会显示在窗口中了。如果你还没有安装和运行Perl/Tk,可以尝试用“xmodmap -pk”命令或者直接查看/usr/include/X11/keysymdef.h文件。不要在Perl脚本中使用Tcl/Tk的%k符号,因为它将被误认为是一个没有定义的Perl的hash,而不是作为Xevent的函数。(译者注:以上都是针对Unix/Linux系统而言的,Windows系统用户可以用下面的脚本)
Ali Corbin最近贴出了一个非常有用而又小巧的脚本,可以查看键盘按键的绑定用代码:
#!/usr/local/bin/perl -w
use Tk;
$top = MainWindow->new();
$frame = $top->Frame( -height => '6c', -width => '6c',
-background => 'black', -cursor => 'gobbler' );
$frame->pack;
$top->bind( '<Any-KeyPress>' => sub
{
my($c) = @_;
my $e = $c->XEvent;
my( $x, $y, $W, $K, $A ) = ( $e->x, $e->y, $e->K, $e->W, $e->A );
print "A key was pressed:\n";
print " x = $x\n";
print " y = $y\n";
print " W = $K\n";
print " K = $W\n";
print " A = $A\n";
} );
MainLoop();
在给一个组件设置某种绑定之前,我们最好先看一下这个组件的.pm文件——看看它是否已经定义了某些绑定,如果是这样的话,就可以直接利用了。例如,要想在 Listbox组件中使用“Up”和“Down”的按钮,我们就可以设置绑定来调用Tk::Listbox::UpDown函数。然而,Guy Decoux给出了一种更加聪明的方法——直接使用在Listbox.pm中已经定义的<Up>和<Down>(Tk- b9.01不能运行):
#!/usr/local/bin/perl
use Tk;
$top = MainWindow->new;
$lb = $top->Listbox(-height => 10);
for($i=0; $i < 120; $i++) {
$lb->insert('end', $i);
}
$f = $top->Frame;
$up = $f->Button(
-text => "Up",
-command => [ $lb->bind(ref $lb, '<Up>'), $lb]
);
$down = $f->Button(
-text => "Down",
-command =>sub {&{$lb->bind(ref $lb, '<Down>')}($lb)}
);
$up->pack(-side => 'left');
$down->pack;
$f->pack;
$lb->pack;
MainLoop;
(译者注:实在不好意思,水平有限,上面的程序我没看明白,无论在Unix还是Windows系统上我都没有调试成功。无奈,我只能把它修改如下:
#!/usr/local/bin/perl
use Tk;
$top = MainWindow->new;
$lb = $top->Scrolled('Listbox',-scrollbars=>'e',-height => 10);
for($i=0; $i < 120; $i++) {
$lb->insert('end', $i);
}
$f = $top->Frame;
$top->bind('<Up>'=>sub{$lb->UpDown(-1);});
$top->bind('<Down>'=>sub{$lb->UpDown(1);});
$up = $f->Button(
-text => "Up",
-command => sub{$lb->UpDown(-1);}
);
$down = $f->Button(
-text => "Down",
-command =>sub{$lb->UpDown(1);}
);
$up->pack(-side => 'left');
$down->pack;
$f->pack;
$lb->pack;
MainLoop;
这样,应该可以运行,但是显然不是原著的本意。所以,还请哪位高手指教!)