使用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
数组中各放一个项目,每个项目都有一个匿名哈希。
对于这些哈希,这次的type
是item
——一个普通菜单项,而不是子菜单的开始。菜单项在名称前有小图标。我们通过指定pixmap_type
是'stock'
来使用标准的GNOME图标库,并使用Menu_Quit
和Menu_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 上打开一个问题或拉取请求来解决问题。