用Gtk 开发Linux上的GUI应用软件

一般一个容器构件只能容纳一个构件,如果要在一个容器构件中安排多个子构件,可先将多个子构件放入一个组合框或组合表构件内,再将这个组合框或组合表构件放入该容器构件。

一、如何建立Gtk 应用

1.基本概念

在Linux上开发GUI应用软件,我们通常利用Gtk 库。为了深入了解Gtk 的应用,我们首先要明确几个概念。

(1) 构件(widget)的概念

在Gtk 库里的窗口、选单和按钮等应用实体,我们称之为构件(widget)。构件具有面向对象的特征,其具体结构由Gtk 库定义,它对运用构件的程序员来说是透明的,除非你想创建自己的构件。在对构件进行安排时,我们只需要关心构件的处理函数,这样做的目的就是要对应用程序 员屏蔽构件的细节,使程序员将更多的精力集中在应用功能上。

(2) 容器(container)的概念

构件主要分为两大类,即容器类(container)和杂类(miscellaneous)。大多数构件属容器类,它们可以像容器一样容纳其它的构 件。在安排构件时常常要遵循一个规则:除了组合框(box)和组合表(table)这两种构件外,其它的容器类构件都只能容纳一个构件。杂类构件比容器类 构件简单,但它不能容纳其它构件。

(3) 消息及回呼函数的概念

程序必须能对用户的操作作出反 应,在基于GUI的程序设计中,“消息”或“信号”是必要的。用户点击选单、各种按钮、输入用户数据、查询运行结果和拖放,都会产生消息或信号。信号可能 需要由软件来加以处理,这时程序员就需要编写消息回呼函数。消息或信号的概念类似于Windows中的事件。在Gtk 中经常产生各种信号,用户产生的大多数信号被忽略,只有程序关心的信号,程序中才有相应的处理函数被调用。程序员要登记信号与处理函数之间的关系,告诉 Gtk 哪些信号或事件是程序所关心的。

2. 构件(widget)的运用

在调用Gtk 的构件时,一般进行如下操作步骤:

(1) 包含所调用构件的头文件

头文件通常存放在/usr/include/gtk/目录下,该文件里有对构件的定义及对构件的操作函数,在我们使用构件时,可以经常在这个目录下 查阅构件函数的调用格式或参数。我们不必让所有构件包含头文件,因为构件的头文件已包含在该目录下一个名为gtk.h的文件里,包含这个文件就包含了所有 构件的头文件。一般系统将编译的包含目录指定为/usr/include,所以我们只需写明 include 即可。

(2) 声明构件

声明构件的过程是为了符合C语言中先声明后使用的原则。一般在程序开始要声明构件结构的指针,这就为构件分配了地址。

(3) 构件指针的初始化

调用构件的创建函数,对构件的属性进行调整(大小、位置和状态等),接着显示构件,这一点不能忽略,如果只创建了构件却忘了显示(gtk_widget_show),在应用时,用户就不能看到构件,也就无法对构件进行操作了。

(4) 安排构件的位置与层次关系

构件之间往往是容纳与被容纳的关系,也就是说容器内还有容器,层层嵌套。要记住一般一个容器构件只能容纳一个构件,如果要在一个容器构件中安排多个 子构件,可先将多个子构件放入一个组合框或组合表构件内,再将这个组合框或组合表构件放入该容器构件。注意父容器构件要先于子容器构件创建,父容器构件的 显示要在子容器构件的显示之后。

(5) 编写事件处理函数

构件的头文件中定义了构件能响应的事件(消息),但并非所有的消息在应用中都是程序所关心的,对于程序应当响应的事件,程序员要写出事件处理函数。


二、应用举例


为了对Gtk 库的应用有一个具体的认识,让我们来看一个简单的应用实例。

1. 初始化Gtk

写Gtk 程序需要调用gtk_init函数对Gtk 库进行初始化。我们首先将应用程序的变量argc和argv传递给gtk_init函数,并检查主要用于调试的Gtk 选项。如果在变量列表中出现任何这样的Gtk 参数,就将它移去。在运行gtk_init函数后,它们不应该出现在应用程序中。初始化Gtk 的代码如下:

gtk_init(&&argc,&&argv);

2. 建立构件

首先要建立的构件是窗口,它是应用程序的顶层构件,其它构件一般安排在顶层窗口中。窗口是GUI程序的基本框架,在窗口里我们可以为用户安排各种方 便的应用。一个应用可以有若干个窗口,这些窗口之间既相互独立,又有层次的关系。窗口有相对固定的风格,前景色、背景色、字体和字号等,我们应当保持定制 的风格,确保不使应用软件杂乱。

按照上面提出的构件运用步骤,我们创建一个程序主窗口:

/*声明构件指针*/

GtkWidget *window;

/*创建窗口,初始化窗口指针,建立一个顶层窗口*/

window=gtk_window_new(GTK_WINDOW_TOPLEVEL);

/*显示构件*/

gtk_widget_show(window);

/*登记消息与消息处理函数的关系*/

gtk_signal_connect(GTK_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(close_window),NULL);

3. 构件类型的转换

由于建立的构件是通用构件,需要将它转换为具体的类型以适合调用更为专用的函数。比如建立按钮构件函数会返回GtkWidget 指针,但是专用的按钮子程序要求返回GtkButton指针,所以在调用专用的按钮函数以前,需要使用GTK_BUTTON宏将通用的GtkWidget 指针转换为GtkButton指针。通常,构件是由其它构件派生的,窗口构件(GtkWindow)是由容器构件GtkContainer派生的,而容器 构件是由通用构件派生的。在Gtk 中可以将构件指针转换为其父类、祖先类构件的任意类型,然后再调用父类或祖先类构件的函数。

4. Gtk 的事件循环

对Gtk 进行初始化并将窗口等构件安排在屏幕上之后,应用软件需要使用Gtk 开始执行事件的循环函数gtk_main(),没有这个函数,应用程序运行时就会一闪即逝。但是在调用gtk_main_quit()函数之前对 gtk_main()函数的调用并不返回,也就是说只有gtk_main_quit()函数才能停止Gtk 的执行,从而最终退出应用程序。我们把gtk_main_quit()函数放在消息处理函数close_window()之中,这样,当用户点击了窗口的 关闭按钮,Gtk 收到“delelte_event”消息,然后调用close_window(),执行gtk_main_quit()函数,整个程序即可退出。

5. 实例源代码

现在创建一个显示“hello”字样的简单窗口程序。整个程序实现代码如下:

//hello.c

include

/*关闭主窗口中的消息处理函数*/

close_window(GtkWidget *window,gpointer data)

{

/*中止gtk事件循环*/

gtk_main_quit();

}

/*主函数*/

main(int argc,char *argv)

{/*声明窗口和标签两个构件*/

GtkWidget *window;

GtkWidget *label;

/*初始化Gtk 库*/

gtk_init(&&argc,&&argv);

/*初始化window构件*/

window=gtk_window_new(GTK_WINDOW_TOPLEVEL);

/*初始化label构件*/

label=gtk_label_new("hello!");

/*将标签放入窗口内,函数内用GTK_CONTAINER宏将窗口构*/

/*件的指针类型转换为其父类容器构件的指针类型*/

gtk_container_add(GTK_CONTAINER(window),label);

/*显示label构件*/

gtk_widget_show(label);

/*显示window构件*/

gtk_widget_show(window);

/*当窗口获得'delete_event'消息时调用close_windw函数*/

gtk_signal_connect(GTK_OBJECT(window),"delete_event",

GTK_SIGNAL_FUNC(close_window),NULL);

/*gtk事件循环*/

gtk_main();

}

6. 编译源代码及运行程序

最后谈一下Gtk 在程序编译和运行时有哪些特别之处。在Linux系统下的C编译器,如gcc,要求编译时在编译命令后加上各种参数,如果参数太复杂,最好把命令写入makefile文件。

前面我们讲过在应用程序文件中用到Gtk 函数或定义的每一部分必须包含gtk/gtk.h文件,它是Gtk 的主要包含文件。此外,还必须连接若干库。Gtk 的开发人员为我们提供了方便。使用gtk-config程序可以简化这些工作。编译hello.c源文件成为可执行文件hello的命令如下:

gcc hello.c -o hello `gtk-config -cflags``gtk-config -libs`

注意,程序中一定是反引号(在键盘上位于字符1的左边)。`gtk-config`实际运行了gtk-config程序;参数-cflags输出编 译标志,并将它们插入命令行;参数-libs输出连接标志并插入命令行。在Gtk 1.2以上版本中包含gtk-config程序。在Linux的命令行提示符后敲入`gtk-config -cflags`和`gtk-config -libs`表示给gcc 传递参数的正确方法。

用shell命令“c

三、读懂Glade生成的代码


在glade的源文件目录src下有7个代码文件,它们分别是:

1> callbacks.c  Glade生成的大部分空的回调函数所在的文件,你自己往里面添加代码
2> callbacks.h  (头文件)Glade生成的回调函数的定义文件
4> interface.c  Glade生成的界面源代码文件
5> interface.h  (头文件)Glade生成的界面的定义文件
6> main.c    主函数
7> support.c  支持文件
8> support.h  (头文件)支持文件

在galde生成的devcpp目录里有2个文件
1> config.h    Glade 生成的配置文件
2>gtk1.dev    Glade 生成的devcpp工程文件(就是你保存时启的那个名子)。

不要被这么多的文件吓着,需要你自己编写代码的文件只有三个(其它文件不要动),它们是:
main.c    (一般只需做少量的修改)
callbacks.h (一般只需做少量的修改,甚至不作修改)
callbacks.c (函数的具体实现部分,你需要在这里编写一定量的代码)

其中callbacks.c是你编写代码的主文件。

下面我们来简单了解一下glade生成的界面文件interface.c

GtkWidget*
create_window1 (void)
{
GtkWidget *window1;  /*定义一个窗口构件*/
GtkWidget *fixed1;  /*定义一个固定容器构件,用于放置其它构件*/
GtkWidget *label1;  /*定义一个标签构件*/

window1 = gtk_window_new (GTK_WINDOW_TOPLEVEL);  /*新建一个窗口*/
gtk_window_set_title (GTK_WINDOW (window1), _("window1")); /*设置窗口的标题*/
gtk_window_set_default_size (GTK_WINDOW (window1), 400, 300);  /*设置窗口的默认大小为400,300*/

fixed1 = gtk_fixed_new (); /*新建一个固定容器*/
gtk_widget_show (fixed1);  /*显示固定容器*/
gtk_container_add (GTK_CONTAINER (window1), fixed1);  /*添加固定容器到窗口*/

label1 = gtk_label_new (_("\346\254\242\350\277\216\350\265\260\350\277\233GTK\347\232\204\344\270\226\347\225\214")); /*新建一个标签*/
gtk_widget_show (label1);  /*显示标签*/
gtk_fixed_put (GTK_FIXED (fixed1), label1, 120, 72); /*把标签添加到固定容器中*/
gtk_widget_set_size_request (label1, 136, 40); /*设置标签的大小*/

/* Store pointers to all widgets, for use by lookup_widget(). */
GLADE_HOOKUP_OBJECT_NO_REF (window1, window1, "window1");
GLADE_HOOKUP_OBJECT (window1, fixed1, "fixed1");
GLADE_HOOKUP_OBJECT (window1, label1, "label1");

return window1;
}
(点评:版本不一样,里面的代码可能有一些不同)

(这部分内容,能理解多少,理解多少,看不懂也不要紧。)
文件:main.c

只作部分解释,以后你水平高了,慢慢看吧!
以下代码节选自main.c

int    main (int argc, char *argv[])   
{
GtkWidget *window1;  /*定义window1构件*/

gchar *pixmap_dir;
#ifdef G_OS_WIN32
package_prefix = g_win32_get_package_installation_directory (NULL, NULL);
package_data_dir = g_build_filename (package_prefix, "share", NULL);
package_locale_dir = g_build_filename (package_prefix, "share", "locale", NULL);
#endif

#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, package_locale_dir);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
#endif

gtk_set_locale ();      /*通过调用这个函数才可显示中文*/
gtk_init (&argc, &argv);  /*GTK初始化*/

pixmap_dir = g_build_filename (package_data_dir, PACKAGE, "pixmaps", NULL);
add_pixmap_directory (pixmap_dir);
g_free (pixmap_dir);

/*
* The following code was added by Glade to create one of each component
* (except popup menus), just so that you see something after building
* the project. Delete any components that you don't want shown initially.
*/
window1 = create_window1 ();    /*创建window1构件*/
gtk_widget_show (window1);  /**显示window1构件/
g_signal_connect ((gpointer) window1, "destroy", G_CALLBACK(gtk_main_quit),
NULL);
/*为window1构件的“destroy”事件,关联函数,
也就是当单击window1的关闭按钮时,关闭window1,同时退出gtk*/
gtk_main ();  /*gtk主程序开始执行*/

#ifdef G_OS_WIN32
g_free (package_prefix);
g_free (package_data_dir);
g_free (package_locale_dir);
#endif

return 0;
}

标签构件

标签构件用到的有关函数

创建新标签:
gtk_label_new(“label1”);
gtk_label_new_with_mnemonic(“label1”);
在字符串中放置换行符,可以创建多行标签。

改变标签的文本:
gtk_label_set_text(GTK_LABEL(label1),”label2”);

取得标签的当前文本:
gtk_label_get_text(GTK_LABEL(label1));

设置标签文本的对齐方式:
gtk_label_set_justify(GTK_LABEL(label1),GTK_JUSTIFY_LEFT);

GTK_JUSTIFY_LEFT    /*左对齐*/
GTK_JUSTIFY_RIGHT    /*右对齐*/
GTK_JUSTIFY_CENTER    /*居中对齐*/
GTK_JUSTIFY_FILL    /*充满*/

标签内的文本自动换行:
gtk_label_set_line_wrap(GTK_LABEL(label1),TRUE);

注:标签不能引发信号,如需引发信号,需将标签放置在事件盒中。

文本输入构件的常用函数:

创建文本输入构件:
GtkWidget  *entry1;
entry1 = gtk_entry_new();

改变文本输入构件当前的文本内容:
gtk_entry_set_text(GTK_ENTRY(entry1),"entry2");

取得文本输入构件当前的文本内容:
const gchar  *text1;
text1 = gtk_entry_get_text(GTK_ENTRY(entry1));

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值