原文地址:http://blog.programet.org/2010/08/gtk-0.html
GTK+是当下流行的图形界面库之一,使用GTK+可以方便地构造出应用程序界面。叶子觉得GTK+很好用,在这里推荐给大家,并留下自己的一些使用心得。希望你也喜欢~
在Programet这个系列中,你可以看到GTK+通俗的介绍,了解使用方法和常用API,我们希望能对你有所帮助。下面是这个系列的内容线索(本系列不断更新中,这个列表可能随更新而有少量变化):
上面的列表中并没有“GTK+介绍”一项,因为我要在这篇文章后半部分完成它!
GTK+是图形界面库,能帮助我们简洁方便地绘制窗口和里面的输入框、按钮等等。这能减少我们很多麻烦——有经验的童鞋可能深有体会,图形界面几乎是应用程序编写中最繁琐的部分。图形界面库就是为了方便我们组织界面而出现的,使用它可以大大减少我们花在组织界面上的代码量。
同时,GTK+可以配合界面设计器Glade,换句话说,做界面不用敲冗长的代码,界面可以画出来!
更重要的是,GTK+是跨平台的。只要代码写得标准,在Windows、Linux和Mac OS下,不用做任何修改就可以展现出同样的界面,方便吧~
GTK+是一个开源跨平台的库,支持很多平台,这里就不一一列举了。它遵循LGPL协议,也就是说我们可以自由地使用它,使用它制作的程序可以自行选择开源与否。
GTK+是用C语言编写的,很多GTK+应用程序也使用C语言完成。但如果你讨厌C语言的话,你同样可以选用其他多种语言,包括C++、Java、Python等等,甚至还可以是PHP。而且在各种语言中的API很相似,这让我们在各种语言下玩GTK+变得很方便。
GTK+现在为很多软件所使用,最典型的是Linux桌面环境GNOME和Xfce,包括在它们中运行的众多软件(很多时候GNOME和Xfce软件可以混用,因为他们都是GTK+的)。
还有号称“开源PS”的GIMP、矢量图编辑器Inkscape等等,还有只是使用部分GTK+库(尤其是GLib)的众多软件,还有偷偷拿GTK+代码来用的软件……
目前,还有很多流行的图形界面库:
还有其他的一些,这里就不提了吧。
毫无疑问的是,GTK+是它们中很有特点的一个。你很难找出第二个C语言图形界面库。GTK+以架构严谨优秀高效著称,是GNU项目的一部分,像是很标准的GNU式的开源项目。它和GNU项目中的其他部分配合良好,遇到麻烦时,常常可以让其他库帮忙。
GTK+是1999年开始发展的一个项目,在图形界面库中算很年轻的,但是发展飞速,以至于网络上对其的描述都难以跟上其发展(现在搜索到的很多描述不正确)。GTK+一直由社区维护,但同时又备受众多商业公司青睐,应用领域在不断扩展中。
在这一系列文章中,GTK+原生语言——C语言将被用来举例,其他语言使用方法类似,具体请参见不同语言的文档。这也要求读者能熟练运用C语言。
文章中的例子使用Windows下的GTK+ 2.16(GLib 2.24)编译通过,并特别照顾Windows下的配置、使用,相较而言,在Linux下的配置、使用简单一些。
这一部分介绍的是在Windows/Linux下配置GTK+(C语言)编译及运行环境的方法。如果内容存在错误,或者方法不适用与你的电脑,请在下方评论区留言给我,谢谢!
Linux的X Window是GTK+主要应用的地方,在Linux下配置GTK+应该是比较容易成功的。当然,你的Linux需要有GNOME或Xfce这样的桌面环境(不建议在KDE下运行GTK+应用程序)。
如果你的Linux像Ubuntu这样有一个软件库,那就太方便了,直接安装包libgtk2.0-dev即可。如果不能直接安装软件包,你还可以直接到http://www.gtk.org/download-linux.html下载,那个安装指南会对你有帮助的。
然后是编辑器的问题。像Anjuta这样的编辑器可以直接创建GTK+项目,你可以利用这个功能,很方便。如果你的编辑器不能创建GTK+项目,或者你根本不打算用编辑器,你可以用pkgconfig命令获得你用gcc编译时所需的参数:
pkg-config --cflags --libs gtk+-2.0 |
这一系列以后的文章中会用到Glade界面设计器,请安装包glade或到http://ftp.gnome.org/pub/GNOME/sources/glade3/3.6/下载Source来编译。要注意的是,Glade本身也是一个GTK+应用程序,需要在GTK+的桌面环境中运行。
在Windows下配置编译环境就有些麻烦。这里看来要用支持创建GTK+项目的编辑器来帮忙了。
这里介绍在Code::Blocks编辑器和MinGW GCC编译器下编译GTK+程序的方法。(其实在Visual Studio下也可以编译GTK+的,但是这里不推荐。)
装好Code::Blocks
如果你不熟悉Code::Blocks,建议看看我以前写的这篇文章。
安装GTK+开发库和Glade界面编辑器
这里介绍一个简单的方法。Glade有的发布版直接包含有GTK+开发库。到Glade主页http://glade.gnome.org/右边的Windows Binaries中找Glade3-x.x.x-with-gtk.exe这样的版本下载安装。建议装到C:\gtk\。
但是可能Glade自带的GTK+开发库不是最新的,无法实现一下高版本的GTK+提供的功能,因此最好到GTK+下载页http://www.gtk.org/download-windows.html下载一个All-in-one bundles。下载下来之后直接解压到刚刚Glade的安装目录即可。
在Code::Blocks中建立GTK+项目
Code::Blocks中,File->New->Project中应该会有GTK+ Project这一选项。按着向导新建即可,但要注意几个地方:项目文件完整路径必须是英文的,Code::Blocks对中文路径和文件名支持不佳;GTK’s location必须指定为你刚刚安装的GTK+开发库所在文件夹。
就拿Code::Blocks为我们自动生成的这段程序做测试吧:
#include |
这段程序会建立一个有两个按钮的窗口。Windows下还会另外有个小黑窗口,方便调试用的;指定Build->Select target->Release之后再编译,编译出来的“Release”版本就没有小黑窗口了。
如果你编译失败——不幸,但是你可以在下面留言给我。
你需要明白的是,GTK+是需要运行库的——Linux下一般都会自带有,Windows下就没那么幸运了。如果你的程序需要在别人的电脑上运行,你往往需要附带一个GTK+运行库,运行库的制作方法是把http://www.gtk.org/download-windows.html中的所有Binary组合起来。
为了方便大家,我自己做了一个运行库,经过一定精简(只有中英两种语言),大小13MB(压缩后3MB)。大家可以到这里下载。
用法就是把程序及程序用到的文件放进来,使程序与运行库的那堆dll在同一级文件夹下。然后整个文件夹就可以作为便携软件在不含GTK+的Windows中使用了。
另外,GTK+运行库是支持主题的。你可以为GTK+指定主题,给那些按钮换一个样子。GTK+主题文件位于运行库的\etc\gtk-2.0文件夹中,名为gtkrc。我制作的运行库指定了GTK+使用Windows主题。你可以在网上搜出很多GTK+ themes,使用方法就是替换gtkrc文件。
原文地址:http://blog.programet.org/2010/09/gtk-2.html
这一部分是对最简单的GTK+(C语言)程序的一个解释,并介绍GTK+的基本概念和运作方式。如果内容存在错误,或者方法不适用与你的电脑,请在下方评论区留言给我,谢谢!
首先先来解释GTK+中几个基本的概念,以方便将来的分析。
物件(GtkWidget):GTK+中每一个窗口里的组成要素都被视为一个物件,如按钮、文本等等,窗口本身也是一个物件。总之GTK+的界面就是由物件构成的。注意,物件都使用指针来管理,物件外在表现就是一个特定类型的指针。
容器(GtkContainer):物件里的一大类,容器的特点是其内部能够容纳其他物件。容器最基本的功能之一是将各种物件良好地组织起来。GTK+的容器能在大小改变时自动调整内含物件的大小,这使得GTK+能够很智能地相应窗口或其他物件的大小改变。这为我们提供了很大的方便,往往我们不需要指定某个物件的大小,只需说明他所在的容器位置,GTK+会把物件的实际位置和大小自动计算出来(这比MFC强多了!)。
继承、组合:虽然是C语言写的,但GTK+灵活地运用了面向对象思想。GTK+的物件体系中就有继承、组合这样的关系,如窗口(GtkWindow)是由容器(GtkContainer)派生出来的。
类型转换宏:C语言本身没有“继承”这个概念,那么,如果直接把派生的物件直接当做基物件使用,会出现一个编译警告,即“隐式指针类型转换”,但不会出错。为了消除这个警告,需要做指针类型转换。一般情况下类型转换使用类型转换宏。类型转换宏内部会检查物件的继承关系,确定能否进行转换,然后再做显式类型转换。
事件(event):用户的操作,比如按下某个按钮或快捷键,被视为一个事件。
信号(signal):GTK+是基于信号回调(signal-slot)机制的。信号捆绑了一个事件和一个函数,在用户触发这个事件时,这个函数会被调用一次。从这个角度来说,GTK+是基于物件的,即程序围绕物件属性、事件、方法进行。
主循环(main loop):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,它创建一个普通窗口,里面只有一句“Hello, World”。在前文的基础上,可以分析一下这一段Hello World。
//下面来分析一下这其中每句话的含义,介绍如何初始化GTK+,使C语言程序在GTK+环境下运行。 #include |
程序内容很简洁,它只处理一个事件:关闭窗口。但是这个程序已经摆出了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+,一些副产品相继诞生,比如C语言界很有名的的GLib库。这些GTK+的“姊妹库”都是GTK+所依赖的,而且,制作GTK+程序时可能需要直接使用这些库。
这些库的API参考都可以在GNOME参考(http://library.gnome.org/devel/references.html.zh_CN)中找到。
还有一些库是GTK+依赖的第三方库,下面是几个重要的。
GTK+本身只负责界面组织。它提供的函数大致可分为三类,物件(Widget)、对象(Object)和其它工具函数。
工具函数提供一些与界面关系密切的实用功能,比如剪贴板读写。
对象是一些功能更加复杂的不可见元素,它们和界面息息相关,比如GtkBuilder。
通过代码来组织界面繁琐而不直观,因而有人为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参考。
这一部分内容介绍有关GTK+常用窗口类物件的一些函数。如果对内容有疑问,请在下方留言,谢谢!
窗口是GTK+最基本的物件之一,物件要被放在窗口里显示。GTK+里,常用的窗口包括顶级窗口(GtkWindow)、对话框(GtkDialog)和消息对话框(GtkMessageDialog)等。
GTK+有关窗口的操作很多,绝大多数情况下可以满足自定义窗口的需求;但有时候还是不可避免要直接访问底层库GDK。要注意的是,GdkWindow与GtkWindow有很大差异,GdkWindow指一个显示区域,每一个可显示的GTK+物件都对应一个GdkWindow,阅读文档时两者不可混淆。
窗口类物件在Glade中得到了良好的支持,复杂的窗口建议直接用Glade创建。
消息对话框是最简易的窗口,如果还在Glade中创建的话,很麻烦且会使Glade文件变得更大。下面这些函数,可以快速创建一个窗口而不需要Glade。
void gtk_show_info(gpointer window, const gchar* message, const gchar* title) { GtkWidget *dialog; dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, message); gtk_window_set_title(GTK_WINDOW(dialog), title); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(GTK_WIDGET(dialog)); } void gtk_show_error(gpointer window, const gchar* message, const gchar* title) { GtkWidget *dialog; dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, message); gtk_window_set_title(GTK_WINDOW(dialog), title); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } gint gtk_show_question(gpointer window, const gchar* message, const gchar* title) { gint i; GtkWidget *dialog; dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, message); gtk_window_set_title(GTK_WINDOW(dialog), title); i=gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); if(i==GTK_RESPONSE_YES) return 1; else return 0; } void gtk_show_warning(gpointer window, const gchar* message, const gchar* title) { GtkWidget *dialog; dialog = gtk_message_dialog_new_with_markup(window, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, message); gtk_window_set_title(GTK_WINDOW(dialog), title); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } |
以上四个函数分别是一个信息窗口、错误提示窗口、询问窗口、警告窗口,三个参数分别是母窗口、窗口内文字内容、窗口标题。在程序中直接调用函数即可。
文件选择对话框同样可以不用Glade创建,而直接调用API方便地创建。下面的函数可以创建文件打开对话框和文件保存对话框。
GtkWidget* gtk_show_file_add_filter(GtkWidget* dialog, const gchar *description, gchar *pattern) { GtkWidget *filter; filter=GTK_WIDGET(gtk_file_filter_new()); gtk_file_filter_set_name(GTK_FILE_FILTER(filter),description); gtk_file_filter_add_pattern(GTK_FILE_FILTER(filter),pattern); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog),GTK_FILE_FILTER(filter)); return filter; } gchar* gtk_show_file_open(GtkWidget* parent_window, const gchar *title, const gchar *filters) { GtkWidget *dialog,*FF[16]; gchar *filename,des[256],pattern[64]; long i,j,FFc=0; dialog = gtk_file_chooser_dialog_new (title, GTK_WINDOW(parent_window), GTK_FILE_CHOOSER_ACTION_OPEN, /*GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,*/ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); //filters for(i=0;i<strlen(filters);i++) { j=0; while(i<strlen(filters) && filters[i]!='|') des[j++]=filters[i++]; if(j>=256)break; des[j]=0; j=0; i++; if(i>=strlen(filters))break; while(i<strlen(filters) && filters[i]!='|') pattern[j++]=filters[i++]; if(j>=64)break; pattern[j]=0; FF[FFc++]=gtk_show_file_add_filter(dialog,des,pattern); if(FFc>=16)break; } if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gtk_object_destroy(GTK_OBJECT(dialog)); return filename; } return NULL; } gchar* gtk_show_file_save(GtkWidget* parent_window, const gchar *title, const gchar *default_folder, const gchar *default_name, const gchar *filters) { GtkWidget *dialog,*FF[16]; gchar *filename,des[256],pattern[64]; long i,j,FFc=0; dialog = gtk_file_chooser_dialog_new (title, GTK_WINDOW(parent_window), GTK_FILE_CHOOSER_ACTION_SAVE, /*GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,*/ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); if(default_folder[0]!=0)gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), default_folder); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), default_name); //filters for(i=0;i<strlen(filters);i++) { j=0; while(i<strlen(filters) && filters[i]!='|') des[j++]=filters[i++]; if(j>=256)break; des[j]=0; j=0; i++; if(i>=strlen(filters))break; while(i<strlen(filters) && filters[i]!='|') pattern[j++]=filters[i++]; if(j>=64)break; pattern[j]=0; FF[FFc++]=gtk_show_file_add_filter(dialog,des,pattern); if(FFc>=16)break; } if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); gtk_widget_destroy (dialog); return filename; } //destroy gtk_widget_destroy (dialog); for(i=0;i<FFc;i++) gtk_object_destroy(GTK_OBJECT(FF[i])); return NULL; } |
gtk_show_file_open()建立一个文件打开窗口供用户选择文件,参数依次是母窗口、标题、过滤器。
gtk_show_file_save()建立一个文件保存窗口供用户选择文件,参数依次是母窗口、标题、默认文件夹、默认文件名、过滤器。
其中“过滤器”是一串字符,字符内用“|”分离,其形式像这样:文件类型名称1|对应通配符1|文件类型名称2|对应通配符2|……
GTK+提供好了丰富的功能,但也有缺陷——某些常用功能无法直接使用,需要访问GDK库。下面这个函数,用来确定窗口是不是处于全屏状态。
gboolean gtk_window_is_fullscreen(GtkWindow* window) { return (gdk_window_get_state(gtk_widget_get_window(GTK_WIDGET(window))) & GDK_WINDOW_STATE_FULLSCREEN) == GDK_WINDOW_STATE_FULLSCREEN; } |
其他用法,请参阅GTK+参考。
原文地址:http://blog.programet.org/2010/10/gtk-5.html
这一部分内容介绍有关GTK+常用文本类物件的一些函数。如果对内容有疑问,请在下方留言,谢谢!
显示文字和控制文本框自然是界面重头戏,基本每个窗口都离不开这样的物件。GTK+中和文本有关的物件主要有:文本标签(GtkLabel,以下简称“文本”),输入框(GtkEntry),可编辑多行文本(GtkTextView,以下简称“多行文本”),调节按钮(GtkSpinButton)。各物件有自己的优点。
具体使用哪个物件需要根据实际情况决定。
对文本类物件的操作基本相似。对这些物件的动态访问基本归结为以下两种——读取所包含的文字信息(读)、设置所包含的文字内容(写)。其他的设置基本不需要动态改变,初始时在Glade中设置好即可(如果真的需要修改,自己去看参考吧)。
下面这些函数用于对文本、输入框的读写,函数名字都很好记。
//写入文本内容 void gtk_label_set_text(GtkLabel *label, const gchar *str); //读取文本内容 const gchar* gtk_label_get_text(GtkLabel *label); //写入输入框内容 void gtk_entry_set_text(GtkEntry *entry, const gchar *text); //读取输入框内容 const gchar* gtk_entry_get_text(GtkEntry *entry); |
调节按钮是用于操作数字的,因而可以直接向其中写入或者读出实数或整数。
//设置调节按钮的数值 void gtk_spin_button_set_value (GtkSpinButton *spin_button, gdouble value); //读出调节按钮的数值 gdouble gtk_spin_button_get_value (GtkSpinButton *spin_button); gint gtk_spin_button_get_value_as_int(GtkSpinButton *spin_button); |
做个实例吧。本系列第三部分做了一个计算器雏形,下面来稍稍完善一下。
计算器的上方有一个名为SAns的调节按钮,下面增加一个功能:当调节按钮的值的绝对值过大(大于等于常数CAL_ABS_MAX)时,弹出错误提示窗口。
每个调节按钮对应一个GtkAdjustment,首先应为调节按钮添加一个GtkAdjustment。在Glade中,点“常规”的“调整部件”右侧的“…”,弹出窗口中点“New”。
此时上方的物件选择栏末尾中会出现一个对象adjustment1,可以更改它的属性,即调节按钮的最值、步长等。
然后为SAns的信号value-changed添加操作句柄“on_SAns_value_changed”,然后在程序中添加相应回调函数。
回到程序中,在初始化时,用gtk_spin_button_set_range()修改调节按钮取值范围为[-CAL_ABS_MAX,CAL_ABS_MAX],再编写回调函数on_SAns_value_changed(),顺便用上上一部分写的函数gtk_show_error()。完整代码如下。
#include |
在以后的内容中,这个计算器将被逐渐完善。
多行文本的使用比较复杂,涉及几个其他对象的使用。一个多行文本的内容储存在一个缓冲区GtkTextBuffer中,这个缓冲区需要用迭代器GtkTextIter访问、用GtkTextMark标记,文字样式用GtkTextTag设置。
看起来真的有些复杂。不过最基本的应用还是读、写。下面给出三个函数,可以直接读写多行文本。这几个函数基本够用了。
//读取多行文本中的文字内容 gchar* gtk_text_view_get(GtkTextView *text_view) { GtkTextBuffer *tb; GtkTextIter st,stp; tb=gtk_text_view_get_buffer(text_view); //获取对应的GtkTextBuffer gtk_text_buffer_get_start_iter(tb,&st); //获得起始点 gtk_text_buffer_get_end_iter(tb,&stp); //获得结束点 return gtk_text_buffer_get_text(tb,&st,&stp,FALSE); //获得两点间所有字符 } //在多行文本末尾追加文字,文字样式包含在text_tag中,如果不需要指定样式,text_tag设为NULL void gtk_text_view_append_with_tag(GtkTextView* text_view, const gchar* text, GtkTextTag* text_tag) { GtkTextBuffer *tb; GtkTextIter stp; tb=gtk_text_view_get_buffer(text_view); gtk_text_buffer_get_end_iter(tb,&stp); gtk_text_buffer_insert_with_tags(tb,&stp,text,strlen(text),text_tag,NULL); //在结束点处追加字符 gtk_text_buffer_get_end_iter(tb,&stp); gtk_text_view_scroll_to_iter(text_view,&stp,0,FALSE,0,0); //将光标置于结束点 } //清空多行文本 void gtk_text_view_clear(GtkTextView *text_view) { gtk_text_buffer_set_text(gtk_text_view_get_buffer(text_view),"",0); //设置文本内容为空 } |
此外,样式可以这样新建:
gtk_text_buffer_create_tag(gtk_text_view_get_buffer(text_view), tag_name, property1, value1, property2, value2, ... , NULL); |
text_view是多行文本名字;tag_name是一个字符串,值不能和别的样式相同;property1,2,3,…各属性名字(字符串形式),可用的属性参见http://library.gnome.org/devel/gtk/unstable/GtkTextTag.html中的Property栏;value1,2,3,…各属性对应的值(字符串形式)。
如果以上的方法不够用,只好查参考了。
小提醒:多行文本一般都需要放在滚动区(GtkScrolledWindow)里面。
要注意的问题是,GTK+内部使用UTF-8编码。在处理非ASCII编码的字符串时,切不可使用C语言string.h里的函数。在UTF-8中,字符含义比较复杂。还好,GLib中提供了很多用于处理多种编码字符串的函数,下面介绍一些用于处理UTF-8字符串的函数。
在http://library.gnome.org/devel/glib/stable/glib-Unicode-Manipulation.html中介绍了很多有关UTF-8字符串的实用函数。这些函数命名与string.h里的常用函数相近,只是多了前缀g_utf8_,表示是专门用来处理UTF-8字符串的。介绍几个吧。
在http://library.gnome.org/devel/glib/stable/glib-String-Utility-Functions.html列出了一些跨字符集的实用函数,适用于任何字符集。其中有一部分常常能用上,比如g_snprintf()和g_strdup_printf(),它们的功能与C语言sprintf类似,都是把一串格式输出写进字符串里(常用于数字和字符混合输出到字符串里),但g_snprintf()和g_strdup_printf()更安全。g_snprintf()需要指定目的字符串长度,避免输出越界;g_strdup_printf()则在函数内部自行申请足够的空间存放目的字符串(注意它返回的字符串废弃之后需要用g_free()释放空间)。
在http://library.gnome.org/devel/glib/stable/glib-Character-Set-Conversion.html有一些字符集转换的函数,有些需要字符集转换的场合会用得上(比如文件名可能不是UTF-8编码,有时需要转换)。
原文地址:http://blog.programet.org/2011/03/gtk-6.html
这一部分内容介绍有关GTK+常用按钮、选择框物件的一些函数,以及相关的使用技巧。如果对内容有疑问,请在下方留言,谢谢!
GTK+提供了各种各样的按钮,功能丰富,能满足各种不同的需求。按钮可大致分为下面几种:
此外还有一些别的按钮,可以提供丰富的细节功能。想用的话请自行查参考。
Glade对它们提供了很好的支持。尤其是提供了菜单编辑器,菜单完全不用写代码构建,这提供了很大的方便。对于可以在Glade中完成的部分,这里不再多做介绍。
按钮和选择框在运行时较少被动态更改,使用这些物件最主要的还是获取信号执行操作。在第三部分的末尾已经介绍了链接信号的基本方法:在Glade中想要连接的信号,输入回调函数名,在程序中编写回调函数。
对于普通按钮,“clicked”肯定是最常用的一个信号。而对于复选框和双态按钮,应当使用“toggled”信号,不建议使用其他信号代替。因为在这个信号被触发时,按钮的状态已经被改变了,可以立即使用gtk_toggle_button_get_active()函数获得按钮的最新状态。
有时,按钮在一起时比较便于管理,因而时常会把物件放入数组中管理。这需要在获取物件地址时把物件地址存入数组中。聪明的做法是,在Glade中命名物件时起有规律的名字。
下面继续编写计算器程序来展示这种手段。
计算器的0~9这10个按钮操作是类似的,因而可以放在数组中管理。首先为按钮起类似的名字:BNum0,BNum1,BNum2,…,BNum9。获取物件的函数原型如下:
GObject* gtk_builder_get_object(GtkBuilder *builder, const gchar *name); |
因而可以用这段代码把物件放入一个数组中:
GtkButton *BNum[10]; gint i; gchar s[6]; strcpy(s,"BNum_"); for(i=0;i<10;i++) { s[4]=i+'0'; BNum[i]=GTK_BUTTON(gtk_builder_get_object(builder,s)); } |
小提示:如果物件超过了10个,可以使用sprintf()或者glib中的g_strdup_printf()来得到等同于物件名的字符串。在Glade中复制物件,物件的名字会自动按照末尾数字递增命名,并且物件的属性和信号也会一同被复制。
在连接信号时,可以把数组里所有类似的信号连接到同一个函数里。注意:回调函数的第一个参数总是GtkObject* widget,即信号对应物件的地址,可以用这个参数来判断是具体是哪个物件发出了信号。
下面给出最新的获取物件函数。
void cal_get_widgets(GtkBuilder* gb) { gint i; gchar s[6]; w_(gb,WINDOW,WMain); w_(gb,SPIN_BUTTON,SAns); w_(gb,BUTTON,BPoint); w_(gb,BUTTON,BPlus); w_(gb,BUTTON,BMinus); w_(gb,BUTTON,BMulti); w_(gb,BUTTON,BDiv); strcpy(s,"BNum_"); for(i=0;i<10;i++) { s[4]=i+'0'; BNum[i]=GTK_BUTTON(gtk_builder_get_object(gb,s)); } } |
这个程序将在后面的部分中完成。
在Glade中,还可以为每个按钮分配快捷键(加速键)。选定物件后,点击Glade右下角的“公共”选项卡中的“加速键”右侧的“…”按钮,可以在弹出窗口中指定该物件某个信号的快捷键。当窗口处于激活态时按下快捷键,对应的信号会被触发。
GTK+中,每个窗口有一个默认物件,某些情况下会被激活——比如在文本框中输入完毕按下Enter(当然这要将文本框的“激活默认”属性置为TRUE),确认按钮(当然它要被设为默认)会被按下。指定一个按钮为默认物件,需要将“公共”选项卡的“可成为默认”和“默认”都置为TRUE。