使用Perl编写GNOME应用程序

目录

架构简介
你好,世界
添加菜单栏
添加关于框
添加更多组件
最终程序

GNOME是Unix桌面环境。它是一个用于使用Unix编写图形应用程序的框架,提供拖放、应用程序间通信、CORBA组件(在Windows世界中被称为“OLE”)标准、美观的界面,以及现代图形应用程序应有的所有其他功能。

而且它对Perl也适用,这意味着Perl程序员也可以创建真正酷炫的应用程序。但是有一个小小的障碍...

    % perldoc GNOME
    No documentation found for "GNOME".

我最近需要编写一个GNOME应用程序并遇到了这个障碍,我不得不几乎完全自己解决这个问题。所以,我决定编写这些教程,以便亲爱的读者您不需要这样做。在本期的第一部分,我们将创建一个非常简单的应用程序,但一个具有完整、标准GNOME界面的应用程序。

架构简介

GNOME是一个复杂的野兽,由许多不同的库和组件组成。幸运的是,对于本教程和您的大部分编程,您只需要了解两部分:GTK+和GNOME。

您可能听说过Tk,这是Perl人们使用的“其他”图形工具包。Tk在生活中的作用是做辛苦的工作,与X服务器通信并告诉它如何绘制按钮、菜单、控件和对话框,然后在用户操作后触发Perl例程。它是X服务器原始强大功能和Perl舒适之间的中介。

GTK+执行类似的工作,但它做得更美。GTK+将为我们提供所有窗口、按钮、文本标签、文本输入,以及我们应用程序的所有图形元素。它还将提供主要事件循环,将用户的操作与我们的代码连接起来。

GNOME库在GTK+之上提供了一个额外的抽象层,为我们提供了更高级的图形对象,例如主应用程序窗口、关于框、按钮面板、对话框、颜色和字体选择框,并且它还提供了“胶水”来与其他GNOME环境部分交互 - 拼写检查器、计算器和来自其他应用程序的资源。

  • 在这个阶段,指出以下几点是值得的:有一个名为Glade的GNOME Visual Basic风格的拖放IDE,它可以生成Perl代码,有些人可能会发现使用它构建应用程序要容易得多;然而,您应该继续阅读,以便了解Glade生成的代码实际上做了什么。

你好,世界

我们将展示经典“你好,世界”应用程序的两个版本:首先是一个仅使用GTK+的版本,然后是一个GNOME版本。

以下是GTK+版本

   1 #!/usr/bin/perl -w
   2
   3 use strict;
   4 use Gnome;
   5 
   6 my $NAME = 'Hello World';
   7
   8 init Gnome $NAME;
   9
  10 my $w = new Gtk::Window -toplevel;
  11
  12 my $label = new Gtk::Label "Hello, world";
  13 $w->add($label);
  14
  15 show_all $w;
  16 
  17 main Gtk;

在第4行,我们加载主要的GNOME模块;这将为我们加载GTK+模块。第8行设置本会话所需的一切并注册应用程序。我们将应用程序的名称传递给init方法。

在第10行,我们创建了主窗口。这是一个顶级窗口,意味着它不是任何其他窗口的子窗口。接下来,我们需要创建一个消息标签,上面会显示“Hello, world”;任何我们想在窗口上放置的文本都必须在Gtk::Label对象中,因此我们创建了一个对象,并将其放入$label中。现在,到第12行,这个标签没有任何作用 - 它已经被创建,但没有地方放置。我们希望它在我们的窗口上显示,所以调用窗口的add方法并将标签对象添加进去。

接下来,我们决定程序开始时要显示什么。我们将显示窗口及其所有附加内容 - 在我们的例子中,是标签。所以,我们调用窗口的show_all方法。请注意,这实际上并没有把窗口放到屏幕上;它只是指定了初始要显示的内容。

最后,启动动作的语句是main Gtk; - 这将控制权传递给GTK+的主事件循环,它会首先在屏幕上绘制窗口和标签,然后等待发生某些事情。

  • 一旦我们调用main Gtk;,我们的程序就放弃了控制权 - 之后发生的一切都是对用户操作的响应。与程序员控制程序做什么的常规过程式方法不同,我们现在必须采取被动、反应式的方法,对用户的行为做出响应。我们这样做的方式是通过回调,我们将在稍后看到一些示例。但重要的是要注意,main Gtk;是我们的工作结束而GTK+的工作开始的地方。

接下来,这是Gnome版本

     1  #!/usr/bin/perl -w
     2  
     3  use strict;
     4  use Gnome;
     5  
     6  my $NAME = 'Hello World';
     7  
     8  init Gnome $NAME;
     9  
    10  my $app = new Gnome::App $NAME, $NAME;
    11  
    12  my $label = new Gtk::Label "Hello, world";
    13  $app->set_contents($label);
    14  
    15  show_all $app;
    16  
    17  main Gtk;

它们的长度相同,大部分内容也相同。这是我们改变的内容

    10  my $app = new Gnome::App $NAME, $NAME;

我们不再创建一个窗口,我们现在提升了一个级别,表示我们正在创建一个完整的应用程序。我们将应用程序的名称传递给new方法两次 - 一次作为窗口的标题,一次用于将其注册到GNOME环境中。

我们还改变了添加标签到窗口的行

    13  $app->set_contents($label);

为什么这里写的是“set contents”而不是“add”?答案在于GTK+将图形元素(“小部件”)放入窗口的方式,这是基于容器思想。简单地说,窗口中只能有一个小部件;幸运的是,一些小部件可以包含其他小部件。我们上面说的是,这个窗口的主要内容,我们允许的唯一小部件,是标签。

现在,如果你使用窗口管理器的“关闭”按钮退出这些示例,你可能会注意到Perl应用程序并没有结束;我们必须使用^C或类似的方法从中退出。当一个GNOME应用程序收到窗口管理器的通知,表示它应该关闭时,GNOME会给我们发送一个信号;这不是内核实现的真正Unix信号,而是一个GNOME信号,这是GNOME的一个特性。我们需要捕获这个信号并安装一个信号处理程序,以干净地关闭程序。下面是如何做这个的

    my $app = new Gnome::App $NAME, $NAME;
    signal_connect $app 'delete_event',
                         sub { Gtk->main_quit; return 0 };

我们正在连接一个处理程序到“删除事件”信号,它告诉我们要清理并回家,我们用一个匿名子程序来捕获它。这个子程序调用GTK+的main_quit方法,终止主循环。

现在我们的应用程序应该可以干净地关闭。但它仍然没有做什么。

添加菜单栏

正如我之前提到的,GNOME比GTK+的优势在于,大多数我们期望的应用程序的标准功能都已经为我们准备好了。让我们为我们的应用程序创建一些标准菜单。在signal_connect行之后添加以下内容

      $app->create_menus(
        {type => 'subtree',
         label => '_File',
         subtree => [
                {type => 'item',
                 label => 'E_xit',
                 pixmap_type => 'stock',
                 pixmap_info => 'Menu_Quit'
                }
                    ]
        },
        {type => 'subtree',
         label => '_Help',
         subtree => [
                {type => 'item', 
                 label => '_About...',
                 pixmap_type => 'stock',
                 pixmap_info => 'Menu_About'
                }
                    ]
        }
      );

我们将一系列匿名哈希传递给create_menus,每个哈希对应我们要创建的每个主菜单标签。每个标签的subtree类型表示在该标签下还将有其他菜单。在label选项中,我们在要作为菜单项快捷键的字符前加上下划线;Alt-F将打开文件菜单。subtree选项是一个菜单项的匿名数组;在这里,我们在我们的两个subtree数组中各放一个项目,每个项目都有一个匿名哈希。

对于这些哈希,这次的typeitem——一个普通菜单项,而不是子菜单的开始。菜单项在名称前有小图标。我们通过指定pixmap_type'stock'来使用标准的GNOME图标库,并使用Menu_QuitMenu_About获取适合在菜单中显示的标准退出和“关于”图标。

如果您再次运行应用程序,应该会看到一个菜单栏。现在,想看到一些真正令人印象深刻的东西吗?我说GNOME为您做了所有的工作。试试这个

   LANG=fr_FR perl hello.pl

如果一切顺利,菜单应该会出现——但这次是翻译成法语。那段代码在哪里?GNOME做到了。尝试其他几种——pt_PT用于葡萄牙语,de_DE用于德语,el_GR(如果您有相应的字体)用于希腊语。神奇!

不过,有一个小问题:我们的菜单没有任何功能。让我们先修复一下退出项目,因为我们已经知道如何关闭GTK+应用程序。更改项目哈希,使其看起来像这样

                {type => 'item',
                 label => 'E_xit',
                 pixmap_type => 'stock',
                 pixmap_info => 'Menu_Quit',
                 callback => sub {Gtk->main_quit; return 0 }
                }

我们说的是,当菜单项被选中时,GNOME应该通过执行我们提供的代码来“调用我们”。我们指定一个子程序引用,当用户选择该项目时将被调用。

添加关于框

现在让我们通过添加一个关于框来修复另一个菜单项。同样,GNOME已经为我们做了这项工作。我们将添加一个回调到About...菜单选项,并将其设置为子程序引用

                {type => 'item',
                 label => '_About...',
                 pixmap_type => 'stock',
                 pixmap_info => 'Menu_About',
                 callback => \&about_box
                }

我们的子程序将创建并显示该框

           sub about_box {
               my $about = new Gnome::About $NAME, "v1.0",
                  "(C) Simon Cozens, 2000", ["Simon Cozens"],
                "This program is released under the same terms as Perl itself";
             show $about;
         }

Gnome::About类为我们提供了一个现成的关于框:我们只需要提供应用程序的名称、版本、版权信息、作者名称的匿名数组以及任何其他注释。然后我们就像显示主窗口一样显示该框。当我们点击“确定”按钮时,窗口将自动移除。

添加更多装饰

GNOME应用程序还有两个其他独特的界面特性:工具栏和状态栏。我们首先添加工具栏。在菜单代码之后放置此内容

   $app->create_toolbar(
    {
        type => 'item',
        label => 'Exit',
        pixmap_type => 'stock',
        pixmap_info => 'Quit',
        hint => "Click here to quit",
        callback => sub { Gtk->main_quit },
    }, {
        type => 'item',
        label => 'About...',
        pixmap_type => 'stock',
        pixmap_info => 'About',
        hint => "More information about this app",
        callback => \&about_box
    }
   );

我们再次传递一系列匿名哈希,其中大部分条目现在应该对您来说很熟悉。hint是在鼠标指针悬停在按钮上时显示的内容。我们的回调和位图与之前相同。

接下来是状态栏

    my $bar = new Gnome::AppBar 0,1,"user" ;
    $bar->set_status("   Welcome   ");

    $app->set_statusbar( $bar );

首先,我们创建一个新的AppBar对象,一个应用程序状态栏。然后我们使用set_status方法将其初始状态写入。同样,这个栏现在存在,但它在屏幕上没有位置,因此它不会显示。我们使用应用程序的set_statusbar方法将其连接到应用程序,它现在将出现在主窗口的底部。

最终程序

在本教程结束时,您应该得到以下内容

    #!/usr/bin/perl -w

    use strict;
    use Gnome;

    my $NAME = 'Hello World';

    init Gnome $NAME;

    my $app = new Gnome::App $NAME, $NAME;

    signal_connect $app 'delete_event', sub { Gtk->main_quit; return 0 };

    $app->create_menus(
               {type => 'subtree',
                label => '_File',
                subtree => [
                    {type => 'item',
                     label => 'E_xit',
                     pixmap_type => 'stock',
                     pixmap_info => 'Menu_Quit',
                     callback => sub { Gtk->main_quit; return 0 }
                    }
                       ]
               },
               {type => 'subtree',
                label => '_Help',
                subtree => [
                    {type => 'item', 
                     label => '_About...',
                     pixmap_type => 'stock',
                     pixmap_info => 'Menu_About',
                     callback => \&about_box
                    }
                       ]
               }
              );

    $app->create_toolbar(
                 {
                  type => 'item', 
                  label => 'Exit', 
                  pixmap_type => 'stock', 
                  pixmap_info => 'Quit', 
                  hint => "Click here to quit",
                  callback => sub { Gtk->main_quit }, 
                 }, {
                 type => 'item',
                 label => 'About...', 
                 pixmap_type => 'stock',
                 pixmap_info => 'About',
                 hint => "More information about this app",
                 callback => \&about_box
                }
                );

    my $label = new Gtk::Label "Hello, world";
    $app->set_contents($label);

    my $bar = new Gnome::AppBar 0,1,"user" ;
    $bar->set_status("   Welcome   ");
    $app->set_statusbar( $bar );

    show_all $app;

    main Gtk;

    sub about_box {
      my $about = new Gnome::About $NAME, "v1.0", 
      "(C) Simon Cozens, 2000", ["Simon Cozens"], 
      "This program is released under the same terms as Perl itself";
      show $about;
    }


=head1 Summary

所以,我们现在已经使用GNOME/Perl创建了我们第一个应用程序。它符合GNOME界面标准,它有标准菜单、工具栏、状态栏和关于框。它看起来、感觉和表现都像真正的GNOME应用程序,全部只需要约70行Perl代码。

下次,我们将开始创建一个更有用的应用程序,一个食谱组织者,我们将使用一些更复杂的控件,如容器、输入区域、滚动条和列表框。

标签

反馈

这篇文章有什么问题吗?请帮助我们通过在 GitHub 上打开一个问题或拉取请求来解决问题。