如何在linux下用gtk开发图形界面应用程序

如何在linux下用gtk开发图形界面应用程序,第1张

 * 使用 GTK+ 和 Glade 快速开发 Linux 图形界面

** GTK+ 简介

*** 基本概念

GTK+ 是一种用于创建图形界面的库. 嗯, gnome 用的就是它, 不过并不是说只

有在 gnome 环境中才能用, 只要系统上装有 GTK 的库 (基本上有图形系统的个

人机都会有的啦) 就能运行基于 GTK 的程序. 除了 UNIX-like 平台, 它还移植

到 windows 上, 还有面向嵌入设备的 framebuffer 版本等等.

GTK 依赖两个重要的库. 一个是 GLib, 这并不是一个图形库, 也和 glibc 不同

, 它大抵上提供了一些接口以屏蔽系统的不同, 比如 gint 在哪里都是 32bit

的, 等等另一个是 GDK, 它是一个设备无关的图形库, 支持基本的画点, 以及

与窗口管理器沟通等任务, 由于 GTK 被设计成能在各个平台, 而非仅仅在

XWindow 环境下使用, 所以这个库也是必要的. 而在他们上面的 GTK 库, 就提

供了一些 widget --- 可以理解为控件啦, 不过窗口也是一个 widget 的说, 给

我们使用, 并提供了包装良好的事件响应机制.

*** GTK+ 开发基础

要开发基于 GTK 的软件, 必须先安装 GTK+ 的开发包. 检查是否正确安装的办

法是在安装后执行 ``pkg-config --cflags --libs gtk+-2.0'', 如果安装不正

确, 会提示找不到相应的包.

GTK 本身是基于 C 的库, 当然也有 C++ 等语言的 wrap, 但它的整个体系是面

向对象的. 其最基本的类是 GObject, GtkObject 继承了它, GtkObject 又派生

出我们最经常用到的 GtkWidget, 我们使用的所有窗体控件都派生于它. 于是,

在 C 环境中我们就要手动处理这些类转换, GTK 和底层的 GLib 等提供了一种

统一的转换方法, 比如把类型为 GtkWidget* 的 button 转换成 GtkButton 形,

写法是: GTK_BUTTON(button), 就酱子.

我不打算在这里列一个 GTK 的 hello world 占页面, 这个程序随便 google 一

下就能找到. 我们可以自己想一想一个图形界面应该如何建立.

首先我们要进行初始化, GTK 提供了 gtk_init() 作为初始化, 它检查程序参数

中的一些特定部分, 进行自己的设置. 调用方法如下:

gtk_init(&argc, &argv)

将 argc 和 argv 传指针的目的是 gtk_init 会对他们进行加工, 把 GTK 自己

用到的一些参数抽取出来.

接着, 我们必须要创建这些控件吧, GTK 中, 创建一个控件会返回一个

GtkWidget 类型 (或它的派生类) 的指针, 所有创建控件的函数的格式是

gtk_控件类型_new(参数表). 比如创建一个窗口的写法是:

GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL)

然后, 我们要设定事件响应函数, GTK 中的事件叫做 signal. GTK 的事件响应

函数接口应该是类似这样的

void

destroy(GtkWidget *widget, gpointer data)

我们把它连入到一个控件中的方法是这样的

g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL)

应该很好理解吧.

我们创建的咚咚, 要说明他们的位置和包含关系, GTK 用 container 来解决这

个问题, 它可以保证在窗口缩放的时候控件的摆放依然合理, container 的具体

使用不详细说, 后面经常要跟 container 打交道, 但基本上不用管 C 代码, 嗯

. 不过其实我们的任何的可视控件都继承自 container, 比如 button 也是一个

container, 它很多时候装的是一个 GtkLabel, 也就是用来显示纯文本的控件,

于是我们就能见到一个文本按钮, 嗯. 使用 container 的方法如下.

gtk_container_add(GTK_CONTAINER(window), button)

这样 button 就会占满整个 window 的控件, 我们后面可以看到可以用

GtkVBox, GtkHBox 等 container 分隔窗体.

好了, 我们可以准备启动程序了, 我们可以用 gtk_widget_show() 来显示各个

控件, 然后我们就应该进入到所谓的事件响应循环了, 这就要使用 gtk_main().

在程序运行过程中, 我们要 *** 纵控件, 比如说我们要在一个 entry 控件(文本框

) 中取出其中的文字, 这样的 *** 作使用 gtk_控件类型_动作(对象, 参数) 的形

式完成的, 比如刚才所说的任务, 做法是 gtk_entry_get_text(entry).

顺便讲讲 GTK 程序的退出, 关闭 GTK 的窗口 (即使是所有窗口) 也不代表程序

退出, 因为那说到底只是一个界面而已, 我们当然可以使用 exit() 的自爆法退

出, 但最好还是给 GTK 一个料理后事的机会, 在主窗口的 destroy 事件响应函

数上用 gtk_main_quit() 就好了.

编译 GTK 程序的办法也很简单.

gcc -o foo foo.c `pkg-config --cflags --libs gtk+-2.0`

** 使用 Glade 快速定制用户界面

好了, 说了一堆有的没的, 如果我现在说我上面说的那一堆中的大部分我们都不

会用到, 是不是觉得偶很歉扁? 前面的介绍只是给大家 GTK 这个库的一些基本

概念, 概念就好了, 我们倒真的不用拿这些来编程的. 想想, 一个复杂一点的界

面, 十几个控件, 再加上各种各样的 container, 自己挂事件, 再加上超常的命

名, 想想都恐怖.

这时候, Glade 横空出世了! 这是一个可视化的界面编辑器 --- 但它仅仅是一

个界面编辑器而已, 甚至连代码编辑框也没有给出. 先不管了, 打开 glade (安

装省略, 饶了我把, 记得装 libglade-dev), 应该很好懂了, 指指点点就能弄好

一个界面, 然后在属性窗的信号一栏中选取需要的信号, 设定响应函数, 非常好

弄.

玩了几分钟, 问题来了, 怎么把它变为程序啊? 提供类似功能的 IDE 如

Borland C++ Builder, 在点击创建新控件的时候, 我们能即使在代码窗看到自

动生成的代码, Glade 也可以采用这种形式, 在设计好界面并保存后, 按一下主

窗口的 build 按钮, 它就自动生成了界面代码, 根本不用自己写的. 打开代码

目录, callbacks.c 里已经有自动创建的事件响应的空函数, 在里面填处理, 然

后 configure make 就行了.

但是, 这样的开发方式还是有问题的. 第一, 自动生成的代码非常复杂, 可是很

多时候我们还是不能完全不看它, 处理和界面是混在一起了, 理解他们变得困难

其二, 由于以上的原因, 修改界面变得非常痛苦其三, 它给你生成那堆有的

没的配置文件不一定是你想要的.

因此 glade 提供了另一种方法, glade 编辑所得的 .glade 文件是一个 XML 文

件, 其实它已经完整地描述了界面, 我们能否采用一种简单的方式直接载入, 配

置它呢. 这样做, 我们的代码中就真真正正地去处了烦人的界面生成代码, 而专

注于处理部分了.

libglade 正是由于这个而来, 它能很好地完成上面所说的工作. 当我们用

glade 创建了一个 .glade 界面后, 用这种方法我们就可以建立界面, 运行程序

了.

#include <gtk/gtk.h>

#include <glade/glade.h>

GladeXML *GUI

int

main(int argc, char **argv)

{

gtk_init(&argc, &argv)

/* load the interface */

GUI = glade_xml_new("frame.glade", NULL, NULL)

/* connect the signals in the interface */

glade_xml_signal_autoconnect(GUI)

/* start the event loop */

gtk_main()

return 0

}

剩下的事情很简单, 如果你的 button 的 clicked 控件有一个响应函数

on_button_clicked, 你写

void

on_button_clicked(GtkWidget *widget, gpointer data)

{

// balabalabala

}

就可以了. 所以, 上面讲的一堆创建界面的方法, 其实大部分时候都用不着.

由于用到了 libglade, 我们的编译方法变为

gcc -o foo foo.c `pkg-config --cflags --libs libglade-2.0`

** 开发举例

一个很简单的程序, 密码学对称加密算法要用到的, 如果说是界面, 就是三个文

本框: 明文, 密码, 密文, 三个按钮, 加密, 解密, 清除, 完了. 为了实验众多

的算法, 我们加了一个下拉窗口, 用来选择算法. 我把它设计成一个 wrapper

和框架, 它不实现任何算法, 只是在界面中获取用户输入, 调用外部程序, 并把

结果显示出来而已. 这样, 实际的算法实现可以用纯 C 写的文本界面程序完成,

移植起来很方便, 在 windows 随便做个一样的界面做前端就整个移植过去了.

于是, 我们需要的窗体元素是 GtkEntry, GtkComboBoxEntry, GtkButton, 查查

手册, 我们用到的界面相关的函数只有以下几个:

- gtk_entry_get_text(), 用于获取文本框输入

- gtk_entry_set_text(), 用于在文本框中显示结果

- gtk_combo_box_get_active_text(), 用于在 ComboBoxEntry (派生自

ComboBox) 取出用户选中的算法.

另一个问题是, 他们都需要相应的对象指针做参数, 这应该怎样获得呢? 我们使

用 glade_xml_get_widget(GUI, "控件名") 就能取得控件了.

默认的Gtk.Window是继承自Gtk.Bin的, 只能放置一个控件, 如果想要放置多个控件就需要容器container, 常用的容器有 盒子, 网格, 笔记本, 固定板 等, 下面的文章会慢慢讲解

首先, 来说盒子容器

self.box = Gtk.Box() 可以实例化一个盒子, 默认是水平盒子

垂直盒子可以 self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

或者 self.box = Gtk.VBox()

Gtk.Box().pack_start(sub_widget, expand, fill, padding)

Gtk.Box().pack_end(sub_widget, expand, fill, padding)

第一个方法是从开始放置, 第二个从末尾

sub_widget 是被放置的控件

expand(bool) 是否分配额外的空间

fill (bool) 是否填充额外的空间, 当expand = False时, fill 无效

padding(int) 向外扩展的像素

例如

下篇文章讲grid 网格容器

欢迎大家留言

本文假设读者熟悉基本的面向对象概念,比如类、对象、方法和继承。虽然不需要能够用 C 编写程序,但是需要对 C 语言的语法有基本的理解。C 语言的 GTK+ 应用程序剖析我发现最好用示例来讨论代码。对于本文来说,我使用一个用 C 编写的名为 Hello World 的简短应用程序。虽然短小 —— 而且作为应用程序来说,基本没什么用 —— 但是这个应用程序的代码确实展示了在进行 GTK+ 编程时可能会碰到的一些最有趣的概念(参见清单 1)。清单1. Hello World 应用程序的 GTK+ 代码 #include <gtk/gtk.h>#include <libintl.h>#define _(x) gettext (x) #define N_(x) (x) #define GETTEXT_PACKAGE "gtk-hello" #define LOCALEDIR "mo" static char *greetings[] = { "Hello World", "Witaj ?wiecie", "世界に今日は" }static char* choose_greeting () { return greetings[g_random_int_range (0, G_N_ELEMENTS (greetings))]} static void cb_button_click(GtkButton *button, gpointer data) { GtkWidget *label = GTK_WIDGET(data)g_assert(label != NULL)gtk_label_set_text(GTK_LABEL (label), choose_greeting())} static gboolean cb_delete(GtkWidget *window, gpointer data) { gtk_main_quit()return FALSE} int main (int argc, char *argv[]) { GtkWidget* window, *button, *label, *vboxbindtextdomain (GETTEXT_PACKAGE, LOCALEDIR)bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8")textdomain (GETTEXT_PACKAGE)gtk_init(&argc, &argv)window = gtk_window_new (GTK_WINDOW_TOPLEVEL)button = gtk_button_new_with_label (_("Hello World"))label = gtk_label_new (choose_greeting())vbox = gtk_vbox_new(FALSE, 0)gtk_container_add(GTK_CONTAINER (window), vbox)gtk_container_add(GTK_CONTAINER (vbox), label)gtk_container_add(GTK_CONTAINER (vbox), button)g_signal_connect(G_OBJECT (window), "delete-event", G_CALLBACK(cb_delete), NULL)g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_button_click), label)gtk_widget_show_all(window)gtk_main()return 0}概述在进入细节之前,先看看运行 Hello World 程序时发生的情况:初始化 GTK+ 和国际化(i18n)支持。创建部件(widget)。部件被组织成层次结构,让 GTK+ 知道如何在屏幕上显示它们。两个信号处理器被连接起来 —— 一个用来在用户关闭窗口时退出应用程序,另一个用来在用户点击按钮时,修改显示的欢迎信息。在屏幕上显示窗口,应用程序调用 gtk_main(),激活主循环。主循环一直运行,直到用户关闭窗口,调用 gtk_main_quit() 时才结束。初始化以下几行初始化 GTK+ 和 i18n 支持:清单2. 初始化 GTK+ 和 i18n 支持 int main (int argc, char *argv[]) { GtkWidget* window, *button, *label, *vboxbindtextdomain (GETTEXT_PACKAGE, LOCALEDIR)bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8")textdomain (GETTEXT_PACKAGE)gtk_init(&argc, &argv)C 程序员应当熟悉 main 声明。(如果不是 C 程序员,那么只需要知道这是应用程序开始执行的函数。)下一行包含几个到 GtkWidget 类型的指针的声明。GTK+ 是一个面向对象的工具包。所以,它使用常见的面向对象概念(例如继承)来实现不同的部件。作为语言,C 缺乏对面向对象的内置支持。GTK+ 通过使用一些更聪明的技巧和 C 标准要求的一些有帮助的属性,克服了这个缺点。在这个方案中,对象由指针代表,而 GtkWidget 是GTK+ 层次结构中的基本类型 —— 叫做 类,其他类都从它派生而来。所以,我把变量声明为 GtkWidget*。下三行是在程序开始的地方应当包含的调用,用来得到国际化接口的支持。注意,在真实的应用程序中,不会手动声明 LOCALEDIR 和GETTEXT_PACKAGE。编译系统将会处理这些声明。但是,在这个简单示例中,声明有助于澄清需要的内容。最后一行调用 gtk_init()。在进行其他 GTK+ 调用之前,必须调用这个函数,并把调用程序使用的参数传递给它。如果这个调用失败,就会从没有机会正确初始化自己的各个子系统得到多个错误消息。创建部件这四行分别调用不同的 _new() 函数:清单3. 调用不同的 _new() 函数 window = gtk_window_new (GTK_WINDOW_TOPLEVEL)button = gtk_button_new_with_label (_("Hello World"))label = gtk_label_new (choose_greeting())vbox = gtk_vbox_new(FALSE, 0)关于TOPLEVEL 的警告在看到 gtk_window_new 的TOPLEVEL 参数之后,可能想知道是否有其他可能的窗口类型。实际上,确实有。但是,对于 TOPLEVEL 之外的类型的需要很少见。而且,要使用不同的类型,必须对 GTK+ 与窗口系统的交互方式有很好的理解。所以,规则很简单:一直 使用TOPLEVEL 参数。正如您所想,这些函数创建新的部件。所以,它们是代表部件的对象的构造函数。在 C++ 中,用特殊的方式标记构造函数,并用特殊语法进行调用。但是,因为 C 不支持面向对象,所以它们与普通的函数没有什么不同。只有添加到函数名尾部的 _new() 才表示这些函数实际上是构造函数。规定是:gtk_* 名称空间中的每个构造函数都返回一个到 GtkWidget 的指针。这样,通过声明这种类型的变量,可以直接把构造函数调用的结果分配给对应的变量。如果查看单独的构造函数,可以看到它们接受不同的参数,对应着它们创建的部件的类型。具体来说,gtk_window_new (GTK_WINDOW_TOPLEVEL) 创建新的 TOPLEVEL 窗口;也就是与用户看成窗口的东西对应的部件,具有标题栏、关闭按钮或者窗口系统添加的其他元素。对label 和button 的构造函数的调用做的工作正如您所料。但是,请注意传递给 button 的字符串周围的下划线和括号(_())。这个宏调用 gettext() 例程,并且对于界面转换至关重要。(关于 gettext 的更多信息,请参阅 参考资料。) 模样古怪的 gtk_vbox_new(FALSE, 0) 创建垂直框(VBox)。虽然这个部件与屏幕上的任何可视像素都不对应,但是它在 GTK+ 的控件布局中扮演着重要角色,您很快就会看到这一点。 决定布局这三行决定部件的布局: gtk_container_add(GTK_CONTAINER (window), vbox)gtk_container_add(GTK_CONTAINER (vbox), label)gtk_container_add(GTK_CONTAINER (vbox), button)这些行是对类型 GtkContainer 的面向对象方法的调用。如果查看应用程序编程接口(API)参考,可以看到 GtkContainer 继承自 GtkWidget,而且它的全部方法都接受 GtkContainer* 作为第一个参数。所以,GtkContainer* 是方法要在上面 *** 作的对象实例。因为变量是 GtkWidget* 类型的,而且 C 编译器不支持面向对象继承,所以需要让编译器相信:向需要 GtkContainer* 的函数传递这些变量是安全的。GTK_CONTAINER() 宏通过实现到类型安全版 GtkContainer 的类型转换做到了这一点。类型安全 意味着宏在进行类型转换之前,会验证指定 *** 作可以在指定类型上安全地执行。如果宏不能执行指定 *** 作,就会提供警告。因为GTK+ 使用方框布局 模型,所以不必显式地指定部件应当放在屏幕上的什么位置。相反,要指明部件放在其他哪个窗口部件内。在 Hello World 应用程序中,每个 gtk_container_add() 方法调用都告诉应用程序用第一个参数(或 双亲部件),并把第二个参数(或 子部件)放在双亲部件内。在这个示例中使用的 VBox 部件是一种布局部件,它垂直地排列子部件。这样,在它内部放置标签和按钮时,结果就是按钮显示在标签下。这是需要做的全部工作。如果您曾经用过绝对定位(在某些工具包中使用的模型,例如 Win32)手动调整部件或重新设置部件大小,那么您会很高兴知道在 GTK+ 中所有这些都是自动完成的。连接信号和主循环在创建并组织好部件之后,该给它们添加些逻辑了。GTK+ 像多数 GUI 工具包一样,是一个事件驱动框架。所以,它是围绕主循环 组织的。主循环在连续的检查-分配-睡眠周期上 *** 作。当事件发生时,与这个事件对应的对象发出信号,通知主循环事件已经发生。然后主循环查询自己的信号和处理程序之间的内部映射表,也叫做 回调,并调用注册到指定对象的指定信号的处理程序。在Hello World 代码中,回调的注册看起来像这样:清单4. 回调的注册 g_signal_connect(G_OBJECT (window), "delete-event", G_CALLBACK(cb_delete), NULL)g_signal_connect (G_OBJECT(button), "clicked", G_CALLBACK(cb_button_click), label)请注意在 GTK+ 中,connect(连接) 到信号。第一行把 cb_delete 函数连接到 window 对象的 delete-event 信号。类似地,第二行把 cb_button_click 函数连接到 button 对象的 clicked 信号。请注意在第二个连接调用中的第四个参数 label。稍后会看到它在 cb_button_click 函数中是如何使用的。下面是 cb_delete 函数,它在用户关闭窗口时退出应用程序: static gboolean cb_delete(GtkWidget *window, gpointer data) { gtk_main_quit()return FALSE} static 修饰符 在C 中,static 关键字在内部链接函数,这意味着静态函数在声明它的源文件之外不可见。除非需要在不止一个文件中使用回调,否则请一直使用 static 关键字声明回调。使用这个方法,可以避免把可用函数名称的有限名称空间弄混乱。因为静态函数被局限在一个文件,所以可以安全地重用函数名称。 这个函数接受 GtkWidget* 和一个未指定的 data 指针(gpointer 是等价于 void* 的类型),因为 "delete-event" 的每个回调都必须符合这个原型。但是,这个函数不需要这些参数,所以它们被忽略了。它调用 gtk_main_quit() 例程以退出主循环。而且,该函数返回布尔值,因为为 GtkWidget 定义的 delete-event 信号的回调原型指明的是布尔返回值。布尔值决定 GTK+ 采取的行动。如果它返回 TRUE 值,那么事件就被认为已经得到处理,而且不调用默认处理程序(该默认处理程序从窗口系统删除部件)。有的时候,例如,如果想显示一条消息,请求尚未保存的数据,并根据用户的响应阻止窗口关闭,那么这个函数会很有用。下面是 cb_button_click 函数,在用户点击按钮时,它修改显示的欢迎信息:清单5. cb_button_click 函数 static void cb_button_click(GtkButton *button, gpointer data) { GtkWidget *label = GTK_WIDGET(data)g_assert(label != NULL)gtk_label_set_text(GTK_LABEL (label), choose_greeting())} 可以看到,这个函数与 cb_delete 函数类似,不同之处是它什么也不返回,而且它接受 GtkButton* 而不是 GtkWidget。代码把 data 转换成到 GtkLabel 的指针。还记得在回调注册中的 label 参数么?现在每次调用回调时,data 指针都会包含到那个标签的指针。每当需要向回调传递额外的信息时,都可以使用 data 参数。类似地,如果需要访问发出信号的对象,就要使用第一个参数,在这个具体回调中是 button。在得到标签的指针后,代码使用 g_assert 宏来确定标签是否等于 NULL。g_assert 宏是一个来自 Glib (GTK+ 使用的一个有用的 C 类型和例程库)的工具宏,如果传递给它的条件满足,就会中止程序 —— 在这个示例中,条件是 label 等于NULL。因为 label 等于NULL 意味着程序员犯了错误,所以这可以确保在代码投入生产之前捕获到错误。显示窗口在回调连接好之后,gtk_widget_show_all() 函数使窗口 —— 即所有的部件 —— 都显示在屏幕上(参见图 1)。图1. Hello World 应用程序,用波兰语和日语运行激活主循环当诸事就位,而且显示出来之后,gtk_main() 函数就激活主循环。主循环进入无限循环,等候事件并调用回调,直到有人关闭窗口,调用 gtk_main_quit() 为止。注意:如果对代码仍有问题,请参阅附带的源代码。它与文章中介绍的代码完全相同,但是每一行都包含详细的注释。编译和运行要编译这个程序,需要 C 编译器和 GTK+ 的开发文件(头和库)。有关如何获取这些项目的信息,请参阅 参考资料。在安装完文件之后,请解压源代码,进入源代码将要解压到的目录,并运行 make: $ tar -xzf gtk_hello.tgz $ cd gtk_hello $ make 注意:如果正在运行 Microsoft�0�3 Windows�0�3,请不要运行 make,而是打开 Microsoft Visual Studio�6�4.NET 并运行 “hello” 项目。回页首在其他编程语言中的 GTK+可以在多个编程语言中使用 GTK+。要做到这点,需要使用绑定。绑定 是针对指定语言的特殊包,它用适合该语言的方式公开 GTK+ API。例如,我已经把 Hello World 应用程序转换成 Python 和 C#。要在这些语言中运行 GTK+,除了 Python 和 Mono/.NET 之外,分别还需要 PyGTK 和 Gtk#(请参阅 参考资料)。PyGTK 中的 Hello World 清单6 显示了转换成 Python 的 Hello World 应用程序的代码。清单6. PyGTK 中的 Hello World 应用程序 import pygtk pygtk.require('2.0') import gtk import random greetings = ["Hello World", "Witaj ?wiecie", "世界に今日は"] def choose_greeting (greets): return greets[random.randint (0, len(greets) - 1)] def cb_clicked(button, label): label.set_text(choose_greeting(greetings)) window = gtk.Window () vbox = gtk.VBox () button = gtk.Button("Hello World") label = gtk.Label (choose_greeting (greetings)) window.add(vbox) vbox.add(label) vbox.pack_start(button, False, False) window.connect("delete-event", lambda a,b: gtk.main_quit()) button.connect("clicked", cb_clicked, label) window.show_all() gtk.main() 由于紧凑的 Python 代码,应用程序的这个版本比它的 C 语言对应物更短。除此之外,看起来是相似的。注意,代码被转换成使用 Python 的习惯,但是 API 保持不变。Gtk# 中的 Hello WorldGtk# 中的 Hello World 应用程序代码要比 C 版本略长,因为 C# 要求的声明很长。所以,我没有在这里包含完整的源代码。源代码包含在附加的下载中。下面快速查看一下 C 到 C# 的主要概念转换: class GtkHello : Gtk.Window { 现在不再创建并设置新窗口,而是把 Gtk.Window 类放进一个子类,并把所有设置代码移动到构造函数。这种方法并非特定于 Gtk#。实际上,在 C 程序中,当需要窗口的多个拷贝时,经常使用这种方法。但是,在 C# 中使用子类如此之容易,所以即使对一个实例这么做也有意义 —— 特别是在考虑到 C# 要求至少声明一个类的时候,更是如此。 this.DeleteEvent += new DeleteEventHandler(DeleteCB)button.Clicked += new EventHandler(ButtonClickCB)可以看到,GTK+ 信号被转换成地道的 C# 事件概念。名称也被稍加修改,以更好地符合 C# 的命名规范。清单7. GTK+ 信号被转换成地道的 C# 事件概念 private void DeleteCB (object o, DeleteEventArgs args) { Application.Quit ()args.RetVal = true} 由于C# 事件的构造方式,所以 delete-event 处理程序的原型略有不同。它不是从回调返回 true,而是通过 args.RetVal 传递返回值。gtk_main() 和gtk_main_quit() 分别被 Application.Run() 和Application.Quit() 代替。回页首有用的工具在使用 GTK+ 进行开发时,有几个工具可以让工作轻松些。其中最著名的几个工具是 Glade、Libglade 和 Devhelp。Glade 和 LibgladeGlade 是一个界面构建器 —— 这个程序可以图形化地构建应用程序,而不必手动从源代码开始构建。更重要的是第二个组件:Libglade。顾名思义,Libglade 支持读取可扩展标记语言(XML)格式,Glade 用 XML 保存用户界面描述。使用 Libglade,可以直接从这个描述构建应用程序的界面,而不需要任何代码。图2 显示了一个包含几个部件的简单的 Libglade 应用程序。图2. 简单的 Libglade 应用程序清单8 显示了图 2 所示的 Libglade 应用程序的完整源代码。清单8. Libglade 应用程序的源代码 #include <gtk/gtk.h>#include <glade/glade.h>int main (int argc, char *argv[]) { GladeXML *uigtk_init(&argc, &argv)/* Read user interface description from glade file */ ui = glade_xml_new ("glade_hello.glade", "main_window", NULL)/* Automatically connect signals */ glade_xml_signal_autoconnect(ui)gtk_main()return 0} 可以看到,所有的事情只有 17 行代码,包括注释和空行。虽然真正的应用程序不会这么短,但是从代码的清晰性、模块性和可管理性来说,Libglade 带来了巨大的提高。如果想进一步研究这个程序是如何构建的,可通过本文附带的下载中其余的示例进行了解。DevhelpDevhelp 是一个文档浏览器,是为了阅读用 gtk-doc 生成的格式的文档而设计的,gtk-doc 是构建 GTK+ 文档的标准工具,相关的项目,例如 Pango 和 GNOME 也使用它。使用 Devhelp,可以迅速地搜索函数索引并浏览已经安装的文档,从而可以更迅速地获得需要的信息。Devhelp 是一个 GNOME 应用程序。所以,要运行它,需要一个符合 POSIX 的 *** 作系统,在上面运行 GNOME,例如 Linux�0�3 或 Sun Solaris,还需要 GNOME 运行时库。不需要运行 GNOME 本身。如果使用其他平台,也有许多其他方法可以阅读 GTK+ 文档。Mono 项目有 Monodoc 浏览器,它通常是与 Gtk# 参考一起预先装入的。GTK+ 的 Windows 安装器也通常包含适合各种开发工具的文档格式,例如 Visual Studio�0�3。最后,总有使用 Web 浏览器在线阅读文档这个选项,但是推荐采用专用浏览器,因为它的速度快,还有针对在程序文档中进行搜索而设计的额外特性。下期预报在这篇文章中,学习了 GTK+ 编程中使用的基本概念。还看到了如何在 C 语言之外的语言中使用 GTK+,在保持使用 GTK+ 的一般方式的同时,还使用了特定于这些语言的方式。最后,还介绍了有助于更快更好地开发应用程序的工具。在本系列的最后一期中,将进一步观察 GTK+ 开发的另一个方面:部署。文章将详细分析各种选项,包括移植性的考虑和安装的简易。最后,将以更广阔的视野来看 GTK+ —— 作为一个有活跃社区的项目,它有助于构建出更好地为用户服务的应用程序。回页首下载描述名字大小下载方法Source codeos-gtk2_hello.zip18KBHTTP关于下载方法的信息参考资料 学习您可以参阅本文在 developerWorks 全球站点上的 英文原文。请阅读 developerWorks “GTK+ 基础” 系列中的全部文章。GNU Gettext 是一个用于应用程序运行时转换的库。Libglade Reference Manual 是用来动态创建 GTK+ 界面的库。请访问 GTK+ 获得关于工具包的更多信息。全面的 GTK+ API Documentation 对于所有开发人员都很重要。Matthias Warkus 编写的 The Official GNOME 2 Developer's Guide(No Starch Press,2004 年)介绍了 GNOME 2,包括使用 GTK+ 进行编程。请访问 developerWorks 开放源码专区 获得丰富的 how-to 信息、工具和项目更新,帮助您用开放源码技术进行开发并把它们用于 IBM 的产品。获得产品和技术 请获取 Gtk#,这是针对 Microsoft .NET 环境的 GTK+ 绑定。请获取 GTK+ 的官方 source code tarballs。请访问 PyGTK,这是 Python 的 GTK+ 绑定的官方站点。Gazpacho 是Glade UI 描述文件的改进的编辑器,是用 PyGTK 编写的。Devhelp 是用于 GNOME 的一个面向程序员的文档浏览器。请参阅 GNOME,这是使用 GTK+ 构建的侧重于应用的桌面。请尝试 Xfce,这是一个快速而易用的桌面,也是用 GTK+ 开发的。请访问 Gnomefiles 并得到超过 1,000 个用 GTK+ 构建的应用程序。请用IBM 试用软件 改造您的下一个开放源码开发项目,这些软件可以下载也可以通过 DVD 得到。讨论 请在GTK+ mailing lists 上获得关于用 GTK+ 开发软件的支持并询问相关问题。通过参与 developerWorks blogs 加入developerWorks 社区。关于作者Maciej Katafiasz 是计算机科学专业的研究生,从高中起就一直使用开放源码技术。从 GNOME 1.0 起,他就是 GNOME 桌面的用户,而 2.0 版一发布,他就爱上了它并了解到 GTK+ 能够开发自己喜欢的桌面。关闭[x]关于报告滥用的帮助报告滥用谢谢! 此内容已经标识给管理员注意。关闭[x]关于报告滥用的帮助报告滥用报告滥用提交失败。 请稍后重试。关闭[x]developerWorks:登录IBM ID:需要一个 IBM ID?忘记IBM ID?密码:忘记密码?更改您的密码 保持登录。单击提交则表示您同意developerWorks 的条款和条件。 使用条款 当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。所有提交的信息确保安全。关闭[x]请选择您的昵称:当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。昵称:(长度在 3 至 31 个字符之间)单击提交则表示您同意developerWorks 的条款和条件。 使用条款. 所有提交的信息确保安全。为本文评分评论回页首


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7810986.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-10
下一篇 2023-04-10

发表评论

登录后才能评论

评论列表(0条)

保存