[Perl]Win32::GUI Tutorial 官方教学翻译 Part 1

回复
头像
PerlMonk
渐入佳境
渐入佳境
帖子: 49
注册时间: 2016年09月19日 10:20
联系:

[Perl]Win32::GUI Tutorial 官方教学翻译 Part 1

帖子 PerlMonk »

翻译:523066680@163.com
主页:Code-By.Org
转载请注明出处

Win32::GUI Tutorial - Part 1
  • Hello, GUI world
    • 先从典型的 "Hello, world" 程序说起。

      首先,加载 Win32::GUI 模块

      use Win32::GUI();

      通过 Win32::GUI::Window->new() 创建窗体。new 括号内接受一系列键值对(hash)作为参数,用来定义窗体的
      属性。目前我们只需要设置宽度和高度(如果未指定大小,则默认为最小值)。

      $main = Win32::GUI::Window->new(-width => 100, -height => 100);

      窗体对象返回到 $main 变量中,以便在之后进行其他操作。
      文字内容可以通过 "label" 控件展示。使用 AddLabel() 方法将 "label" 添加到窗体。AddLabel() 方法接受
      一系列选项,类似前面提到的 new() 方法,而这里只需要指定 -text 参数。
      默认情况下 label 的尺寸恰好容得下文本内容,以及位于窗体的左上方。

      $main->AddLabel(-text => "Hello, world");

      默认情况下窗体是隐藏的,通过调用 Show 方法显示出来:

      $main->Show();

      最后,通过 Win32::GUI::Dialog() 开启“消息循环”,进入交互模式。

      Win32::GUI::Dialog();

      目前完成了最简单的窗体示例。但我们还未对用户交互事件作相应的处理,例如关闭窗体。所以当点击关闭时
      窗体仍然运行,无法从 Win32::GUI::Dialog() 循环中退出。那么如何对不同的交互事件做出响应呢?可通过
      为窗体或者控件设置名称(-name参数),再以 “对象名称_事件名称” 为函数名,定义相应的操作。

      为对象设置一个名称 —— "Main"(该名称可以作为句柄调用)
      $main = Win32::GUI::Window->new( -name => 'Main', -width => 100, -height => 100, );
      假设现在要对关闭窗口事件进行处理(对应 Terminate 事件),那么响应函数名为 Main_Terminate
      事件函数应返回以下三种结果之一:
      > 1: 执行默认操作并继续运行
      > 0: 执行指定操作并继续运行
      > -1: 结束消息循环

      显然,对于Terminate事件,应返回 -1
      sub Main_Terminate { -1; }
      完整代码:
      use Win32::GUI(); $main = Win32::GUI::Window->new( -name => 'Main', -width => 100, -height => 100, ); $main->AddLabel(-text => "Hello, world"); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; }
      可以随时设置、修改窗口的大小、位置,以及最小化最大化状态。
    扩展
    • 通过 -text 参数为窗体设置标题(译注, -text -caption -title 都是一样的):
      $main = Win32::GUI::Window->new( -name => 'Main', -width => 100, -height => 100, -text => 'Perl', );
      现在,假设要把窗口大小适应到 label。窗体分为用户自定义区域和固定区域,标题栏、边框都属于固定区域,
      剩下的为自定义区域。

      首先通过 Height() 和 Width() 方法获得窗体尺寸,然后通过 ScaleHeight() 和 ScaleWidth()
      获得窗体自定义区域的尺寸,通过求差算得固定区域占用的尺寸。再通过label对象句柄的 Height() 和
      Width() 方法获得 label 尺寸。

      获取固定区域(边界和标题栏)占用大小(none-client area):
      $ncw = $main->Width() - $main->ScaleWidth(); $nch = $main->Height() - $main->ScaleHeight();
      现在计算 固定区域 + label 尺寸
      $w = $label->Width() + $ncw; $h = $label->Height() + $nch;
      通过 Resize() 方法重设窗口尺寸
      $main->Resize($w, $h);
      注意我们必须在建立窗口之后重设窗口尺寸,因为边界需要在窗口建立之后计算。但是要在调用Show()
      之前 Resize ,以免出现闪烁的情况。
      use Win32::GUI(); $main = Win32::GUI::Window->new(-name => 'Main', -text => 'Perl'); $label = $main->AddLabel(-text => "this is a label"); $ncw = $main->Width() - $main->ScaleWidth(); $nch = $main->Height() - $main->ScaleHeight(); $w = $label->Width() + $ncw; $h = $label->Height() + $nch; $main->Resize($w, $h); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; }
    设置字体
    • 颜色
      • 可通过 -foreground 参数设置 label,颜色值可以是 16进制格式 或者 [R, G, B] 形式:
        -foreground => 0x0000FF 或者 -foreground => [ 255, 0, 0 ]
      字体
      • 通过 -font 参数设置字体,提供的值必须是 Win32::GUI::Font 对象,建立 Font 对象的方法:
        $font = Win32::GUI::Font->new(...);

        new括号内通常使用以下参数:
        -size 字体大小
        -name 字体名称,如 "Consolas", "Arial", "Verdana"
        -bold 0/1 粗体,默认为0
        -italic 0/1 斜体,默认为0
      示例代码
      • $font = Win32::GUI::Font->new( -name => "Comic Sans MS", -size => 24, ); $label = $main->AddLabel( -text => "This is Label", -font => $font, -foreground => [255, 0, 0], );
    窗口居中
    • 首先需要获得 Windows 桌面尺寸,可通过 Win32::GUI::GetDesktopWindow() 获得桌面对象(句柄),
      注意该对象不同于 Win32::GUI::Window ,所以无法直接通过 Height() 和 Width() 方法获得尺寸。
      可以通过向 Win32::GUI::Height() 和 Win32::GUI::Width() 函数传参的方式返回长和宽。
      # 假设 $h 和 $w 是预先获取的应用窗体大小 $desk = Win32::GUI::GetDesktopWindow(); $dw = Win32::GUI::Width($desk); $dh = Win32::GUI::Height($desk); $x = ($dw - $w) / 2; $y = ($dh - $h) / 2; $main->Move($x, $y);
      (翻译补充代码)
      use Win32::GUI(); $main = Win32::GUI::Window->new(-name => 'Main', -text => 'Perl'); $font = Win32::GUI::Font->new( -name => "Comic Sans MS", -size => 24, ); $label = $main->AddLabel( -text => "This is Label", -font => $font, -foreground => [255, 0, 0], ); $ncw = $main->Width() - $main->ScaleWidth(); $nch = $main->Height() - $main->ScaleHeight(); $w = $label->Width() + $ncw; $h = $label->Height() + $nch; $main->Resize($w, $h); $desk = Win32::GUI::GetDesktopWindow(); $dw = Win32::GUI::Width($desk); $dh = Win32::GUI::Height($desk); $x = ($dw - $w) / 2; $y = ($dh - $h) / 2; $main->Move($x, $y); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; }
      这时如果任意拉伸窗口,文字内容会一直处于窗口的左上方。要使其保持居中,可通过 Resize 事件
      函数做相应处理。另一点要注意的是当窗口可能被缩放到小于 label 的文字区域,所以要通过监听
      Resize事件来限制宽度和高度的最小值。
      sub Main_Resize { my $mw = $main->ScaleWidth(); my $mh = $main->ScaleHeight(); my $lw = $label->Width(); my $lh = $label->Height(); if ($lw > $mw) { $main->Width($lw + $ncw); # ncw - non-client width! } else { $label->Left(($mw - $lw) / 2); } if ($lh > $mh) { $main->Height($lh + $nch); # nch - non-client height! } else { $label->Top(($mh - $lh) / 2); } }
    限制窗体的最小尺寸
    • 如果要限制最小尺寸,可以使用上面的通过 Resize 事件强制处理的办法,但这种方法会引起闪烁,更好的方法
      是使用 -minsize 参数。
      $main = Win32::GUI::Window->new( -name => 'Main', -text => 'Perl', -minsize => [100, 100], );
      但以上一节的需求为例,在 Label 创建之前并不知道具体限制尺寸,而这里 -minsize 参数在创建窗体时使用。
      解决办法是通过 窗体对象的 Change 方法调用这个参数(在 label 创建之后)。
      $main->Change(-minsize => [$w, $h]);
    最终代码
    • use Win32::GUI(); $text = defined($ARGV[0]) ? $ARGV[0] : "Hello, world"; $main = Win32::GUI::Window->new( -name => 'Main', -text => 'Perl', ); $font = Win32::GUI::Font->new( -name => "Comic Sans MS", -size => 24, ); $label = $main->AddLabel( -text => $text, -font => $font, -foreground => [255, 0, 0], ); $ncw = $main->Width() - $main->ScaleWidth(); $nch = $main->Height() - $main->ScaleHeight(); $w = $label->Width() + $ncw; $h = $label->Height() + $nch; $desk = Win32::GUI::GetDesktopWindow(); $dw = Win32::GUI::Width($desk); $dh = Win32::GUI::Height($desk); $x = ($dw - $w) / 2; $y = ($dh - $h) / 2; $main->Change(-minsize => [$w, $h]); $main->Resize($w, $h); $main->Move($x, $y); $main->Show(); Win32::GUI::Dialog(); sub Main_Terminate { -1; } sub Main_Resize { my $mw = $main->ScaleWidth(); my $mh = $main->ScaleHeight(); my $lw = $label->Width(); my $lh = $label->Height(); $label->Left(int(($mw - $lw) / 2)); $label->Top(int(($mh - $lh) / 2)); }
图片
[Finished in 0.8s]
回复

在线用户

正浏览此版面之用户: 没有注册用户 和 0 访客