Gtk+2 Hello World:从源码到打包发布

时间:2022-06-16 09:33:19

1.创建源代码

[zechen11@Arch ~]$ mkdir hello
[zechen11@Arch ~]$ cd hello
[zechen11@Arch hello]$ gvim helloGTK.c

 源码如下:

#include <gtk/gtk.h>

/* 这是一个回调函数。data 参数在本例中被忽略
 * 后面有更多的回调函数示例。 */
void hello( GtkWidget *widget, gpointer data )
{
    g_print("Hello GTK!\n");
}

gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
    /* 如果你的 "delet_event" 事件处理函数返回 FALSE, GTK 会发出 "destroy" 信号
     * 如果你不希望关闭窗口,请返回TRUE。
     * 当你想弹出”你确定要退出吗?“对话框时它很有用。 */ 
    
    g_print("delete event occurred\n");

    /* 改 TRUE 为 FALSE 程序会关闭。 */

    return TRUE;
}

/* 另一个回调函数 */
void destroy( GtkWidget *widget, gpointer data )
{
    gtk_main_quit();
}

int main( int argc, char *argv[] )
{
    /* GtkWidget 是构件的存储类型 */
    GtkWidget * window;
    GtkWidget * button;

    /* 这个函数在所有的 GTK 程序都要调用。
     * 参数由命令行中解析出来并且送到该程序中 */
    gtk_init( &argc, &argv );

    /* 创建一个新窗口 */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    /* 当窗口收到 "delete_event" 信号(这个信号由窗口管理器发出,通常是“关闭”
     * 选项或是标题栏上的关闭按钮发出的),我们让它调用在前面定义的
     * delete_event() 函数。
     * 如果传给回调函数的 data 参数值时 NULL,它会被回调函数忽略。 */
    g_signal_connect(G_OBJECT(window), "delete_event",
                    G_CALLBACK(delete_event), NULL);

    /* 在这里我们连接 "destroy" 事件到一个信号处理函数。
     * 对这个窗口调用 gtk_widget_destory() 函数或在 "delete_event" 回调函数中
     * 返回 FALSE 值都会触发这个事件。 */
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

    /* 设置窗口边框的宽度。 */
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    /* 创建一个标签为 "Hello GTK" 的新按钮。 */
    button = gtk_button_new_with_label("Hello GTK");

    /* 当按钮收到 "clicked" 信号时会调用 hello() 函数,并将 NULL 传给它作为参数
     * hello() 函数在前面定义了。 */
    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(hello), NULL);

    /* 当点击按钮时,会通过调用 gtk_widget_destroy(window)来关闭窗口。
     * "destroy" 信号会从这里或从窗口管理器发出。 */
    g_signal_connect_swapped(G_OBJECT(button), "clicked",
                            G_CALLBACK(gtk_widget_destroy), window);

    /* 把按钮放入窗口(一个 gtk 容器中)。 */
    gtk_container_add(GTK_CONTAINER(window), button);

    /* 最后一步是显示新创建的按钮和窗口 */
    gtk_widget_show(button);
    gtk_widget_show(window);
    
    /* 所有的 GTK 程序必须有一个 gtk_main() 函数。程序运行停在这里
     * 等待事件(如键盘事件或鼠标事件)的发生。 */
    gtk_main();

    return 0;
}

2.编译试试看

[zechen11@Arch hello]$ gcc -Wall -g helloGTK.c -o helloGTK `pkg-config --cflags --libs gtk+-2.0`
[zechen11@Arch hello]$ ./helloGTK
Hello GTK!

3.国际化编程

 3.1.加入头文件支持

#include <libintl.h>        /* gettext支持 */
#include <locale.h>         /* locale支持 */

 3.2.加入宏定义

#define PACKAGE "helloGTK"     /* 软件包名 */
#define LOCALEDIR "./locale"    /* locale所在目录 */
#define _(string)   gettext(string)
#define N_(string)  string

 3.3.在主函数中加入相关函数

    /* 用来设定国际化翻译包所在位置 */
    bindtextdomain(PACKAGE, LOCALEDIR);
    /* 用来设定国际化翻译包名称,省略了.mo */
    textdomain(PACKAGE);

 3.4.修改相关字符串

将代码中需要国际化--即多语言输出的字符串改写为_()宏。

完成上述所有修改后,代码如下:

#include <gtk/gtk.h>
#include <libintl.h>        /* gettext支持 */
#include <locale.h>         /* locale支持 */

#define PACKAGE "helloGTK"     /* 软件包名 */
#define LOCALEDIR "./locale"    /* locale所在目录 */
#define _(string)   gettext(string)
#define N_(string)  string

/* 这是一个回调函数。data 参数在本例中被忽略
 * 后面有更多的回调函数示例。 */
void hello( GtkWidget *widget, gpointer data )
{
    g_print(_("Hello GTK!\n"));
}

gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
    /* 如果你的 "delet_event" 事件处理函数返回 FALSE, GTK 会发出 "destroy" 信号
     * 如果你不希望关闭窗口,请返回TRUE。
     * 当你想弹出”你确定要退出吗?“对话框时它很有用。 */ 
    
    g_print(_("delete event occurred\n"));

    /* 改 TRUE 为 FALSE 程序会关闭。 */

    return TRUE;
}

/* 另一个回调函数 */
void destroy( GtkWidget *widget, gpointer data )
{
    gtk_main_quit();
}

int main( int argc, char *argv[] )
{
    /* 用来设定国际化翻译包所在位置 */
    bindtextdomain(PACKAGE, LOCALEDIR);
    /* 用来设定国际化翻译包名称,省略了.mo */
    textdomain(PACKAGE);
    /* GtkWidget 是构件的存储类型 */
    GtkWidget * window;
    GtkWidget * button;

    /* 这个函数在所有的 GTK 程序都要调用。
     * 参数由命令行中解析出来并且送到该程序中 */
    gtk_init( &argc, &argv );

    /* 创建一个新窗口 */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    /* 当窗口收到 "delete_event" 信号(这个信号由窗口管理器发出,通常是“关闭”
     * 选项或是标题栏上的关闭按钮发出的),我们让它调用在前面定义的
     * delete_event() 函数。
     * 如果传给回调函数的 data 参数值时 NULL,它会被回调函数忽略。 */
    g_signal_connect(G_OBJECT(window), "delete_event",
                    G_CALLBACK(delete_event), NULL);

    /* 在这里我们连接 "destroy" 事件到一个信号处理函数。
     * 对这个窗口调用 gtk_widget_destory() 函数或在 "delete_event" 回调函数中
     * 返回 FALSE 值都会触发这个事件。 */
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

    /* 设置窗口边框的宽度。 */
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    /* 创建一个标签为 "Hello GTK" 的新按钮。 */
    button = gtk_button_new_with_label(_("Hello GTK"));

    /* 当按钮收到 "clicked" 信号时会调用 hello() 函数,并将 NULL 传给它作为参数
     * hello() 函数在前面定义了。 */
    g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(hello), NULL);

    /* 当点击按钮时,会通过调用 gtk_widget_destroy(window)来关闭窗口。
     * "destroy" 信号会从这里或从窗口管理器发出。 */
    g_signal_connect_swapped(G_OBJECT(button), "clicked",
                            G_CALLBACK(gtk_widget_destroy), window);

    /* 把按钮放入窗口(一个 gtk 容器中)。 */
    gtk_container_add(GTK_CONTAINER(window), button);

    /* 最后一步是显示新创建的按钮和窗口 */
    gtk_widget_show(button);
    gtk_widget_show(window);
    
    /* 所有的 GTK 程序必须有一个 gtk_main() 函数。程序运行停在这里
     * 等待事件(如键盘事件或鼠标事件)的发生。 */
    gtk_main();

    return 0;
}

 3.5.生成po翻译文件

[zechen11@Arch hello]$ xgettext -k_ -o helloGTK.po helloGTK.c
xgettext: Non-ASCII comment at or before helloGTK.c:23.
Please specify the source encoding through --from-code.

文件编码不对,在命令中用 --from-code指定

[zechen11@Arch hello]$ xgettext -k_ --from-code=utf-8 -o helloGTK.po helloGTK.c

 3.6.修改po文件

命令生成的helloGTK.po文件如下

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-11-10 23:56+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: helloGTK.c:14
msgid "Hello GTK!\n"
msgstr ""

#: helloGTK.c:23
msgid "delete event occurred\n"
msgstr ""

#: helloGTK.c:69
msgid "Hello GTK"
msgstr ""

msgid后面的内容为英文,msgstr后面的内容为翻译的中文,同时要将第17行中的CHARSET字段改为文件编码即utf-8

修改该后的helloGTK.po文件如下:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-11-10 23:56+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: helloGTK.c:14
msgid "Hello GTK!\n"
msgstr "你好GTK!\n"

#: helloGTK.c:23
msgid "delete event occurred\n"
msgstr "删除事件发生\n"

#: helloGTK.c:69
msgid "Hello GTK"
msgstr "你好 GTK"

 3.7.生成helloGTK.mo文件

[zechen11@Arch hello]$ msgfmt -o helloGTK.mo helloGTK.po

这样程序在运行时就能根据当前locale的设定来正确读取mo文件中的数据,从而显示关语言的信息了。

 3.8.将mo文件移动到程序设定的位置

关于.mo文件的位置,本程序设 在./locale目录下的中文目录zh_CN下的LC_MESSAGES目录下,即./locale/zh_CN/LC_MESSAGES 目录下。将此步骤生成的mo文件复制到相应的目录下,将locale设为简体中文,再运行此程序,测试结果就变为中文了,如locale设为英文则显示仍为上面的英文信息。

[zechen11@Arch hello]$ mkdir -p locale/zh_CN/LC_MESSAGES
[zechen11@Arch hello]$ mv helloGTK.mo locale/zh_CN/LC_MESSAGES/
[zechen11@Arch hello]$ export LANG=zh_CN.UTF-8

4.自动生成makefile与打包

 4.1.执行autoscan生成configure.scan文件并改名为configure.in

[zechen11@Arch hello]$ autoscan 
[zechen11@Arch hello]$ ls
autoscan.log helloGTK helloGTK.c~ helloGTK.po~
configure.scan helloGTK.c helloGTK.po locale
[zechen11@Arch hello]$ mv configure.scan configure.in

 4.2.修改configure.in

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.68])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([helloGTK.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([libintl.h locale.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

 修改改后:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.68])
AC_INIT([helloGTK], [0.01], [zechen11@qq.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([helloGTK.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([libintl.h locale.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT(Makefile)

 4.3.执行aclocal命令,生成aclocal.m4宏文件

[zechen11@Arch hello]$ aclocal
[zechen11@Arch hello]$ ls
aclocal.m4 autoscan.log configure.in~ helloGTK.c helloGTK.po locale
autom4te.cache configure.in helloGTK helloGTK.c~ helloGTK.po~

 4.4.执行autoconf命令,生成configure shell可执行脚本

[zechen11@Arch hello]$ autoconf 
[zechen11@Arch hello]$ ls
aclocal.m4 configure helloGTK helloGTK.po
autom4te.cache configure.in helloGTK.c helloGTK.po~
autoscan.log configure.in~ helloGTK.c~ locale

 4.5.执行autoheader命令,生成config.h.in文件

[zechen11@Arch hello]$ autoheader 
[zechen11@Arch hello]$ ls
aclocal.m4 config.h.in configure.in~ helloGTK.c~ locale
autom4te.cache configure helloGTK helloGTK.po
autoscan.log configure.in helloGTK.c helloGTK.po~

 4.6.创建Makefile.am文件

AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = helloGTK
helloGTK_SOURCES = helloGTK.c
helloGTK_LDFLAGS = `pkg-config --cflags --libs gtk+-2.0`

 4.7.执行automake命令,生成Makefile.in文件

[zechen11@Arch hello]$ automake --add-missing 
configure.in:6: installing `./install-sh'
configure.in:6: installing `./missing
'
Makefile.am: installing `./depcomp'
[zechen11@Arch hello]$ ls
aclocal.m4 configure helloGTK helloGTK.po~ Makefile.am~
autom4te.cache configure.in helloGTK.c install-sh Makefile.in
autoscan.log configure.in~ helloGTK.c~ locale missing
config.h.in depcomp helloGTK.po Makefile.am

 4.8.执行./configure生成Makefile

[zechen11@Arch hello]$ ./configure 
checking for a BSD-compatible install... /bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking libintl.h usability... yes
checking libintl.h presence... yes
checking for libintl.h... yes
checking locale.h usability... yes
checking locale.h presence... yes
checking for locale.h... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: config.h is unchanged
config.status: executing depfiles commands
[zechen11@Arch hello]$ ls
aclocal.m4 config.log depcomp helloGTK.po~ Makefile.am~
autom4te.cache config.status helloGTK install-sh Makefile.in
autoscan.log configure helloGTK.c locale missing
config.h configure.in helloGTK.c~ Makefile stamp-h1
config.h.in configure.in~ helloGTK.po Makefile.am

 4.9.执行make命令,生成可执行文件helloGTK

[zechen11@Arch hello]$ make
make all-am
make[1]: Entering directory `/home/zechen11/hello'
gcc -g -O2 `pkg-config --cflags --libs gtk+-2.0` -o helloGTK helloGTK.o
make[1]: Leaving directory `/home/zechen11/hello
'

 4.10.执行make dist命令,在当前目录下生成hellogtk-0.01.tar.gz源代码包,如此就可以将你的源代码包向外界发布了。

[zechen11@Arch hello]$ make dist
{ test ! -d "hellogtk-0.01" || { find "hellogtk-0.01" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hellogtk-0.01"; }; }
test -d "hellogtk-0.01" || mkdir "hellogtk-0.01"
test -n "" \
|| find "hellogtk-0.01" -type d ! -perm -755 \
-exec chmod u+rwx,go+rx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec /bin/sh /home/zechen11/hello/install-sh -c -m a+r {} {} \; \
|| chmod -R a+r "hellogtk-0.01"
tardir=hellogtk-0.01 && /bin/sh /home/zechen11/hello/missing --run tar chof - "$tardir" | GZIP=--best gzip -c >hellogtk-0.01.tar.gz
{ test ! -d "hellogtk-0.01" || { find "hellogtk-0.01" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hellogtk-0.01"; }; }
[zechen11@Arch hello]$ ls
aclocal.m4 config.status hellogtk-0.01.tar.gz locale missing
autom4te.cache configure helloGTK.c Makefile stamp-h1
config.h configure.in helloGTK.o Makefile.am
config.h.in depcomp helloGTK.po Makefile.am~
config.log helloGTK install-sh Makefile.in
[zechen11@Arch hello]$ tar -tzvf hellogtk-0.01.tar.gz
drwxr-xr-x 1000/100 0 2011-11-11 18:11 hellogtk-0.01/
-rwxr-xr-x 1000/100 11419 2010-11-20 11:20 hellogtk-0.01/missing
-rw-r--r-- 1000/100 34611 2011-11-11 13:07 hellogtk-0.01/aclocal.m4
-rw-r--r-- 1000/100 3472 2011-11-11 00:23 hellogtk-0.01/helloGTK.c
-rwxr-xr-x 1000/100 18615 2010-11-20 11:20 hellogtk-0.01/depcomp
-rw-r--r-- 1000/100 138 2011-11-11 13:08 hellogtk-0.01/Makefile.am
-rw-r--r-- 1000/100 521 2011-11-11 05:23 hellogtk-0.01/configure.in
-rw-r--r-- 1000/100 19636 2011-11-11 13:08 hellogtk-0.01/Makefile.in
-rwxr-xr-x 1000/100 13663 2010-11-20 11:20 hellogtk-0.01/install-sh
-rwxr-xr-x 1000/100 158255 2011-11-11 13:07 hellogtk-0.01/configure
-rw-r--r-- 1000/100 1599 2011-11-11 13:08 hellogtk-0.01/config.h.in

5.程序效果图

Gtk+2 Hello World:从源码到打包发布

图1. 英文locale下界面,点击关闭按钮,终端打印delete event occurred

Gtk+2 Hello World:从源码到打包发布

图2. 点击hello GTK按钮后,退出程序,终端打印 Hello GTK!

Gtk+2 Hello World:从源码到打包发布

图3. 中文locale下界面,点击关闭按钮,终端打印 删除事件发生

Gtk+2 Hello World:从源码到打包发布

图4. 点击 你好 GTK 按钮后,退出程序,终端打印 你好GTK!