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

头像
PerlMonk
渐入佳境
渐入佳境
帖子: 51
注册时间: 2016年09月19日 10:20
拥有现金: 锁定
Has thanked: 4 times
Been thanked: 3 times
联系:

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

帖子 #1 PerlMonk » 2017年05月20日 16:03

翻译: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]

回到 “模块”

在线用户

用户浏览此论坛: 没有注册用户 和 1 访客