本文介绍了Linux平台下的Xwindow图形窗口编程工具GTK,并给出了用GTK编程的基本要点和步骤。
GTK,回调函数,消息处置器,调节器
GTK是一个图形用户编程的接口工具。它注册完全免费,所以用来开发自由软件或商业软件都无需花费什么。目前不少Linux集成系统都已经将GTK1.2版本打包进来了。包含RedHat Linux 6.0以上版本,还有中文化的Turbo Linux等等。它也愈加被常见的应用于UNIX系统编程。
还有一个组件叫Glib,它包括了一些标准应用的新扩展用来提升GTK的兼容性。用于Linux系统的某些函数可能不合适标准的UNIX系统,比如g_strerror函数等等。某些函数也扩展了GNUC的一般功能,比如g_malloc函数就有自己加大的调试功能。
GTK可以与多种语言绑定,包含C++, Guile, Perl, Python, Ton, Ada95, Objective C, Free Pascal, Eiffel。用标准C开发的程序,编译软件可用GNU并附带上GTK选项即可。想用除去标准C以外的其它语言来开发Xwindow图形用户程序,则需要先参考一下有关绑定软件的内容(HTTP:// www.gtk.org)。 假如用C++语言来调用GTK进行开发,可以用已经和C++绑定的软件叫GTK--软件,来提供一个比GTK更好的C++编译环境。
现在已经开发出来GTK的增强版GTK+。GTK+是将GTK,GDK,GLIB集成在一块的开发包,可以工作在很多像UNIX的系统上,没GTK的平台限制。
1.GTK的消息处置机制
下面大家先看一个基本的例子,该例子产生一个200×200像素的窗口。它不可以自己退出,只能通过shell来杀死进程(调用kill命令)。
#include <gtk/gtk.h>
int main{
GtkWidget *window;
gtk_init ;
window = gtk_window_new ;
gtk_widget_show ;
gtk_main ;
return;
}
从上面的程序可以看出,GTK是一个事件驱动工具包,当它运行到gtk_main函数时会自动睡眠,直到有事件发生,控制权出售给相应的函数调用,在该函数中可以用标准C写出相应的事物逻辑。这与windows 上的程序处置是一样的。
对窗口对象上发生的事件(如按下鼠标,激活键盘等),GTK也有相应的消息信号产生。这个时候就需要技术员创建一个信号处置器来捕获该信号,并告诉GTK程序事件发生后调用什么回调函数。信号处置器的创建函数概念如下:
gint gtk_signal_connect;
返回值是一个区别同一对象中的事件与不同回调函数的关联标签。如此可以做到一个对象的一个信号就有任意多个回调函数,并且每个都会根据声明的顺序实行。函数调用的第一个参数是产生信号的widget组件(即按钮等窗口构件),而name则是期望捕获的信号或事件的名字,callback_func则是事件发生后所调用的回调函数名字,而第四个参数func_data则是传递给回调函数的参数。
回调函数要概念在主程序的前面,它们的一般格式都如下所示:
void callback_func;
调用下面这个办法将允许你将回调函数与事件的关联断开:
void gtk_signal_psconnect;
该函数的第二个参数就是上述gtk_signal_connect()函数的返回值,即关联标签。第一个参数指向了去除关联的对象名字。如此可以做到断开事件与回调函数的关联,使得事件发生后,不会调用有关的回调函数。
布局格式
2.1打包盒子
对GTK显示格式的控制是一般通过打包盒子来完成的。widget组件打包可以使用两种方法,水平盒子和垂直盒子。若将widget组件打包进平行盒子,组件就被依次水平的插入窗口;如果是垂直盒子,则组件排列是垂直的。产生新的水平盒子的函数为
GtkWidget *gtk_hbox_new ;
参数homogeneous是用来控制是不是盒子中的每一个组件都有同样的大小(比如水平盒子中的控件有同样的宽度,垂直盒子中的控件有同样的高度)。Spacing参数是组件之间的间隔。
垂直盒子的创建函数是gtk_vbox_new(),概念与水平盒子一致。
gtk_box_pack_start和gtk_box_pack_end函数是用来将打包对象放入这类盒子中的。
void gtk_box_pack_start;
第一个参数是你将组件打进来的盒子指针,第二个参数是你将要打进来的组件指针。Expand参数是用来控制是不是允许组件扩展至分配给盒子空间的大小(选TRUE),还是盒子的大小缩短到组件那样大(选FALSE)。函数中的fill参数是用来控制是不是将多余的空间分配给组件,马上组件扩展到盒子的大小(选TRUE),或者多余的空间不变,保留作为盒子和打包组件间的间隔。该参数只有在expand参数取TRUE时才有效。Padpng参数是指组件四周与盒子的间隔大小。
注意fill取FALSE值,expand取TRUE值时与expand取FALSE值,fill值无效有什么区别。前者的盒子仍是原来创建盒子时指定的大小,而后者的盒子已经缩小到打包组件的大小了。
gtk_box_pack_end函数的参数与上面描述的一致。只不过排列顺序分别是从下到上
,从右到左。
最后将所有些盒子或组件打包到一个大盒子中,用gtk_container_add函数将盒子加入窗口即可。
2.2表格打包
大家可以产生一个表格,将widget组件一一放入。Widget组件将占据所有分配给它的空间。创建表格是用下面的函数:
GtkWidget *gtk_table_new;
第一个参数,显而易见,是表格的行数。后面的参数则是表格的列数。homogeneous参数则是用来安排表格间隔大小。假如它取TRUE,则表格中每一个小格的大小用表格中最大组件的大小来设置的,所有些小格大小都是一样的。假如homogeneous参数取FALSE的,每一个小格的大小都用同行中最高组件的高度,同列中最宽组件的宽度。
将一个widget组件放入一个表格,用下面的函数:
void gtk_table_attach;
left_attach参数和right_attach参数将指出在什么地方放置组件,与用了多少盒子。假如你想在两行两列的表格中的右下小格中加入一个按钮,并且想让按钮充满那个小格,则参数可以选择left_attach = 1, right_attach = 2, TOP_attach = 1, bottom_attach = 2。其实left_attach也就是组件所在小格的左侧框是表格的第几条边数,其它依此类推。
参数xoptions和yoptions是用来确定打包选项的,可以用OR来选择多个选项。
调节器
GTK有不少组件可以用鼠标或键盘来调整,比如范围组件(Range Widget)。还有一些组件在整个数据地区的一部分是可调整的,比如文本组件(Text Widget)和视口组件(Viewport Widget)。
非常明显,程序是要可以对可调整组件所产生的变化进行处置。一种解决方法是让可调整组件在释放我们的信号时,将调整数据值传递信号处置器。或者用另外一种解决方案将调整数据值放入一个数据结构,由程序访问该结构来获得改变的参数值。有时你可能需要将几个可调整组件的调节有关联,调整一个也会致使另一个的变化。最明显的例子就是滚动条与文本编辑框组件的处置。假如这类有关联的组件分别有自己处置调整数据的办法,则技术员需要自己写一个信号处置器,将一个组件的调整数据转换成另一个组件的调整数据,并调用调整设置函数将该值设置进来。
GTK调用了调节器成功的解决了这个问题。调节器不是组件,而是存储和传递调整数据的结构。最典型的调整器应用是存储配置参数和范围组件的值。不一样的是调整器也是从对象(Object)继承而来的,它有很多不同于数据结构的特质。非常重要的是,它也会释放信号,并且这类信号不仅能够被程序捕获来响应用户的调整和编辑,还可以在可调整组件中透明的传播调整数据。
一般调节器会创建组件时自动创建。比如让文本组件和滚动条组件用同一个调节器如下所示:
text = gtk_text_new ;
vscrollbar = gtk_vscrollbar_new ->vadj);
调节器是从对象Object继承下来的。所以它与其它的组件对象一样,可以产生信号。当好几个组件共享一个调节器时,它们都会和一个信号处置器有关联。这个信号处置器是用来处置“value_changed”信号的,跟程序中处置信号是一样。下面是在GtkAdjustmentClass结构中该信号的概念:
void ;
不一样的可调整组件都用一个调节器时,任何一个组件发生调整变化都会产生该信号。有两种状况会致使这个现象的发生。第一种状况是用户在用鼠标或键盘调整该组件(比如拉滚动条),或者直接在程序中用gtk_adjustment_set_value函数来改变调节器中的value值。
当调节器的upper参数和lower参数被重新配置时,就象用户需要给一个文本编辑框加入了更多的文本后,调节器就会释放出“changed”信号。它的概念如下:
void ;
范围组件将该信号与一个信号处置器有关联,并随时在面板上反映参数的变化。举例,滚动条中滑动键的大小与调节器中upper,lower值之差正好成反比。一旦前者有任何改变,面板上的显示也会相应产生变化。
无需在程序中将一个信号处置器与该信号有关联,所有都是GTK完成的。假如你直接设置了调节器的这类参数,则需要在程序中调用下面的语句来释放信号:
gtk_signal_emit_by_name , "changed");
创建组件小结
从上面可看出,创建一个widget组件可以用以下几个步骤完成:
gtk_*_new—调用一个很有用的函数来产生一个新的widget组件。
4.2用gtk_box_pack_start()函数连接所有些信号和事件,产生相应的事件处置器来调用回调函数。
4.3设置widget组件与调节器的特质。
4.4用适合的函数将widget组件打包到一个容器(盒子或表格)中,比如gtk_box_container_start函数或者gtk_container_add函数等。
4.5用gtk_widget_show函数来显示组件。
用上述办法可创建出技术员所需要的任意窗口构件,再将容器打入窗口并显示窗口之后,程序便进入主循环睡眠状况,主程序编制也就结束了。事件的处置逻辑放到回调函数中编制。
编译程序用下面的命令:
gcc my_prog.c –o my_prog.o –lgtk –lgdk ↙
完成后在Xwindow环境下运行my_prog.o程序即可。
现在X窗口(Xwindow)和GNU编译系统已成为应用linux或unix操作系统的计算机工作站和大型计算机上最主要的图形用户界面系统,在微机上也有广
泛应用。而GTK正是两者结合的编程开发包。它比以往用的Xwindow/Motif编程更为简单便捷,功能也非常强大,有着较好的应用前景。现在网上已经有不少借助这款软件包开发出来的自由发布软件,很大的丰富了Linux平台的应用。
[参考文献]
1.《GTK Turtoil》 Peter Mattis, Spencer Kimball, Josh MacDonald著http://www.gtk.org
2.《linux系统管理指南》 M.F.Komarinski,C.Collet著 晓冬 马丁译 1999,清华大学出版社
3.《UNIX互联网编程》 W.Richard Stevens著 1998,清华大学出版