非常6 1 陈静怡:GTK相关【转载】

来源:百度文库 编辑:九乡新闻网 时间:2024/05/08 08:07:55
http://baike.baidu.com/view/1238103.htm

GTK+ (GIMP Tool Kit) 是一套图形函式库 (GUI, Graphical User Intreface),可用来建立 XWindow System 以图形为基础 (GUI-based) 的应用程式。一开始 GTK+ 是写来给 GIMP (GNU ImageManipulation Program) 图形处理软件使用的,不过随著 GNU/Linux 与 GNOME Desktop (使用了GTK+) 的流行,GTK+ 图形库已经慢慢普遍使用在各种工具中。虽然有了 GTK+,但是要用 GTK+ 来撰写程式并不是一件轻松的事,因为要完成一个GUI-based 的应用程式,得靠自己用熟悉的文书编辑器,一行一行把 C程式码敲出来。如果你是个抽象思考力非常好,又很有耐性写程式码的人,也许只要几个小时就能把 GTK+摸透;但如果你和我一样也是个懒堕的家伙,我想能撑个一小时来弄清楚 GTK+ 有什用,就可算是一件非常了不起的事了 :-)。还好,Glade的出现让我在想放弃前有了回心转意的念头。Glade 是 GTK+ 图形用户界面产生器 (Graphical UserInterface Builder for GTK+)。也就是说,Glade 是个 Visual Programming Tool,和Microsoft Windows 平台的 Visual Tools (VB、Delphi) 类似,只要用滑鼠拉一拉,它就会自动帮你产生 Csource code。所以我们这些懒人,就不用再去为画面的设计烦脑,用 Glade 设计好画面,再用编辑器把程式码稍为修修减减就 OK了。(现在也有各种语言如 C++、Ada95、Python、Perl 等的 GTK+ 介面,如果再搭配其它工具,也可以自动产生 C++,Ada95, Python and Perl 的程式码) 。

什么是Glade?

Glade是一个相当不错的图形界面设计工具,使用Glade可以使得基于GTK+ Toolkit及GNOME桌面环境的UI开发变得更加快速和便捷。用Glade设计的用户界面(User Interface)是以XML格式的文件保存的,它们可以通过GTK+对象GtkBuilder被应用程序动态地载入。通过GtkBuilder,Glade XML文件可以被许多编程语言使用,包括:C、C++、C#、Vala、Java、Perl、Python,等等。而且,Glade是在GNU GPL许可证(GNU GPL License)下的免费软件。

http://developer.gnome.org/gtk/2.24/GtkBuilder.html

A GtkBuilder is an auxiliary object that reads textual descriptionsof a user interface and instantiates the described objects. To pass adescription to a GtkBuilder, call gtk_builder_add_from_file() orgtk_builder_add_from_string(). These functions can be called multipletimes; the builder merges the content of all descriptions.

A GtkBuilder holds a reference to all objects that it has constructedand drops these references when it is finalized. This finalization cancause the destruction of non-widget objects or widgets which are notcontained in a toplevel window. For toplevel windows constructed by abuilder, it is the responsibility of the user to call gtk_widget_destroy()to get rid of them and all the widgets they contain.

The functions gtk_builder_get_object() and gtk_builder_get_objects()can be used to access the widgets in the interface by the names assignedto them inside the UI description. Toplevel windows returned by thesefunctions will stay around until the user explicitly destroys themwith gtk_widget_destroy(). Other widgets will either be part of alarger hierarchy constructed by the builder (in which case you shouldnot have to worry about their lifecycle), or without a parent, in whichcase they have to be added to some container to make use of them.Non-widget objects need to be reffed with g_object_ref() to keep thembeyond the lifespan of the builder.

The function gtk_builder_connect_signals() and variants thereof can beused to connect handlers to the named signals in the description. 


http://blog.programet.org/2010/09/gtk-2.html

几个概念

首先先来解释GTK+中几个基本的概念,以方便将来的分析。

物件(GtkWidget):GTK+中每一个窗口里的组成要素都被视为一个物件,如按钮、文本等等,窗口本身也是一个物件。总之GTK+的界面就是由物件构成的。注意,物件都使用指针来管理,物件外在表现就是一个特定类型的指针。

容器(GtkContainer):物件里的一大类,容器的特点是其内部能够容纳其他物件。容器最基本的功能之一是将各种物件良好地组织起来。GTK+的容器能在大小改变时自动调整内含物件的大小,这使得GTK+能够很智能地相应窗口或其他物件的大小改变。这为我们提供了很大的方便,往往我们不需要指定某个物件的大小,只需说明他所在的容器位置,GTK+会把物件的实际位置和大小自动计算出来(这比MFC强多了!)。

继承、组合:虽然是C语言写的,但GTK+灵活地运用了面向对象思想。GTK+的物件体系中就有继承、组合这样的关系,如窗口(GtkWindow)是由容器(GtkContainer)派生出来的。

类型转换宏:C语言本身没有“继承”这个概念,那么,如果直接把派生的物件直接当做基物件使用,会出现一个编译警告,即“隐式指针类型转换”,但不会出错。为了消除这个警告,需要做指针类型转换。一般情况下类型转换使用类型转换宏。类型转换宏内部会检查物件的继承关系,确定能否进行转换,然后再做显式类型转换。

事件(event):用户的操作,比如按下某个按钮或快捷键,被视为一个事件。

信号(signal):GTK+是基于信号回调(signal-slot)机制的。信号捆绑了一个事件和一个函数,在用户触发这个事件时,这个函数会被调用一次。从这个角度来说,GTK+是基于物件的,即程序围绕物件属性、事件、方法进行。

主循环(mainloop):GTK+程序在一个主循环中运行。当一个事件被触发时,它将被插入队列中;在主循环中被触发的事件会被逐个处理(和这个事件绑定的函数被逐个调用);没有事件被触发时,程序就处于等待状态,等待下一个事件被用户触发。直到退出主循环的函数被调用,GTK+程序才结束。

GTK+命名规范

GTK+拥有开源软件的很多特点,比如结构高度严谨,可读性甚好。现在介绍一下GTK+的关键字命名方式,以便阅读一段GTK+程序。

普通变量类型名:全小写写法,以“g”开头,如“gint”。

物件类型名:驼峰写法(首字母大写),以“Gtk”开头,形如“GtkWindow”。在GTK+内部,类型是向下面这样定义的(以GtkWindow为例)。

typedef _GtkWindow { ... } GtkWindow;

函数名:小写夹下划线写法,以“gtk_”为前缀,形如“gtk_main()”。如果是针对某类物件的函数,则前缀中还有物件类型名,形如“gtk_window_new()”。

常数名:大写夹下划线写法,以“GTK_”为前缀,形如“GTK_WINDOW_TOPLEVEL”。

类型转换宏:大写夹下划线写法,以“GTK_”为前缀。一般来说,宏名字和类型名相仿,比如要把GtkWindow*类型的物件转换为GtkContainer*类型,就使用宏“GTK_CONTAINER()”。

GTK+的“Hello World”

下面这段程序是GTK+的Hello World,它创建一个普通窗口,里面只有一句“Hello, World”。在前文的基础上,可以分析一下这一段Hello World。

//下面来分析一下这其中每句话的含义,介绍如何初始化GTK+,使C语言程序在GTK+环境下运行。                         #include  //包含gtk库                         int main (int argc, char *argv[])            {            GtkWidget *window;            GtkWidget *label; //定义两个物件指针,用于操作物件。                         //这一句是所有GTK+程序必须的:初始化GTK+库。每个GTK+程序必须用这个来使GTK+做好准备。            gtk_init (&argc, &argv);                         //接下来这三句用于建立并设置一个窗口,几乎所有的GTK+程序都要新建窗口。                         //建立一个新窗口,让window指向它。之后window就相当于这个窗口了。目前窗口中不包含任何物件。            window = gtk_window_new (GTK_WINDOW_TOPLEVEL);                         //设置window标题为“Hello World”。            //这里使用了类型转换宏GTK_WINDOW()。因为这里函数参数需要是GtkWindow*型,而window在定义的时候是GtkWidget*型的。            gtk_window_set_title (GTK_WINDOW (window), "Hello World");                         //连接信号:将window的关闭(destroy)事件与退出主循环函数gtk_main_quit()绑定在一起,即窗口被关闭时程序结束。            //G_CALLBACK()也是一个类型转换宏,它把普通函数变成信号回调函数。            g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);                         //接下来写入窗口内容。窗口只包含一个文本(GtkLabel)。                         //新建一个GtkLabel,让label指向它。之后label就相当于这个文本了。            label = gtk_label_new ("Hello, World");                         //把label插入母容器中。把window转换为容器(这是允许的,因为GtkWindow由GtkContainer派生),然后插入label。            gtk_container_add (GTK_CONTAINER (window), label);                         //接下来这两句也是所有GTK+程序必须的。                         //显示所有物件。物件新建好后是隐藏的,用这个函数来显示window及它包含的内容。            gtk_widget_show_all (window);                         //进入主循环,开始接受用户操作并处理各种事件。            gtk_main ();                         return 0;            }

程序内容很简洁,它只处理一个事件:关闭窗口。但是这个程序已经摆出了GTK+程序主函数编写的基本形式:使用gtk_init()初始化;建立窗口、组织窗口内容并连接信号;显示窗口;进入主循环。此外,编写回调函数并动态修改窗口内容通常也是必须的。基本所有GTK+程序都遵循这个规律。

可以想见的是,建立窗口、组织窗口内容是非常麻烦的事情。于是界面设计器应运而生,使得组织界面的工作不再由代码完成。下一部分内容会介绍使用界面设计器Glade的方法。

另外,有关GTK+物件、函数、常数的说明都可以在GTK+参考中找到。记得收藏GTK+参考的网址http://library.gnome.org/devel/gtk/stable/index.html,将来查找函数就靠它了!

http://blog.programet.org/2010/09/gtk-3.html

这一部分包括GTK+相关组件的简要介绍,和界面设计器的使用方法。如果内容存在错误,或者方法不适用与你的电脑,请在下方评论区留言给我,谢谢!

GTK+的姊妹库

准确地说,GTK+仅指一个界面物件库。为了制作GTK+,一些副产品相继诞生,比如C语言界很有名的的GLib库。这些GTK+的“姊妹库”都是GTK+所依赖的,而且,制作GTK+程序时可能需要直接使用这些库。

  • GLib:目前最好的C语言数据结构库之一。除数据结构外,它还包括许多常用小工具,比如多线程管理、定时器。GTK+界面无关的部分基本都被并入GLib中。
  • GIO:GLib库相对独立的一部分,专门处理输入输出流。新版本的GIO还包括了网络连接功能。
  • GObject:GLib库相对独立的一部分,维护一套对象系统。GTK+疯狂地使用这个系统。
  • ATK:ATK提供一组查看和控制接口以方便对GTK+程序的访问。
  • pango:负责处理GTK+中和字体有关的部分。
  • cairo:著名的2D渲染库,被Firefox等很多程序使用。它也是目前GTK+使用的2D渲染库,通过它可以进行矢量绘图。
  • gdk-pixbuf:GDK的一个部分,提供了一组位图函数,包括位图变换、位图文件读写等等。
  • GDK:提供一组接口,把GTK+从桌面系统细节中隔离出来。它是一组底层函数,可以直接访问窗口细节。GTK+系统有关的部分多数在这里。

这些库的API参考都可以在GNOME参考(http://library.gnome.org/devel/references.html.zh_CN)中找到。

还有一些库是GTK+依赖的第三方库,下面是几个重要的。

  • gettext:国际化库。主要用于制作多语言程序。运行时gettext自动识别操作系统语言,然后从已有语言包中选择一个最合适用户的。
  • iconv:字符集转换库。GTK+内部使用UTF-8字符集,有时需要字符集转换。

GTK+内部构成

GTK+本身只负责界面组织。它提供的函数大致可分为三类,物件(Widget)、对象(Object)和其它工具函数。

工具函数提供一些与界面关系密切的实用功能,比如剪贴板读写。

对象是一些功能更加复杂的不可见元素,它们和界面息息相关,比如GtkBuilder。

界面设计器Glade

通过代码来组织界面繁琐而不直观,因而有人为GTK+做了一款界面设计器,名为Glade,现已成为GTK+最重要的辅助工具。

接下来用一个计算器制作的实例来讲解GTK+界面设计器的使用方法。

打开Glade。Glade会自动新建一个文件,新建后会弹出对话框设置文件格式,应选用GtkBuilder。

首先建一个窗口。在左栏中找到“窗口”一项,点一下即可。中间部分的黑框即为窗口中的内容。

下面要组织窗口中的内容了。要注意的是,一个灰色区域只能放置一个物件。如果需要放置多个物件,可以使用水平框、垂直框或表格物件,这些容器可以把一个灰色区域分成多个。

添加Spin按钮(Spin按钮用于输入数字)、表格、按钮等物件,可以把界面画成想要的样子,在右下方的属性设置中,可以设置物件的各种属性。在“常规”选项卡中,可以设置一些重要的初始值,物件名等。注意:需要动态更改的物件,物件名很重要。

“包装”选项卡负责物件的间距控制和大小改变方式等。GTK+在窗口大小改变时会智能地调整物件大小,其依据的就是这个选项卡里的设置。

计算器的界面成形了。记得经常保存,Glade有时会比较脆弱。

注意:在输入完某项属性之后务必使输入焦点离开当前输入区,然后才可以保存文件,否则当前输入区的更改不会被立即保存到文件中。

载入界面

Glade文件的本质是个XML文件,这个文件可以用GtkBuilder对象载入并生成界面。下面这样写可以载入一个Glade文件。

GtkBuilder* gtk_load_glade(gchar* filename)            {            GtkBuilder *gb;                         //新建一个GtkBuider对象            gb=gtk_builder_new();            //载入文件,失败则返回NULL            if(!gtk_builder_add_from_file(gb,filename,NULL))return NULL;            //连接文件中包含的所有信号            gtk_builder_connect_signals(gb,NULL);                         //返回GtkBuilder对象供后面操作使用            return gb;            }

载入后还需要还需要获得已载入的物件地址,并将储存在物件指针里以便以后动态更改物件。一个聪明的策略是使指针名字和物件在Glade里设置的名字一样。用函数gtk_builder_get_object()可以获得指定名字的物件地址。为了简便,可以写一段宏代替冗长的函数调用。下面这段代码演示了获得主窗口(名为WMain)和Spin按钮(名为SAns)地址的方法。

#define w_(builder,type,name) name=GTK_##type(gtk_builder_get_object(builder,#name))                         GtkWindow *WMain;            GtkSpinButton *SAns;                         void cal_get_widgets(GtkBuilder* gb)            {            w_(gb,WINDOW,WMain);            w_(gb,SPIN_BUTTON,SAns);            }

主窗口开始时是不显示的,应该用下面这个函数把它显示出来。下面这个函数只能在获得物件地址后执行。

void cal_widget_init()            {            gtk_widget_show(GTK_WIDGET(WMain));            }

编写回调函数

现在的主要任务就是编写回调函数——这些函数才是程序的主角。在某个事件被触发时,对应的函数会被执行。这个函数可以在Glade中指定。在Glade中选定某个物件,然后在右下角“信号”选项卡中选择一个合适的事件,在“操作句柄”列填入函数名。

下面为窗口WMain指定destroy事件的回调函数on_WMain_destroy()。

然后编写一个函数on_WMain_destroy()。在Windows下,这个函数要加上修饰词G_MODULE_EXPORT。

G_MODULE_EXPORT void on_WMain_destroy(GtkObject* widget, gpointer user_data)            {            gtk_main_quit();            }

这个回调函数只是退出程序而已。最后献上一段main()。

int main(int argc, char *argv[])            {            GtkBuilder *gb;                         gtk_init(&argc,&argv);                         gb=gtk_load_glade("gtk-cal.glade");            if(gb==NULL)return -1;            cal_get_widgets(gb);            cal_widget_init();                         gtk_main();                         return 0;            }

这个计算器程序目前只完成了最基本的部分,这个系列后续的文章会把它做完。有关回调函数、物件函数的信息,请参考GTK+ API参考。