Chapter 11. Frame, MainWindow, and Toplevel Widgets 框架,主窗体,顶级部件
框架和Toplevels 都是设计用于其他部件的容器。
它们的不同在两个方面:
在它们的默认设置和和其他部件的关系。
一个Frame,默认 没有明显的边界,relief 或者任何其他表明 它是在那里,
而所有的Toplevel 部件有装饰
一个Toplvel 可以操作单独的其他的顶级部件,
但是Frame 总是需要一个parent(一个Toplevle或者其他Frame) 它不能是单独的:
我们已经看到很多的例子使用Toplevel widgets, 部件通过调用MainWindow->new 创建
通常是一个Toplevel widget,如果你打印这个变量 ,你会看到这样的东西:
print "$mw\n"; # prints: MainWindow=HASH(0x909a2d0)
这个窗口是被指定因为它自动的显示它本身, 当你调用Mainloop.
在其他方面, MainWindow widget 是一个Toplevel。
通过创建一个Toplevel widget,你可以创建另外一个窗口 作为你应用的一部分。
其他的Toplevel widgets 在你的程序里 必须被显示的显示 在代码里
当你使用一个额外的Toplevel 是一个设计决定 ,你必须做。
你需要使用另外一个Toplevel widget 代替MainWindow
如果这里有太多的信息来适应这个窗口。
使用Toplevels 来组织信息也是一个好的主意,你不需要有太多的窗口 对于用户导航栏,
但是一个好的设计的应用可能会使用一到2个
这里有一些例子使用 Toplevel widgets:
显示一个关闭按钮的信息文本:
看看 Tk::Dialog. 它是设计做这个,使用一个 Toplevel widget:
提供数据收集输出不同的Toplevel windows 有用户比如点击按钮触发
Frame 部件的整个目的是提供一个其他部件的容器, 它看起来是重要的,
Perl/Tk的 的布局管理器 提供了一些限制(查看 章节2 布局管理器)
我们可以使用Frames 来帮助把工作做的更好。
我们会pack 作为我们简单的布局管理器通过这个章节,因为它是最流行的,
但是记住 使用一个Frame 最基本的规则 适用于其他布局管理器
当一个Frame 包含其他的部件,它容纳了部件的大小 在他里面,
如果你没有任何部件部署在Frame里, 你不会看到Frame.
如果部件在Frame是被重新调整 由于一些原因, Frame也会尝试resize .
11.1. Creating a Frame 创建一个Frame:
创建一个框架部件 没有什么特别的,除了你通常保存一个引用到部件,所以你可以把其他的东西放在它里面:
Frame的父窗体是一个MainWindow,一个Toplevel, 或者其他的Frame 部件。
当部件被创建后,它可能变成一个父窗体对于其他部件。
你必须已经创建了Frame,但是需要不是在屏幕上的 ,变成其他部件的父窗体。
记住, 即使你部署其他部件在你的Frame里, 如果你不部署 Frame,其他的部件不会出现在屏幕上。
从技术上讲, 任何部件可以是其他部件的父部件, 但是生活要简单点 当部件是一个窗体的child
11.2 创建一个Toplevel Widget:
要创建一个Toplevel, 从需要的父部件调用Toplevel,通常 MainWindow 部件
(通过 MainWindow->new( )) 创建。
返回的条目是一个引用到Toplevel widget; 引用允许你配置部件,
调用方法,这里有一个简单的例子:
use Tk;
$mw = MainWindow->new;
$mw->title("MainWindow");
$mw->Button(-text => "Toplevel", -command => \&do_Toplevel)->pack( );
MainLoop;
sub do_Toplevel {
if (! Exists($tl)) {
$tl = $mw->Toplevel( );
$tl->title("Toplevel");
$tl->Button(-text => "Close",
-command => sub { $tl->withdraw })->pack;
} else {
$tl->deiconify( );
$tl->raise( );
}
}
当你允许这个程序, 点击Toplevel 按钮 在MainWindow 创建Toplevel widget(如果需要的化)
然后显示它, 点击关闭隐藏Toplevel。
你需要Toplevel部件的存在 在你显示它之前,因为你不要重新创建 它如果它已经存在,
你不需要尝试显示一些 不存在的
当你的关闭按钮被点击, Toplevel 被撤回。 它仍旧存在, 只是对用户不可见。
这个节约时间 下一次重新显示相同的窗口。
你也可以使用 撤走 如果你不需要显示部件 当你用小部件填满。
简单地使用 withdraw 方法, 不是内部的部件,
然后使用deiconify and raise 来重新显示部件:
11.5. Toplevel Methods Toplevel 部件:
Toplevel 部件 方法被列出,下面章节会被解释。
重要的是要注意所有这些方法也应用于一个MainWindow
一个MainWindow 是一个指定的部件。
也请记住,大量的方法最初被设计用于使用一个Unix windowing environment,
其中不少规定在Win32上没有影响。
很多那些函数 没有任何作用罪域典型的Perl/Tk应用,但是记录他们在这里:
11.6. Creating Multiple MainWindows 创建多个 MainWindows :
有时候,你可能需要创建多个MainWindows 在相同的程序,典型的,
有两个MainWindows 在一个应用里 不是一个明智的注意,
因为位图和凸显不能在MainWindows 之间贡献。
一些Tk模块贡献时是不可靠的。
但不管怎么说我们要探索它,因为它是一个有趣的练习。
来显示它是如何完成的, 我们会开始一个更先进的 "Hello Worlds" 程序,
之所以这么叫是因为它使用了两个主窗体:
你可能想知道什么有用的程序可能存在 利用多于一个的屏幕。
非线性数字视频编辑软件就是一个很好的例子。
高分辨率屏幕显示电影的过程,另外一个屏幕包含编辑控制。
我们的小项目开始通常够用,导入所有需要的Tk符号,子程序, 变量,类,部件,和方法。
然后打开第一个MainWindow, $mv1,以正常方式:
它运行严格和启用warnings, 大部分的程序在本书中都是这样
#!/usr/local/bin/perl -w
#
# Advanced Hello World program using two MainWindows.
use Tk;
use subs qw/beep/;
use strict;
my $mw1 = MainWindow->new;
默认情况下, MainWindow 打开它的窗口来显示通过$ENV{DISPLAY},
通常在Unxi上是:0(假设你没有指定它 在其他地方)
屏幕号码是解释为 至少2种方式,如果有多个物理屏幕 逻辑上作为一个。
他们被定位通过屏幕号码。
屏幕是对待为一个连续的局域, 因此如果你需要移动一个窗口从一个屏幕到另外一个,
就抓住它并拖动它。
我们打开第2个MainWindow 就像 第一个一样,但是提供了命令行 勾选 来发送它到其他地方
my $mw2 = MainWindow->new(-screen => $ARGV[0] ||= $ENV{DISPLAY});
$mw1->Button(-text => 'MainWindow 1 Bell', -command => [\&beep, $mw1])->pack;
$mw1->Button(-text => 'MainWindow 2 Bell', -command => [\&beep, $mw2])->pack;
$mw1->Button(qw/-text Quit -command/ => \&exit)->pack;
MainLoop;
sub beep {shift->bell}
请注意 MainWindow的构造参数是 -screen 不是 -display
如果在命令行 什么都没指定,那么两个窗口出现正在相同的屏幕:
现在部署3个按钮在第一个MainWindow , 设置一个简单的回调 来响铃 在每个窗口