文章目錄
- 0.1 本文常式:hello3
- 1.1 下載、安裝gladewin32
- 1.2 庫檔案和pkg-config
- 1.3 GTK工程
- 2.1 程式裡
- 2.2 程式外
Linux之旅(2): 你好,GTK (上)0 概述
網上有不少GTK的入門文章,例如:應用GTK+編程。本文同樣介紹一個Hello World程式,但涉及的知識點略有不同。
0.1 本文常式:hello3
本文常式是一個叫作hello3的小程式。GTK是一個跨平台的圖形庫,讓我們看看hello3在各平台的運行效果。
同一個軟體包可以在千差萬別的平台上編譯、運行,這就是GTK的世界。可以從這裡下載hello3的原始碼。
1 使用VC開發GTK程式
網上提到在Windows平台運行GTK,通常都會說cygwin、MinGW。其實,如果只用GTK的圖形庫,只要下載、安裝gladewin32,用VC就可以開發、調試GTK程式。
1.1 下載、安裝gladewin32
gladewin32是sourceforge上的一個開源項目。讀者可以從我的首頁下載本文使用的版本。在安裝gladewin32時可以選擇是否與VC6整合。所謂與VC6整合就是修改兩個登錄機碼,增加GTK的包含檔案目錄和庫檔案目錄(假設gladewin32的安裝目錄是C:/GTK):
- 在 HKEY_CURRENT_USER/Software/Microsoft/DevStudio/6.0/Build System/Components/Platforms/Win32 (x86)/Directories/Include Dirs 的前面加上: C:/GTK/INCLUDE;C:/GTK/INCLUDE/GTK-2.0;C:/GTK/INCLUDE/GLIB-2.0;C:/GTK/INCLUDE/PANGO-1.0;C:/GTK/INCLUDE/CAIRO;C:/GTK/INCLUDE/ATK-1.0;C:/GTK/INCLUDE/GTKGLEXT-1.0;C:/GTK/LIB/GTK-2.0/INCLUDE;C:/GTK/LIB/GLIB-2.0/INCLUDE;C:/GTK/LIB/GTKGLEXT-1.0/INCLUDE;C:/GTK/INCLUDE/LIBGLADE-2.0;C:/GTK/INCLUDE/LIBXML2;
- 在 HKEY_CURRENT_USER/Software/Microsoft/DevStudio/6.0/Build System/Components/Platforms/Win32 (x86)/Directories/Library Dirs 的前面加上: C:/GTK/LIB;
如果讀者使用VC7或VC8,可以直接在工程中設定包含檔案和庫檔案的附加目錄。安裝了gladewin32後,用VC開啟hello3.dsw,就可以編譯、運行、調試了。
1.2 庫檔案和pkg-config
不管使用什麼庫檔案,除了設定包含檔案目錄、庫檔案目錄,還需要設定連結哪些庫檔案,GTK也不例外。通常,我們只需要連結:
gtk-win32-2.0.lib glib-2.0.lib gobject-2.0.lib
如果用到了gdk函數,還要加上gdk-win32-2.0.lib。如果用到gettext,還要加上intl.lib。
在linux平台,我們通常用pkg-config工具自動產生包含檔案路徑和要連結的庫檔案。在windows環境也可以使用pkg-config,不過要先設定PKG_CONFIG_PATH,例如
set PKG_CONFIG_PATH=C:/GTK/lib/pkgconfig
然後再在C:/GTK/lib/pkgconfig目錄執行pkg-config。不過我使用的gladewin32版本會有一個錯誤提示:
pkg-config --cflags --libs gtk+-2.0
Package pixman-1 was not found in the pkg-config search path.
Perhaps you should add the directory containing `pixman-1.pc'
to the PKG_CONFIG_PATH environment variable
Package 'pixman-1', required by 'cairo', not found
修改C:/GTK/lib/pkgconfig/cairo.pc,去掉對pixman-1的依賴後,就可以了:
C:/GTK/lib/pkgconfig>pkg-config --cflags --libs gtk+-2.0
-mms-bitfields -IC:/GTK/include/gtk-2.0 -IC:/GTK/lib/gtk-2.0/include -IC:/GTK/include/atk-1.0 -IC:/GTK/include/cairo -IC:/GTK/include/pango-1.0 -IC:/GTK/include/glib-2.0 -IC:/GTK/lib/glib-2.0/include -IC:/GTK/include/freetype2 -IC:/GTK/include -Wl,-luuid -LC:/GTK/lib -lgtk-win32-2.0 -lgdk-win32-2.0 -limm32 -lshell32 -lole32 -latk-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lcairo -lpangoft2-1.0 -lpangowin32-1.0 -lgdi32 -lfreetype -lz -lfontconfig -lpango-1.0 -lm -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lintl
讀者可以按照pkg-config的輸出,在工程中把所有的庫都加上:
atk-1.0.lib cairo.lib fontconfig.lib freetype.lib gdk-win32-2.0.lib gdk_pixbuf-2.0.lib glib-2.0.lib gmodule-2.0.lib gobject-2.0.lib gtk-win32-2.0.lib intl.lib pango-1.0.lib pangocairo-1.0.lib pangoft2-1.0.lib pangowin32-1.0.lib z.lib
不過,我習慣用什麼加什麼。不報錯就不加。
1.3 GTK工程
在VC中使用GTK,只要建立一個win32控制台的空工程就可以了。如果在運行時,不希望有控制台視窗,只要在程式中加上:
#ifdef WIN32
#pragma comment( linker, "/subsystem:/"windows/" /entry:/"mainCRTStartup/"" )
#endif
在調試版本,我還是習慣保留控制台視窗,這樣可以看到g_print的輸出。雖然VC環境調試很方便,但在linux平台,列印輸出還是常用的調試手段。
2 在windows平台使用gettext
gettext是linux平台的標準國際化工具。使用gettext主要做兩件事情:
- 在程式裡,使用gettext庫處理需要翻譯的字串。這個過程通常稱作國際化。
- 在程式外,使用gettext相關工具產生、維護、翻譯字串資源。這個過程通常稱作本地化。
其實真正的國際化和本地化不僅僅是翻譯字串,還有考慮其它地區相關的問題。不過gettext只管文字翻譯。
gettext的原理很簡單。使用gettext宏包圍要翻譯的字串。gettext工具就可以從源檔案提取出這些字串,產生一個模板檔案(pot檔案)。翻譯者根據這個pot檔案做翻譯,產生po檔案。gettext工具根據po檔案產生gettext庫喜歡的二進位格式:mo檔案。gettext化的程式在運行時會根據系統當前語言設定到指定目錄去找指定名字的mo檔案。如果找到了,包圍每個字串的gettext宏就會根據mo檔案把源字串替換成當前語言要求的字串。如果找不到mo檔案,就用原來的字串。
2.1 程式裡
程式裡要做兩件事情:
- 在主程式中初始化gettext庫
- 定義一個gettext宏,需要翻譯的字串用這個宏處理後再用。
說得具體點,使用gettext後代碼有3處改動:
在檔案頭包含gettext的標頭檔,定義gettext宏:_(字串)。
#ifdef ENABLE_NLS
#include <libintl.h>
#define _(String) gettext(String)
#else
#define _(String) (String)
#endif
在主程式中初始化gettext庫:
#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
#endif
如果不是GTK程式,在調用bindtextdomain前還要加一句:
setlocale(LC_ALL, "");
GETTEXT_PACKAGE確定mo檔案的名字。PACKAGE_LOCALE_DIR確定mo檔案的位置。
用gettext宏包圍每個需要翻譯的字串。例如:
button = gtk_button_new_with_label(_("Hello World!"));
在linux環境,ENABLE_NLS、GETTEXT_PACKAGE、PACKAGE_LOCALE_DIR都可以用組態工具(Autotool)產生。在VC環境,我們不想用Autotool,可以直接定義它們,例如:
#ifdef WIN32
#define ENABLE_NLS
#define GETTEXT_PACKAGE "hello3"
#define PACKAGE_LOCALE_DIR "./locale"
#endif
將GETTEXT_PACKAGE定義為"hello3",gettext函數就會去找“hello.mo”。將PACKAGE_LOCALE_DIR定義為"./locale",在簡體中文環境,gettext函數就會在“./locale/zh_CN/LC_MESSAGES”目錄尋找mo檔案。
2.2 程式外
在程式外,我們要維護字串資源。在linux環境,我們通常不需要直接使用gettext工具,Autotool通過intltool指令碼和Makefile把我們料理好所有雜事,我們只要維護要翻譯的檔案清單(POTFILES.in),翻譯po檔案就可以了。在windows平台,我寫了兩個批次檔簡化操作。
2.2.1 update-po.bat
update-po.bat的內容如下:
@echo off
xgettext -k_ -o hello3.pot ../src/main.c
msgmerge -o zh_CN.po zh_CN.po hello3.pot
xgettext根據源檔案產生模板檔案(pot檔案)。如果現在還沒有po檔案,可以將pot檔案複製一份,尾碼改成po,然後填寫檔案頭,翻譯字串。在大多數情況下,我們已經有了po檔案,然後來源程式又變化了。我們用xgettext產生新的pot檔案後,用msgmerge將新的pot檔案合并到原來的po檔案中。已經翻譯的部分當然不用重新翻譯了。
2.2.2 update-mo.bat
update-mo.bat的內容如下:
@echo off
if not exist ../output/locale/zh_CN/LC_MESSAGES mkdir ../output/locale/zh_CN/LC_MESSAGES
msgfmt -o ../output/locale/zh_CN/LC_MESSAGES/hello3.mo zh_CN.po
首先看看放mo檔案的目錄有沒有準備好,沒有就建一個。然後用msgfmt根據po檔案產生mo檔案,並放到指定目錄。
2.2.3 翻譯
GTK內部的字串都是UTF-8編碼。GTK項目的po檔案通常都採用UTF-8編碼。我們可以用任何支援UTF-8編碼的編輯器編輯po檔案。但我更喜歡用專門的工具poedit。
很好用。
2.2.4 流程
綜上所述,在改動了源檔案後,本地化流程如下:
- 雙擊update-po.bat,更新po檔案。
- 雙擊po檔案,在poedit裡看看有沒有需要翻譯的。需要就翻譯、儲存。
- 雙擊update-mo.bat,產生新的mo檔案。
在windows平台使用GTK庫就是這麼簡單,不用makefile、也不用Autotool。下面,我們先看看hello3的代碼有什麼值得說說的東西,然後再看看在linux環境編譯、運行hello3是不是更加簡單。