Tab 是一个常见的 GUI 窗口小部件,它帮助将大量的选项分组为较小的子集,并向复杂的对话栏(举例来说)添加结构。
Tk::NoteBook 是 Perl/Tk 的一个具有类 Tab 外观和语义的窗口小部件。图 1 中展示了一个使用了三个标签的例子。注意,第三个标签被禁用了。
图 1. NoteBook 窗口小部件这个例子由下面的代码生成:
清单 1: 使用 NoteBook 窗口小部件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| use Tk;
use Tk::NoteBook;
$mw = MainWindow->new();
$mw->geometry( "400x100" );
$book = $mw->NoteBook()->pack( -fill=>'both', -expand=>1 );
$tab1 = $book->add( "Sheet 1", -label=>"Start", -createcmd=>\&getStartTime );
$tab2 = $book->add( "Sheet 2", -label=>"Continue", -raisecmd=>\&getCurrentTime );
$tab3 = $book->add( "Sheet 3", -label=>"End", -state=>'disabled' );
$tab1->Label( -textvariable=>\$starttime )->pack( expand=>1 );
$tab2->Label( -textvariable=>\$raisetime )->pack( expand=>1 );
$tab3->Button( -text=>'Quit', -command=>sub{ exit; } )->pack( expand=>1 );
MainLoop;
sub getStartTime {
$starttime = "Started at " . localtime;
}
sub getCurrentTime {
$raisetime = " Last raised at " . localtime;
$book->pageconfigure( "Sheet 3", -state=>'normal' );
}
|
指定回调的参数我们可以用两种不同的方式来指定回调的参数 —— 可以指定为一个普通的列表:
-command=>[ \&fct, $slide, $bar1, $bar2 ]
也可以指定为直接调用一个匿名子例程内的回调:
-command=>sub{ convert( $input, $label ) }
这两种方式之间的区别与变量范围有关;更确切地说,与参数被赋值的准确时间有关。
在第一种情况中,参数的值是在包含有 -command 属性的构造函数执行的时候计算得到的。如果参数的值稍后发生改变,将不会影响到回调内部。这在 ProgressBar 例子中是很好的,因为参数是对应用程序中窗口小部件的引用,这些窗口小部件一经创建就不再发生任何改变。
与此相反,在第二种情况中,所使用的匿名子例程的内容直到这个子例程真正被调用时才会计算得到。换句话说,在回调执行的时候,回调才可以知道参数的值。这在 DateEntry 例子中是很重要的,因为 $input 变量中包含的是最近的用户输入,所以在程序运行过程中经常会发生改变。
最后,由于 convert 函数的主体太长,不方便放置于内嵌的 sub{ } 声明中,所以我们将 convert 设计为一个单独的函数,而只是在匿名子例程中去调用它。
在任何 Perl/Tk 应用程序中都是一样,我们首先指定我们将要使用的模块,然后创建一个 MainWindow 。注意, Tk::NoteBook 以及CPAN 上贡献的其他窗口小部件并不是标准 Tk 贡献的一部分,所以需要显式地指定。
我们创建一个 NoteBook 窗口小部件作为 MainWindow 的子窗口,然后添加三个标签。 add() 函数的第一个参数是一个符号名,可以在notebook 中通过它引用生成的页:下面我们将使用它。
我将给出两条关于使用 NoteBook 窗口小部件时表面形状管理的注释。首先,尽管标签本身是窗口小部件,但它们不需要 被包装 。它们的表面形状管理是由封装它们的 NoteBook 来处理的。其次,如果 NoteBook 窗口小部件的父窗口的大小是可变的,那么,在 包装NoteBook 时,要 同时指定 -fill 和 -expand 属性,这很重要。后者确保 NoteBook 的分配矩形区将始终填充可用区域,而前者确保实际的 NoteBook 窗口小部件将扩展并填充它的分配矩形区。
标签接受多种属性。我们在这里作为例子来说明的是 -createcmd 、 -raisecmd 和 -state 。前两个可以用来注册回调,分别在标签第一次被创建及重新激活时被调用;最后一个属性可以取的值为 normal 和 disabled 。我们还在第二个标签上使用了 -raisecmd 回调,目的是当第二个标签第一次被重新激活时将第三个标签的状态由禁用切换为活动。我们在封装标签的 NoteBook 窗口小部件中使用 pageconfigure() 函数来完成这一任务,传入的第一个参数为被引用的标签的符号名。
多用途图形显示:Tk:rogressBarTk:rogressBar 是一个显示数据值的图形化描述的窗口小部件。进度条通常是在下载大文件或执行类似的长时间运行的任务时为用户提供反馈。Perl/Tk 中相应的窗口小部件具备一些特殊的特性,使得它在其他用途方面也具有吸引力。
图 2. ProgressBar 窗口小部件这个例子包括两个 ProgressBar 窗口小部件,它们连结到一个标准的 Scale 。滑块的移动调用名为 fct 的回调来改变显示的颜色条的长度,那个回调会调用 ProgressBar 的 value 函数来设置新的长度。值为 100 对应的是可见的颜色条的全长。可以分别使用 -to 和 -from属性来改变这个值以及对应于零长度颜色条的值。
举例说明了定制颜色条外观的一些方法。底部的 ProgressBar 分为十块,每两块之间有一个象素的间隔。这些是默认的值;可以通过显式地指定 blocks 和 gap 属性来进行设置。通常需要对 -padx 、 -pady、 -length 和 -borderwidth 进行一些试验。
-colors 属性接受对包含有位置-颜色对的一个数组的引用。(注意,位置必须以升序排序!)最后指定的那个颜色将用来显示颜色条,直到到达颜色将发生改变的下一个位置点。所以,定义 @colors = ( 0, "red", 50, "green" ); 会生成一个左边为红色右边为绿色的颜色条。在这里,我给出了 100 个离散的值,为顶部的 ProgressBar 生成了彩虹的颜色。注意,当窗口大小发生变化时,顶部的 ProgressBar 会改变它的长度。
清单 2: 使用 ProgressBar 窗口小部件 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| use Tk;
use Tk:rogressBar;
@colors = ( 0, '#ff002a', 1, '#ff0014', 2, '#ff000a', 3, '#ff0500', 4, '#ff1000',
5, '#ff1b00', 6, '#ff3000', 7, '#ff3b00', 8, '#ff4600', 9, '#ff5100',
10, '#ff6100', 11, '#ff7600', 12, '#ff8100', 13, '#ff8c00', 14, '#ff9700',
15, '#ffa100', 16, '#ffbc00', 17, '#ffc700', 18, '#ffd200', 19, '#ffdd00',
20, '#ffe700', 21, '#fffd00', 22, '#f0ff00', 23, '#e5ff00', 24, '#dbff00',
25, '#d0ff00', 26, '#baff00', 27, '#afff00', 28, '#9fff00', 29, '#95ff00',
30, '#8aff00', 31, '#74ff00', 32, '#6aff00', 33, '#5fff00', 34, '#54ff00',
35, '#44ff00', 36, '#2eff00', 37, '#24ff00', 38, '#19ff00', 39, '#0eff00',
40, '#03ff00', 41, '#00ff17', 42, '#00ff21', 43, '#00ff2c', 44, '#00ff37',
45, '#00ff42', 46, '#00ff57', 47, '#00ff67', 48, '#00ff72', 49, '#00ff7d',
50, '#00ff87', 51, '#00ff9d', 52, '#00ffa8', 53, '#00ffb8', 54, '#00ffc3',
55, '#00ffcd', 56, '#00ffe3', 57, '#00ffee', 58, '#00fff8', 59, '#00faff',
60, '#00eaff', 61, '#00d4ff', 62, '#00c9ff', 63, '#00bfff', 64, '#00b4ff',
65, '#00a9ff', 66, '#008eff', 67, '#0083ff', 68, '#0079ff', 69, '#006eff',
70, '#0063ff', 71, '#004eff', 72, '#003eff', 73, '#0033ff', 74, '#0028ff',
75, '#001dff', 76, '#0008ff', 77, '#0200ff', 78, '#1200ff', 79, '#1d00ff',
80, '#2800ff', 81, '#3d00ff', 82, '#4800ff', 83, '#5300ff', 84, '#5d00ff',
85, '#6e00ff', 86, '#8300ff', 87, '#8e00ff', 88, '#9900ff', 89, '#a300ff',
90, '#ae00ff', 91, '#c900ff', 92, '#d400ff', 93, '#df00ff', 94, '#e900ff',
95, '#f400ff', 96, '#ff00f3', 97, '#ff00e3', 98, '#ff00d9', 99, '#ff00ce' );
$mw = MainWindow->new();
$mw->geometry( '250x150' );
$mw->resizable( 1, 0 );
$bar1 = $mw->rogressBar( -borderwidth=>2, -blocks=>100, -gap=>0,
-troughcolor=>'white',-colors=>\@colors,
-length=>106 )->pack( -padx=>5, -pady=>5, -fill=>'x' );
$slide = $mw->Scale( -orient=>'horizontal', -length=>150,
-showvalue=>0, -tickinterval=>20 )->pack;
$bar2 = $mw->rogressBar( -padx=>2, -pady=>2, -borderwidth=>2,
-troughcolor=>'#BFEFFF', -colors=>[ 0, '#104E8B' ],
-length=>106 )->pack;
$mw->Button( -text=>'Quit', -command=>sub{ exit } )->pack( -padx=>15, -pady=>15,
-anchor=>'se' );
$slide->configure( -command=>[ \&fct, $slide, $bar1, $bar2 ] );
MainLoop;
sub fct {
my ( $slide, $bar1, $bar2 ) = @_;
my $val = $slide->get();
$bar1->value( 100 - $val );
$bar2->value( $val );
}
|
我们没有在它的构造函数中指定 Scale 窗口小部件的回调,而是稍后使用 configure 来指定。原因在于,我们需要以对两个 ProgressBar 的引用作为回调的参数,而当 Scale 构造函数被调用时,它们还没有被定义。不可能改变窗口小部件构造函数的调用次序,因为这将改变窗口小部件包装的次序。
此代码还举例说明了指定回调的参数的一种方法:作为一个匿名列表,具有到作为第一个参数的回调的引用,随后是所需的参数。如果回调不需要参数,则我们不需要创建那个匿名列表,因为 Perl 按单元素数组来处理列表上下文中计算得到的数量值。(要获得关于 Perl 中的列表的更多信息,请参阅 中列出的 Learning Perl, 2nd edition。)下面我们将用到向回调发送参数的一种不同的方法;查看 中关于两种方法之间区别的讨论。
可以为颜色条中任何一段自由地选择任意的颜色值,这就使得 ProgressBar 可以有趣地用作常规的显示窗口小部件:例如,可以通过颜色来指明显示的值是不是处在“正常”的参数范围之内。不幸的是,窗口小部件不支持 -orient 属性; ProgressBar 的方向只能是水平的。 |