免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5242 | 回复: 5
打印 上一主题 下一主题

wxPerl: Another GUI for Perl [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-09-22 11:54 |只看该作者 |倒序浏览
原作:Jouke Visser http://www.perl.com/pub/au/Visser_Jouke  .

翻译改写:chiesa  个人主页:http://chiesa.ithelper.cn

最后更新:2005/9/22

缘起

wxPerl缘起于wxWindows项目。wxWindows 是一款 C++ 语言的跨平台图形界面工具箱。后来,受微软压力 wxWindows 改名为 wxWidgets。

wxWindows是个成功的项目,于是出现了多种语言的绑定。这些绑定来自于其他的开发者。wxPerl就是其中之一。在国内,wxPython的使用者似乎更多一点。

wx 的特色在哪里呢?
wx特色就在于本地化绑定,所以做出来的界面风格和本地gui相同。
比如,在windows,就像mfc,在linux,就像gtk。

wx的设计模仿了mfc,所以mfc程序员转到这个gui平台特别容易。

wx支持Windows, Gtk, Motif 和 Macintosh平台。

wx不仅仅是GUI库,也是跨平台的类库。提供了很多实用类,比如:wxNet,wxHTML,wxODBC,wxMedia。基本上,你可以用wx开发一个完美的跨平台程序。

wxPerl的特点呢?
It is less Perlish – but it’s more OO.

概述
一个wxPerl程序,开始的时候需要创建一个类继承Wx::App。它最少需要实现一个方法OnInit,用来创建程序所使用的窗口。如果你使用标准窗口,那么你使用标准窗口类就ok了。如果你想给窗口添加一些控件,那么你需要一个类来继承标准窗口。

所以,wxPerl比Tk,Gtk更加面向对象化,但是Perlish方面要差。

wxPerl的文档很少,所以,如果你需要帮助,那么请更多的参考wxWindows的文档,当然,我认为,更多的看demo代码是更好的途径。wxPerl,wxPython,wxWindows都提供了丰富的demo。

Hello World

一切从Hello World开始。


   =1= #!/usr/bin/perl -w
   =2= use strict;
   =3= use Wx;
   =4=
   =5= ###########################################################
   =6= #
   =7= # Define our HelloWorld class that extends Wx::App
   =8= #
   =9= package HelloWorld;
  =10=
  =11= use base qw(Wx::App);   # Inherit from Wx::App
  =12=
  =13= sub OnInit
  =14= # Every application has its own OnInit method that will
  =15= # be called when the constructor is called.
  =16= {
  =17=    my $self = shift;
  =18=    my $frame = Wx::Frame->;new( undef,         # Parent window
  =19=                                -1,            # Window id
  =20=                                'Hello World', # Title
  =21=                                [1,1],         # position X, Y
  =22=                                [200, 150]     # size X, Y
  =23=                              );
  =24=   $self->;SetTopWindow($frame);    # Define the toplevel window
  =25=   $frame->;Show(1);                # Show the frame
  =26= }
  =27=
  =28= ###########################################################
  =29= #
  =30= # The main program
  =31= #
  =32= package main;
  =33=
  =34= my $wxobj = HelloWorld->;new(); # New HelloWorld application
  =35= $wxobj->;MainLoop;

从第9行开始讲解。

第9行,我们命名了一个package HelloWorld。第11行,我们申明这个包继承于wx::App,并且定义方法OnInit。所有的wxPerl开发都要像这样开始。

在 OnInit方法中,我们至少要让一个窗口跑起来。

所以在第18行,我们 new 了一个wx::Frame,这是wxPerl的一个标准窗口类型,并且定义该frame是TopWindow(第24行),也就是,把这个frame作为这个程序的最顶层的窗口。最后,我们调用show这个方法(第25行),让窗口显示出来。

创建frame的时候我们使用了一些参数。
第一个参数是父窗口。你可以把它理解为父窗口的句柄。如果我们创建2个frame,那么第二个frame就可以(但是不是必要的)设置为第一个frame的子窗口,方法是,把第一个frame,比如$frameFirst,作为参数传递给第二个frame的构造函数。在我们这个例子里面,只有一个frame,所以父窗口是undef,表示无指定。

第二个参数表示window id,-1是默认值,具体含义我们暂且不去管。通常你就使用默认值好了。

第三个参数表示窗口标题。

第四、五个指定了窗口的起始位置和窗口大小。这两个参数是作为引用传递的。当然你也可以使用wxDefaultPosition和wxDefaultSize 这两个预定义的值作为第四、五个参数,表示显示在系统默认的位置,采用默认的大小。 到此,我们的HelloWorld package就结束了。
下面我们要创建main程序段来调用 HelloWorld。

首先,定义 main package(第32行)。然后我们就new HelloWorld。执行完这句,wx的机制就已经启动了。OnInit被自动调用,窗口被显示出来。

最后是调用MainLoop方法(第35行)。这是为了让主线程不立即结束,而是等待窗口事件的处理。否则,窗口刚被显示出来,整个程序就结束了。
现在,执行我们这第一个例子程序,it will look like this:



Fill the empty window

呵呵,我们创建了一个简单的例子。显示了一个空窗口,标题是HelloWorld。不怎么兴奋?hoho。

那么下面让我们在窗口里面搞点花样。

下面我们的目标是,在窗口里面添加一段文字和一个button,不过这个button什么都不处理。

在概述里面我们说过,要在窗口里面搞花样,你必须实现一个继承标准窗口的类。这个窗口类和标准窗口的区别就是,你可以往里面自己加点花样,比如,加一个button控件。

为了把控件放入窗口,必须先要创建一个从属于窗口的Panel,因为控件只能被放在wx:annel的实例上。
我想你可以这样理解:窗口是一个综合体,它有标题栏,最大最小化框,还有窗口区域等,实际能放button的地方只有窗口区域,所以我们要先得到这个可以放置控件的区域。这个区域呢,就被抽象为一个概念:Pannel。我们要先得到这个区域,就要用窗口作为参数,创建一个Panel的实例。

下面让我们看看实现代码,也就是例子2:


   =1= #!/usr/bin/perl -w
   =2= use strict;
   =3= use Wx;
   =4=
   =5= ###########################################################
   =6= #
   =7= # Extend the Frame class to our needs
   =8= #
   =9= package MyFrame;
  =10=
  =11= use base qw(Wx::Frame); # Inherit from Wx::Frame
  =12=
  =13= sub new
  =14= {
  =15=     my $class = shift;
  =16=     my $self = $class->;SUPER::new(@_); # call the superclass' constructor
  =17=
  =18=     # Then define a Panel to put the button on
  =19=     my $panel = Wx:anel->;new( $self,  # parent
  =20=                                 -1      # id
  =21=                               );
  =22=     $self->;{txt} = Wx::StaticText->;new( $panel,             # parent
  =23=                                         1,                  # id
  =24=                                         "A buttonexample.", # label
  =25=                                         [50, 15]            # position
  =26=                                        );
  =27=     $self->;{btn} = Wx::Button->;new(     $panel,             # parent
  =28=                                         1,                  # id
  =29=                                         ">;>;>; Press me <<<", # label
  =30=                                         [50,50]             # position
  =31=                                        );
  =32=     return $self;
  =33= }
  =34=
  =35= ###########################################################
  =36= #
  =37= # Define our ButtonApp class that extends Wx::App
  =38= #
  =39= package ButtonApp;
  =40=
  =41= use base qw(Wx::App);   # Inherit from Wx::App
  =42=
  =43= sub OnInit
  =44= {
  =45=     my $self = shift;
  =46=     my $frame = MyFrame->;new(    undef,         # Parent window
  =47=                                  -1,            # Window id
  =48=                                  'Button example', # Title
  =49=                                  [1,1],         # position X, Y
  =50=                                  [200, 150]     # size X, Y
  =51=                                );
  =52=     $self->;SetTopWindow($frame);    # Define the toplevel window
  =53=     $frame->;Show(1);                # Show the frame
  =54= }
  =55=
  =56= ###########################################################
  =57= #
  =58= # The main program
  =59= #
  =60= package main;
  =61=
  =62= my $wxobj = ButtonApp->;new(); # New ButtonApp application
  =63= $wxobj->;MainLoop;

第39行,还是惯例,我们实现了Wx::App的继承类,这次的名字叫ButtonApp。不过呢,这次我们在app里面创建的窗口不是标准窗口Wx::Frame,而是MyFrame。MyFrame是Wx::Frame的继承类(第9行)。

继承标准窗口类Wx::Frame,我们只必须override(重载)它的构造函数,就可以达到基本的目的。因为我们是实现Wx::Frame的扩展,所以呢,在重载的这个构造函数里面,我们要调用SUPERclass(超类/父类)的构造(第16行)。这样呢,标准窗口的一些基本机制就可以启动起来了。

大家思考一下。

Wx::App的继承不需要调用supperclass(父类)的构造,为什么Wx::Frame的继承却需要呢?

其实,你也可以在Wx::App的继承类的构造过程中调用父类构造,但是由于Wx::App的构造没做什么时候我们关注的事情,所以它的构造是不必要得。而Wx::Frame的构造中,可以想见,是做了很多有用的事情的,最基本的,就是创建了窗口,如果不调用父类构造,那么继承类的根基:窗口就没有创建。hehe。

然后呢,我们就可以实现我们自己针对Wx::Frame所作的扩展了,包括,第19行,我们创建了一个Panel,往Panel上添加一个StaticText(静态文本控件)(第19行)和一个Button(按钮控件)(第27行)。最后呢,我们需要返回$self(第32行),以便调用MyFrame->;new的地方可以得到我们这个窗口的实例。

正如你所见,我们把button和StaticText控件定义为了MyFrame的属性,我们用了$self->;{btn}这样的语句。但是这并不是必须的,不过如果我们需要添加interaction(互动)(事件处理)的时候,我们就必须这样做了,因为我们要在事件处理过程访问这些对象,所以不能使用局部变量定义这些对象,而用$self->;{btn}这样的方式把他们定义为MyFrame的属性,以便在MyFrame的其他地方可以访问这些对象。

现在,执行我们这第二个例子程序,it will look like this:



添加事件处理

不过这个例子可以做什么么?oh。nothing。hehe。

所以,我们下一步的目标是让程序可以实现和用户的互动,添加事件的处理。刚才我们说过了,为了在事件处理中访问对象,我们必须把button和StaticText或者其他窗口内对象的实例定义为MyFrame的属性。

看看我们的实现代码:



   =1= #!/usr/bin/perl -w
   =2= use strict;
   =3= use Wx;
   =4=
   =5= ###########################################################
   =6= #
   =7= # Extend the Frame class to our needs
   =8= #
   =9= package MyFrame;
  =10=
  =11= use Wx::Event qw( EVT_BUTTON );
  =12=
  =13= use base qw/Wx::Frame/; # Inherit from Wx::Frame
  =14=
  =15= sub new
  =16= {
  =17=  my $class = shift;
  =18=  
  =19=  my $self = $class->;SUPER::new(@_);  # call the superclass' constructor
  =20=
  =21=     # Then define a Panel to put the button on
  =22=  my $panel = Wx:anel->;new( $self,  # parent
  =23=                              -1      # id
  =24=                            );
  =25=
  =26=  $self->;{txt} = Wx::StaticText->;new( $panel,             # parent
  =27=                                      1,                  # id
  =28=                                      "A buttonexample.", # label
  =29=                                      [50, 15]            # position
  =30=                                     );
  =31=  
  =32=  my $BTNID = 1;  # store the id of the button in $BTNID
  =33=  
  =34=  $self->;{btn} = Wx::Button->;new(     $panel,             # parent
  =35=                                      $BTNID,             # ButtonID
  =36=                                      ">;>;>; Press me <<<", # label
  =37=                                      [50,50]             # position
  =38=                                     );
  =39=
  =40=  EVT_BUTTON( $self,          # Object to bind to
  =41=              $BTNID,         # ButtonID
  =42=              \&ButtonClicked # Subroutine to execute
  =43=             );
  =44=
  =45=  return $self;
  =46= }
  =47=
  =48= sub ButtonClicked
  =49= {
  =50=  my( $self, $event ) = @_;
  =51=  # Change the contents of $self->;{txt}
  =52=  $self->;{txt}->;SetLabel("The button was clicked!";
  =53= }
  =54=
  =55= ###########################################################
  =56= #
  =57= # Define our ButtonApp2 class that extends Wx::App
  =58= #
  =59= package ButtonApp2;
  =60=
  =61= use base qw(Wx::App);   # Inherit from Wx::App
  =62=
  =63= sub OnInit
  =64= {
  =65=     my $self = shift;
  =66=     my $frame = MyFrame->;new(   undef,         # Parent window
  =67=                                 -1,            # Window id
  =68=                                 'Button interaction example', # Title
  =69=                                 [1,1],         # position X, Y
  =70=                                 [200, 150]     # size X, Y
  =71=                                );
  =72=     $self->;SetTopWindow($frame);    # Define the toplevel window
  =73=     $frame->;Show(1);                # Show the frame
  =74= }
  =75=
  =76= ###########################################################
  =77= #
  =78= # The main program
  =79= #
  =80= package main;
  =81=
  =82= my $wxobj = ButtonApp2->;new(); # New ButtonApp application
  =83= $wxobj->;MainLoop;

这第三个例子和前面第二个例子的不同在于添加了事件处理部分。此例中,当你点击 button ,程序会将 StaticText 的文字改掉。让我们看看代码中的变化:

首先,我们use Wx::Event,并引入了EVT_BUTTON(第11行)。EVT_BUTTON是所有button事件的处理函数。还有其他很多类似的处理函数,但是此例中我们仅使用EVT_BUTTON。

第32行,我们定义了一个变量 $BTNID,用来保持 button 的 id。然后在40行,我们告诉 EVT_BUTTON 函数,在遇到窗口( $self,也就是 MyFrame )中 id = $BTNID 的控件时,调用一个名称为 ButtonClicked 的 callback (回调)函数。

在第48行,我们定义了 ButtonClicked 回调函数。

wxPerl中,所有的事件回调函数都有2个参数:第一个是事件发生的窗口对象,第二个是事件本身(事件也是一个对象)。本例中,我们不需要第二个参数,但是我们需要第一个。我们通过这个窗口对象,得到它的一个属性,$self->;{txt} ,这个属性就是我们在第26行创建的 StaticText 实例。我们调用 StaticText 的方法 SetLabel ,来改变它的显示文字(第52行)。

于是,我们的目的就达到了。当我们点击 Button 的时候,事件处理函数执行 ButtonClicked 回调, StaticText 控件的文字被改变。如图:



思考

本文的3个例子解释了wxPerl的基本运行机制。

下面我们来总结wxPerl程序的一个基本流程。

首先:
实现标准窗口的继承类(你可以实现n个不同的窗口),在继承类的构造函数中,添加你想要添加的控件,比如,button,menu,或者其他控件。然后通过wx::Event提供的一些方法,比如:EVT_BUTTON,定义特定事件的处理回调。然后,实现这个回调函数,实现事件的处理。

接下来,实现wx::App的继承类,在这个类中,我们生成窗口实例,并且把它显示出来。

最后,我们需要生成main程序段,调用wx::App->;new,wx::App->;mainloop,让wx程序run起来。

下面谈谈wx和MVC模式的问题。

在wx中,App负责程序的启动,结束,事件调度,分派,也就是Control。窗口类负责窗口和窗口内控件的实现,也就是View,同时定义事件处理。在实际程序中,你还要处理大量的业务逻辑,比如:数据库处理,可以将这块分离出来,定义数据处理package,负责Model。这样呢,你可以发现,wx基本上是一个MVC的机制。

当然,以上是我个人理解。关于其他人的观点,请参考:http://www.yesky.com/20010202/157459.shtml,他是针对mfc来说的。

如果你熟悉mfc,那么你可以发现,基本上2者的机制很多地方是类似的。EVT_*相当于事件映射的宏。wx::App对应为mfc的app,窗口类对应于mfc中的各种窗口。

结论

wxPerl. Start to use it,or forget it.

论坛徽章:
0
2 [报告]
发表于 2005-09-22 11:56 |只看该作者

wxPerl: Another GUI for Perl

不错哦。
不过,我从未在win下做过develop...

论坛徽章:
1
未羊
日期:2014-09-08 22:47:27
3 [报告]
发表于 2009-12-05 22:05 |只看该作者
下午搞了下Padre,发现wxWidgets的显示效果很优秀,真的很棒!!

论坛徽章:
0
4 [报告]
发表于 2009-12-05 22:21 |只看该作者
晕~才记起2005年就回过帖子~一晃4年多了~
win下写图形界面,MS很多工具吧,VB、delphi等。

论坛徽章:
1
未羊
日期:2014-09-08 22:47:27
5 [报告]
发表于 2009-12-06 10:16 |只看该作者
wxPerl的文档不多,还是几年以前的C++文档,缺少Perl接口的文档,不利于推广啊。不过从Padre的显示效果来看,效果很优秀,具备本地GUI外观,很不错。

论坛徽章:
20
CU大牛徽章
日期:2013-04-17 11:48:26羊年新春福章
日期:2015-03-10 22:39:202015年中国系统架构师大会
日期:2015-06-29 16:11:282015亚冠之平阳省
日期:2015-07-31 09:19:042015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-09-30 06:20:002015亚冠之柏太阳神
日期:2015-10-19 20:29:5915-16赛季CBA联赛之天津
日期:2016-11-29 14:03:4315-16赛季CBA联赛之北控
日期:2016-12-24 20:51:492015年辞旧岁徽章
日期:2015-03-03 16:54:15双鱼座
日期:2015-01-12 20:58:532014年中国系统架构师大会
日期:2014-10-14 15:59:00
6 [报告]
发表于 2009-12-06 10:42 |只看该作者
不错
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP