GNOME 是一個 UNIX 下的桌面系統,它提供了在 Unix 下編寫圖形程序的環境,支持鼠標拖放,程序間通信,CORBA 組件(也就是在 Windows 里面的 OLE),CORBA 組件是一組標準的,美觀的編程接口,以及所有其它現代的圖形應用程序應該包含的特征。所有這些都能在 Perl 的完成,也就是 Perl 程序員能夠用GNOME 庫來編寫整潔漂亮的應用程序,但是這兒也有一點小小的問題。。。
% perldoc GNOME No documentation found for "GNOME".沒有GNOME編程的幫助文檔!。我最近需要寫一個基于 GNOME 庫的圖形界面應用程序,就遇到了這個問題。我不得不自己解決所有的問題。所以我寫了這個教程,來幫助親愛的讀者朋友,使你們不用也事事親為。首先,放松一下,我們將創建一個極為簡單,但是卻很完整,很標準的 GNOME 應用程序。
GNOME系統構成簡介:
整個 GNOME 系統非常的復雜,由很多的庫和組件組成。幸運的是,教學及日常大部分的程序,你都只需要知道其中的兩個部分: GTK+ 和 GNOME.
可能你已經聽說過了 TK,另一個 Perl 程序員經常用到的圖形工具庫.Tk 所扮演的角色主要是與 X 窗口服務器通信,告訴它怎樣畫一個按鈕,菜單,控制欄,對話框等,根據用戶的點擊情況執行相應的 Perl 子程序.Tk庫一方面用到了 Perl 的便捷,另一方面又不得不與雖然強大但是卻很原始難懂的X窗口系統打交道.
GTK+ 也完成相似的任務,但是卻更簡單。GTK+ 提供所有的窗口,按鈕,文本標記,文本輸入框,一切我們的程序用的到的圖形控件。而且,嚴格的說還提供主窗口事件等待循環,以便監視用戶的動作。
GNOME 庫則在 GTK+ 的基礎上進行了更高一個層次的抽象,為我們提供更高層的圖形對象,比如主應用程序窗口,彈出窗口,按鈕板,對話框,顏色字體選擇器,甚至還提供與GNOME環境中其它部分的粘合交互通信,比如拼寫檢查,計算器及其它應用程序資源。
* 這里值得指出,有一個VB風格的集成圖形編程環境,叫 Glade,支持像 VB 一樣拖放控件。它能自動產生 Perl 代碼,用 Glade 你會發現開發圖形界面十分簡單,但是我們還是建議你應該把這個教程看下去,這樣你才能看懂那些產生的 perl 代碼。Hello,World
這里我們展示經典的 “Hello,World” 程序的兩個版本,一個用 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;
在第四行,裝載 Gnome 模塊,這樣就將一并裝載其下的 GTK+ 模塊。第八行注冊并初始化這個程序,分配我們在該程序中需要的資源,init 語句后面根這個程序的標題,它將顯示在標題欄。
在第十行,創建主窗口,也就是最頂層的窗口,它不是任何其它組件的子窗口。然后,我們創建內容為 “Hello,world” 的消息文本標簽,任何我們想要在窗口中顯示的文本都必須是派生于 Gtk::Label 對象的實例,在第十二行我們就是這樣做的,并把派生的實例命名為 $label。但是僅僅是第十二行的一條語句沒有任何作用,它僅僅創建了文本,卻不能顯示在任何地方顯示出來。未了在窗口中顯示它,我們必須用窗口的 add 方法把這個標簽實例添加到待顯示列。
然后,我們決定在程序啟動的時候應該顯示上面。如果我們想要顯示窗口中包含的所有的東西,在這里也就是那個消息文本標簽,我們就需要調用窗口的 show_all 方法。注意,調用了 show_all 后窗口仍不會被顯示,show_all 方法只是申明了程序運行的時候待顯示的內容。
最后,main Gtk 這條語句將把程序的控制權交給 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;
和上面的Gtk+版一樣長,而且大部分語句都是一樣的,下面這處有改動:
10 my $app = new Gnome::App $NAME, $NAME;不象在Gtk+中我們申明創建一個窗口,在這里我們從更高一層聲明創建一整個程序。把程序的名稱傳遞給 new,而且傳遞了兩個。第一個是作為窗口的標題,第二個則是在 GNOME 的環境中對該程序進行注冊。 把文本標簽添加到窗口的語句也有變化:
13 $app->set_contents($label);
為什么在這里用 set_content 方法而不用 add 方法呢?這是由 GTK+ 把圖形元素(也就是控件)顯示在窗口中的方法決定的,GTK+ 如何顯示圖形元素由包含該圖形元素的上一層元素,或稱容器決定。通常,一個窗口只能放一個控件。但幸運的是很多控件都能自身包含其它的控件。而我們上面的那條語句則是申明,在窗口中只能放置文本標簽類控件。 到現在你可能已經注意到了一點,當你用 GTK+ 編寫好程序并運行它,然后點擊程序中的退出按鈕你卻并不能退出,而不得用 Ctrl+C 或類似的強制方法退出。GNOME 中不存在這樣的問題。當 GNOME 程序從窗口管理器中收到退出的通知時,它會給自己發送一個信號,當然不是 UNIX 內核中發送的那種信號,而是純粹的 GNOME 特色的信號。我們需要捕捉這個信號,并且給這個信號編寫一個相應的信號處理程序來退出程序。下面的語句就是完成這個功能:
my $app = new Gnome::App $NAME, $NAME;
signal_connect $app 'delete_event',
sub { Gtk->main_quit; return 0 };
我們指定了一個程序來處理 “delete event“ 信號,“delete event”信號意味這退出當前子程序,返回上一級程序。我們用一個匿名子程序來捕捉并處理它—-GTK+ 中的 main_quit 方法,這個方法將終止程序的主事件等待循環。
現在我們的程序就會完全的退出了。但是現在這個程序還不能做什么。
添加菜單條像前面提到的,GNOME 優于 GTK+ 的地方在于,它提供更多我們在應用程序中需要用到的標準控件?,F在來為我們的程序添加一個標準的菜單。在 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就將打開菜單的 File 項。subtree 關鍵字的值其實可以是一個包含很多匿名散列的匿名數組,但是上面的程序段中,兩個 subtree 關鍵字的值我們都只指定了一個匿名散列。
表征子項的散列中的 type 關鍵字都被賦于“item”,表示該子項為一個普通項,不像它的上一級包含子菜單。菜單的每個選項都可以有自己的圖標。這里通過 “pixmap_type=>stock” 語句我們調用了 GNOME 自帶的圖標庫,我們還用了 Menu_Quit 和 Menu_About 方法來實現標準的退出的彈出窗口功能。
現在,重新運行你的程序,你就將會看到菜單條了。還想來點特別炫的東西嗎?我說過 GNOME 可以為你做到一切。用下面的語句啟動程序:LANG=fr_FR perl hello.pl
一切仍然正常,仍有菜單條,但是文字卻變成了法語!實現這個轉變的代碼在哪里呢?GNOME 為你做了一切。LANG 后根pt_PT就將變成葡萄牙語,跟 de_DE 就將變成德語,跟 el_GR (如果你有那個字庫的話)就將變成希臘語。神奇吧! 這里還有一個小問題:那個菜單好像出來能看不能用。由于我們已經知道了如何退出一個 GTK+ 程序,那么讓我們首先讓菜單的Exit項起作用。把這個菜單項的散列內容照下面修改:
{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 => chunk73189886chunk#38;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 類可以創建彈出窗口的實例:在這里我們給彈出窗口傳遞了我們程序的名稱,版本,版權信息,作者的姓名和其它評論。然后用顯示主窗口用到的 show 方法來同樣顯示這個彈出窗口。當點擊 “OK” 按鈕的時候,這個彈出窗口就關閉。
添加更多的東西
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 => chunk73189426chunk#38;about_box
}
);
我們同樣給 creat_toolbar 函數傳遞了一系列的匿名散列,而且散列的很多關鍵值都是你熟悉的。hint 關鍵值的內容定義當鼠標旋停在按鈕上的時候顯示的內容。而每個選項綁定的處理函數和選項的圖標都和前面一樣。 接著添加狀態欄:
my $bar = new Gnome::AppBar 0,1,"user" ;
$bar->set_status(" Welcome ");
$app->set_statusbar( $bar );
首先,創建一個 AppBar 實例,它是一個程序的狀態欄。然后用 set_status 定義狀態欄的初始信息。狀態欄到現在就已經存在了,但是還不會在屏幕上被顯示出來。因為還沒有指定它是屬于整個 GNOME 環境中那個應用程序。所以我們用 set_statusbar 方法給它指定歸屬?,F在它就會在主窗口中顯示出來了。
完整程序清單
下面是讀完這個教程,一步步按照我們說的做所應該生成的程序清單:
#!/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 => chunk73189196chunk#38;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 => chunk73189196chunk#38;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 應用程序??偣仓挥写蠹s 70 行 Perl 代碼。
下一次,我們會創建一個更有用的應用程序,一個食譜管理器。在里面我們將會用到一些稍微復雜一些的控件,比如容器,文本輸入域,滾動條和列表框。