QT和GTK+.docx

上传人:b****5 文档编号:11639991 上传时间:2023-03-29 格式:DOCX 页数:34 大小:101.73KB
下载 相关 举报
QT和GTK+.docx_第1页
第1页 / 共34页
QT和GTK+.docx_第2页
第2页 / 共34页
QT和GTK+.docx_第3页
第3页 / 共34页
QT和GTK+.docx_第4页
第4页 / 共34页
QT和GTK+.docx_第5页
第5页 / 共34页
点击查看更多>>
下载资源
资源描述

QT和GTK+.docx

《QT和GTK+.docx》由会员分享,可在线阅读,更多相关《QT和GTK+.docx(34页珍藏版)》请在冰豆网上搜索。

QT和GTK+.docx

QT和GTK+

GTK+图形界面编程

本章将介绍Linux下的图形界面编程,重点介绍基于C语言的具有面向对象特征的GTK+图形界面编程。

主要介绍

GTK+图形界面应用程序的框架、基本原理、常用控件的使用。

本章重点:

GTK+程序的基本结构。

事件和消息处理。

常用控件的使用。

本章难点:

理解GTK+应用程序的基本原理。

熟悉常用控件的基本用法。

12.1Linux下的图形界面编程

12.1.1 Qt和GTK+

虽然Linux下的大多数开发是基于字符界面的,但在Linux环境下也可以开发出美观大方的图形界面。

经过多年的发展,目前已经存在多种用于在Linux下开发图形界面程序的开发包,其中较为常用的是Qt和GTK+。

Qt是一个跨平台的图形用户界面开发库,它不仅支持Linux操作系统,还支持所有类型的UNIX以及Windows操作系统。

Qt良好的封装机制使它模块化程度非常高,可重用性很强,Qt提供了丰富的API供开发人员使用。

使用Qt开发的图形用户界面程序具有良好的稳定性和健壮性。

桌面环境KDE(KDesktopEnVironment即K桌面环境)就是使用Qt作为其底层库开发出来的。

由于Qt使用C++面向对象编程语言作为其开发语言,而许多在Linux下从事开发的程序员更喜欢或更习惯于用C语言。

GTK+使用C语言作为开发语言。

它基于LGPL授权,因此GTK+是开放源代码而且完全免费的。

GTK+简单易用,执行效率高。

基于这些原因,GTK+拥有为数众多的拥护者。

Linux的桌面环境GNOME就是建立在GTK+基础上。

GTK+简介

图12-1GTK+在几种相关的

开发库中的位置。

图12-1中每层除了与其上下相邻的两层有联系外,似乎与其他层没有关系。

实际上,任何上层都可以调用位于它下面的各层提供的函数。

例如,GTK+不仅可以调用GDK函数,也可以调用glib和C库函数。

下面按层作简单的介绍,具体说明如表12-1所示。

表12-1 各层的具体含义

具体描述

C

有两类C库函数可供调用,一类是标准C的库函数,如printf、scanf;另一类是Linux的系统调用,如open、read、write、fork

glib

glib是GDK、GTK+、GNOME应用程序常用的库。

它包含内存分配、字符串操作、日期和时间、定时器等库函数,也包括链表、队列、树等数据结构相关的工具函数

X

它是控制图形显示的底层函数库,包括所有的窗口显示函数、响应鼠标和键盘操作的函数

GDK

GDK(GIMP绘图包)是为了简化程序员使用X函数库而开发的。

X库是其低层函数库,GDK对其进行了包装,从而使程序员的开发效率大为提高

GTK+

GTK+就是GIMP工具包,它把GDK提供的函数组织成对象,使用C语言模拟出面向对象的特征,这使得用它开发出来的图形界面程序更为简单和高效。

GTK+的一个重要组成部分是widget(控件,也称为小部件),按钮、文本编辑框、标签等都是widget

GNOME

GNOME库是对GTK+的扩展,GNOME桌面环境用来控制整个桌面。

GNOME使用GNOME对象和函数与桌面小部件交互,基本小部件由GTK+处理。

GNOME为了方便程序员还增加了一些专门的小部件

Application

Application即应用程序,它完成窗口的初始化,创建并显示窗口,进入消息循环,等待用户使用鼠标或键盘进行操作

简单地说,GTK+就是用C语言编写的用于开发图形界面程序的函数库。

GTK+来源于GIMP(GNUImageMinipulationProgram即GNU图像处理程序)。

GTK+在GDK(GIMPDrawingKit即GIMP绘图包)基础上创建,对它进行封装。

GTK+简单易用,它设计良好,灵活而富有扩展性。

它是自由软件,这意味着它不仅开放源代码,而且还可以免费使用。

由于它使用C语言作为其开发语言,而C语言是跨平台的,因此GTK+几乎可以在任何操作系统上使用。

在安装FederoCore或者RedHatLinux系列操作系统时,如果选择了安装应用程序开发包,那么操作系统安装完毕后,GTK+开发包就已经安装好了。

如果没有安装,请从网络上(http:

//www.gtk.org)免费下载一份GTK源代码并安装到系统上,也可以插入Linux安装光盘在系统提示下进行安装。

由于安装过程非常简单,这里就不再赘述了。

12.2一个简单的例子

先来看一个简单的GTK+图形界面程序的例子,了解这类程序的一般框架。

这个程序创建了一个窗口,并在窗口中放置了一个按钮,实现代码如例12-1所示。

例12-1 gtkwin.c

#include

/*定义回调函数hello,单击按钮时系统自动调用*/

voidhello(GtkWidget*widget,gpointer*data)

{

g_print("buttonclickedanddata=%s\n",(char*)data);

}

/*定义回调函数destroy,关闭窗口时系统自动调用*/

voiddestroy(GtkWidget*widget,gpointer*data)

{

gtk_main_quit();

}

intmain(intargc,char**argv)

{

/*定义指向控件的指针*/

GtkWidget*window;

GtkWidget*button;

/*初始化图形显示环境*/

gtk_init(&argc,&argv);

/*创建窗口,并设置当关闭窗口时,要执行的回调函数*/

window=gtk_window_new(GTK_WINDOW_TOPLEVEL);

g_signal_connect(GTK_OBJECT(window),"destroy",

GTK_SIGNAL_FUNC(destroy),NULL);

/*设置窗口的属性*/

gtk_container_border_width(GTK_CONTAINER(window),20);

/*创建按钮,并设置当单击按钮时,要执行的回调函数*/

button=gtk_button_new_with_label("HelloWorld");

g_signal_connect(GTK_OBJECT(button),"clicked",

GTK_SIGNAL_FUNC(hello),"Iamfrombutton");

/*将按钮加入到窗口中*/

gtk_container_add(GTK_CONTAINER(window),button);

/*显示按钮和窗口*/

gtk_widget_show(button);

gtk_widget_show(window);

/*进入消息处理循环*/

gtk_main();

return0;

}

编译并运行:

[root@mcitmp]#gcc-ogtkwingtkwin.c`pkg-config--libs--cflagsgtk+-2.0`

[root@mcitmp]#./gtkwin

注意:

编译命令中的字符串"pkg-config--libs-cflagsgtk+-2.0"两边是反引号(在键盘上位于数字字符1的左边)。

运行程序,显示如图12-2所示的界面:

图12-2  运行界面

程序说明。

(1)所有的GTK+程序中都必须包含头文件gtk/gtk.h,它声明了所有GTK+编程中要使用的常量、数据结构和函数。

(2)所有GTK+程序开始都要调用函数gtk_init(gint*argc,gchar***argv)。

该函数定位和打开图形显示,并对颜色、信号等进行初始化。

在命令行输入的参数由该函数传递给GTK+,该函数读取并获得与它有关的命令行参数。

(3)函数gtk_window_new(GTK_WINDOW_TOPLEVEL)用于创建顶级窗口,GTK+程序的主窗口被称为顶级窗口。

虽然一个程序可以创建多个顶级窗口,但通常只创建一个。

(4)图形界面下,用户的任何一个操作(如单击鼠标左键,按下键盘上的某个键)都称为发生了一个事件,GTK+都有相应的消息信号产生,如果程序中定义了处理该消息信号的函数,在事件发生后,消息信号处理函数会自动调用。

这样的消息信号处理函数也称为回调函数,因为这种函数虽然是在程序里定义,但程序中并没有显式调用而是由系统在事件发生后自动调用。

hello()和destroy()就是两个处理消息的回调函数。

destroy函数中调用了GTK+函数gtk_main_quit,它使程序退出gtk_main()并完成一些清理工作。

g_signal_connect函数用于在控件和消息处理函数间建立关联,该函数的第一个参数为产生消息的控件,第二个参数是消息名,第三个参数是消息发生后要调用的函数名,第四个是传递给消息处理函数的参数,可以为空值(即NULL)。

关于消息和回调函数的详细内容请参考下一节。

(5)gtk_container_border_width函数用于设置窗口边框的宽度,这是一个设置窗口属性的函数。

(6)gtk_button_new_with_label函数创建一个带文本标签的按钮,它完成内存分配,并把所分配到的内存的首地址赋给GtkWidget类型的指针。

(7)函数gtk_container_add通知GTK+将按钮加入到主窗口中,函数gtk_widget_show用于显示控件。

(8)gtk_main()使GTK+进入消息处理循环。

每个GTK+应用程序都有一个gtk_main函数,该函数使程序进入休眠状态。

当有事件发生,如果程序中有相应的处理函数,gtk_main()就调用相应的消息处理函数。

(9)为了方便编译,可以在源程序所在目录下编写一个Makefile文件:

CC=gcc

program=gtkwin

#PATH+=/usr/include/gtk2.0

LDLIBS=`pkg-config--libsgtk+-2.0`

CFLAGS=-Wall-g`pkg-config--cflagsgtk+-2.0`

$(program):

$(program).o

$(CC)$(LDLIBS)$(program).o-o$(program)

$(program).o:

$(program).c

$(CC)$(CFLAGS)-c$(program).c

clean:

-rm-f$(program)

-rm-f*.o

此时编译程序可以简化为:

[root@mcitmp]#make

要删除编译所产生的中间文件和可执行文件,可以执行命令:

[root@mcitmp]#makeclean

如果要编译其他GTK+程序,把Makefile文件中的gtkwin改为相应源程序的文件名即可。

Makefile的编写和make命令的使用请参考第5章。

例12-1程序中用到了一些GTK+预定义的函数和数据类型,表12-2和表12-3对其作一个简单的介绍。

表12-2 GTK+预定义的函数

前缀

含义

G

glib定义的数据结构

g

glib声明的数据类型

g_

glib定义的函数

gtk_

GTK+定义的函数

Gtk

GTK+库的对象或数据结构

GTK

GTK+定义的宏或者常量

表12-3 GTK+预定义的数据类型

GTK+的数据类型

C语言数据类型

gchar

char

gint

int

glong

long

gboolean

char

gfloat

float

gdouble

double

guchar

unsignedchar

guint

unsignedint

gulong

unsignedlong

gpointer

void*

gint8

在任何平台上都是8位的整型

gint16

在任何平台上都是16位的整型

gint32

在任何平台上都是32位的整型

guint8

在任何平台上都是8位的无符号整型

guint16

在任何平台上都是16位的无符号整型

guint32

在任何平台上都是32位的无符号整型

12.3 消息和回调函数

图形用户界面的程序是事件驱动的程序。

程序进入gtk_main函数后,等待事件的发生,一旦发生某个事件,相应的信号将产生。

如果程序中定义了相应的消息处理函数,系统会自动进行调用。

消息处理函数(或称回调函数)的原型是:

voidcallback_func(GtkWidget*widget,gpointerfunc_data);

参数widget指向要接收消息的控件,参数func_data指向消息产生时传递给该函数的数据。

函数g_signal_connect在控件和消息处理函数间建立关联,该函数的原型是:

gulongg_signal_connect(GtkObject*object,gchar*name

Gcallbackcallback_func,gpointerfunc_data);

各参数说明如下。

object:

指向产生消息的控件。

name:

消息或事件的名称。

callback_func:

事件发生后要执行的回调函数。

func_data:

传递给回调函数的数据,与callback_func()的第二个参数相同。

该函数的返回值用于区分一个控件的一个事件对应的多个处理函数。

一个控件上可以发生多个事件,比如单击一个按钮,双击一个按钮。

对于一个控件上的每个事件可以有0个、1个或多个处理函数。

该事件发生时,将按声明的顺序逐个调用这些函数。

对应于某个事件,如果控件没有定义处理函数,那么事件发生时将没有响应,系统忽略此事件。

还有一个与g_signal_connect()类似的函数:

gintg_signal_connect_swapped(GtkObject*object,gchar*name

GCallbackcallback_func,GtkObject*slot_object);

它的第四个参数指向一个GTK+控件的指针。

它与g_signal_connect()的区别在于相应的回调函数只有一个参数:

voidcallback_func(GtkObject*object);

通常object指向一个控件。

可以在上一节的例子中"gtk_container_add(GTK_CONTAINER(window),button);"之前加上一条语句:

g_signal_connect(GTK_OBJECT(button),"clicked",

GTK_SIGNAL_FUNC(gtk_widget_destroy),GTK_OBJECT(window));

则对应于button按钮的"clicked"事件有两个处理函数,一个是程序中定义的回调函数hello,还有一个是GTK+预定义的gtk_widget_destroy()。

gtk_widget_destroy()的作用与程序中的destroy()相同。

编译运行程序,如果单击按钮,系统先调用hello函数(因为它先与button控件建立关联)在命令行上打印出一行消息,然后调用gtk_widget_destroy()退出程序。

如果要删除控件和消息处理函数的关联,可以调用g_signal_disconnect(),该函数的原型是:

voidg_signal__handler_disconnect(GtkObject*object,gulongid);

参数说明如下。

object:

要删除消息处理函数的控件。

id:

g_signal_connect()或g_signal_connect_swapped()函数的返回值。

下面这个函数可以删除某控件的所有消息处理函数:

voidg_signal_handlers_destroy(GtkObject*object);

12.4 GTK+的面向对象机制

对于那些没有接触过面向对象语言的读者来说,本节的内容可能比较难以理解。

不过没有关系,这并不会影响后面内容的掌握。

介绍本节的内容只是为了简单地介绍一下GTK+中是如何模拟面向对象机制的。

面向对象编程语言(如C++、Java)把数据和对数据的操作封装在一起构成类,由类来产生对象,由对象来构建程序。

类中对数据的操作由函数来完成,这种函数被称为成员函数或方法。

面向对象语言通过继承、重载、多态等机制大大增强软件的可重用性和可维护性。

C语言虽然不是面向对象语言,但GTK+以及建立在其上的GNOME库却使C语言模拟出了一些典型的面向对象机制,如封装、继承和多态。

为了较好的理解GTK+程序,了解GTK+中的面向对象机制也是很有必要的。

对象的一个主要特性是将数据和对数据的操作封装在一起,受保护的私有数据只能通过成员函数才能访问和修改。

GTK+使用C语言的结构体来模拟对象,虽然有些缺陷但基本模拟出了对象的基本特征。

有了对象作为基础,通过在对象中加入新的数据和对这些数据进行操作的函数,就实现了继承。

被继承的类(类相当于一种自定义数据类型,由类来定义对象)称为父类或基类,由基础类派生出来的类称为子类或派生类。

子类继承了父类的数据和对这些数据进行操作的成员函数,并加入了新的数据和成员函数,实现了对原有父类的重用和扩展,从而实现了可重用性和可扩展性。

GTK+中有一个类,它是所有其他类的父类,这个类是GtkObject。

GTK+中最常用的按钮控件也是一个类,它继承自GtkObject。

它与GtkObject的继承关系是:

GtkObject->GtkWidget->GtkContainer->GtkBin->GtkButton

使用C语言如何模拟继承呢?

对象(类)是由结构体模拟的,每一个子类所在的结构体都包含了父类的结构体,子类结构体的第一个成员是其父类结构体,示例代码如下:

structGtkObject{

...

};

structGtkWidget{

GtkObjectobject;

...

};

structGtkContainer{

GtkWidgetwidget;

...

};

structGtkBin{

GtkContainercontainer;

...

};

structGtkButton{

GtkBinbin;

...

};

从上述代码可以看到,每个子类都包含了其父类的所有数据,并且父类的数据位于子类结构体的开始。

对于一个GtkButton类型的button控件变量(它其实是一个指向GtkButton结构体的指针),通过宏GTKBIN(button)就得到了其父类(GTK+预定义的宏GTKBIN其实是进行了强制类型转换,把一个GtkButton类型的指针强制转化为GtkBin类型的指针)。

例12-1中的GTK_OBJECT(button)就是进行了这样的转换。

为了便于理解,我们写一个测试程序,如例12-2所示。

例12-2 test.c

#include

#include

#defineFATHER(child)(structFather*)(child)

voidprint1(inti)

{

printf("thisisfatherandi=%d\n",i);

}

voidprint2(inti)

{

printf("thisischild andi=%d\n",i);

}

structFather{

int a;

void(*pointer1_to_function)(int);

};

structChild{

structFatherf;

intb;

void(*pointer2_to_function)(int);

};

voidfather_member_funtion(structFather*f,char*string)

{

printf("\n");

f->pointer1_to_function(f->a);

printf("%s\n\n",string);

}

intmain()

{

structChild*p_child;

p_child=(structChild*)malloc(sizeof(structChild));

p_child->f.a=10;

p_child->f.pointer1_to_function=print1;

p_child->b  =20;

p_child->pointer2_to_function  =print2;

p_child->pointer2_to_function(p_child->b);

structFather*p_father=FATHER(p_child);

p_father->pointer1_to_function(p_father->a);

father_member_funtion(p_father,"hello");

return0;

}

程序输出:

thisischildandi=20

thisisfatherandi=10

thisisfatherandi=10

hello

程序说明。

(1)结构体Father相当于GTK+中的父类,而结构体Child就相当于子类。

结构体Father有一个成员变量和一个成员函数(实际上是一个指向函数的指针,函数指针的内容请参考第4章4.3.4指针和函数一节)。

结构体Child在其头部包含了结构体Father,并增加了一个成员变量和一个成员函数(也是一个函数指针)。

结构体Father和Child模拟了类,Child模拟继承了Father。

(2)程序定义了一个指向结构体Child的指针,并对Child中的成员进行了初始化。

然后调用了结构体Child的成员函数pointer2_to_function。

通过宏FATHER(p_child)将指针p_child强制转换为指向Father结构体的指针。

事实上,p_child和p_father的值是一样的,它们都保存着结构体Child的首地址。

宏FATHER(p_child)类似于例12-1程序gtk_container_add(GTK_CONTAINER(window),button)中的GTK_CONTAINER(window)。

我们注意到,p_father调用了它自己的成员函数pointer1_to_function。

(3)father_member_funtion函数是类Father成员函数的另一种实现方法,这种方法避免了在结构体Father中保存函数指针。

GTK+定义了很多生成对象或对对象进行操作的函数。

例如,下面就创建了一个对象:

GtkWidget*button;

button=gtk_button_new_with_label("label");

所有创建对象的函数在其名称上都有"new"这个词。

函数gtk_button_new_with_label创建了一个显示文本的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1