GObject对象系统 (3)


信号的定义和应用

     在GObject系统中,信号是一种定制对象行为的手段,同时也是一种多种用途的通知机制。初学者可能是在GTK+中首先接触到信号这一概念的,事实上在普通的字符界面编程中也可以正常应用,这可能是很多初学者未曾想到的。

一个对象可以没有信号,也可以有多个信号。当有一或多个信号时,信号的名称定义是必不可少的,此时C语言的枚举类型的功能就凸显出来了,用LAST_SIGNAL来表示最后一个信号(不用实现的信号)是一种非常良好的编程风格。这里为Boy对象定义了一个信号BOY_BORN,在对象创建时发出,表示Boy对象诞生。

     同时还需要定义静态的整型指针数组来保存信号的标识,以便于下一步处理信号时使用。

对象的类结构是所有对象的实例所共有的,我们将信号也定义在对象的类结构中,如此信号同样也是所有对象的实例所共有的,任意一个对象的实例都可以处理信号。因此我们有必要在在类初始化函数中创建信号(这也可能是GObject设计者的初衷)。函数g_signal_new用来创建一个新的信号,它的详细使用方法可以在GObject的API文档中找到。信号创建成功后,返回一个信号的标识ID,如此就可以用发射信号函数g_signal_emit向指定义对象的实例发射信号,从而执行相应的功能。

    本例中每创建一个新的Boy对象,就会发射一次BOY_BORN信号,也就会执行一次我们定义的boy_born函数,也就输出一行"Message : A boy was born ."信息。

 

 

 

对象的属性和方法

       对象实例所有的属性和方法一般都定义在对象的实例结构中,属性定义为变量或变量指针,而方法则定义为函数指针,如此,我们一定要定义函数为static类型,当为函数指针赋值时,才能有效。

 

 

 

对象的继承

以下为继承自Boy对象的Man对象的实现,Man对象在Boy对象的基础上又增加了一个属性job和一个方法bye。

 

 

 

#ifndef __MAN_H__
#define __MAN_H__
#include "boy.h"
#define MAN_TYPE  ( man_get_type() )
#define MAN(obj) ( G_TYPE_CHECK_INSTANCE_CAST ( (obj), MAN_TYPE, Man ) )
typedef struct _Man Man;
typedef struct _ManClass ManClass;
struct _Man {
	Boy parent;
	char *job;
	void (*bye)(void);
};
struct _ManClass {
	BoyClass parent_class;
};
GType man_get_type ( void );
Man*  man_new ( void );
gchar* man_get_job ( Man *man );
void  man_set_job ( Man *man, gchar *job );
Man*  man_new_with_name_age_and_job ( gchar *name, gint age, gchar *job );
void man_info ( Man *man );
#endif //__MAN_H__
 
/* man.c */
#include "man.h"
static void man_bye ( void );
static void man_init ( Man *man );
static void man_class_init ( Man *man );
GType man_get_type ( void )
{
	static GType man_type = 0;
	if ( !man_type )
	{
		static const GTypeInfo man_info = {
			sizeof( ManClass ),
			NULL, NULL,
			(GClassInitFunc)man_class_init,
			NULL, NULL,
			sizeof( Man ),
			0,
			(GInstanceInitFunc) man_init
		};
		man_type = g_type_register_static ( BOY_TYPE, "Man", &man_info, 0);
	}
	return man_type;
}
static void man_init ( Man *man )
{
	man->job = "none";
	man->bye = man_bye;
}
static void man_class_init ( Man *man )
{
}
Man*  man_new ( void )
{
	Man *man;
	man = g_object_new ( MAN_TYPE, 0 );
	return man;
}
gchar* man_get_gob ( Man *man )
{
	return man->job;
}
void  man_set_job ( Man *man, gchar *job )
{
	man->job = job;
}
Man*  man_new_with_name_age_and_job ( gchar *name, gint age, gchar *job )
{
	Man *man;
	man = man_new ( );
	boy_set_name ( BOY (man), name );
	boy_set_age ( BOY(man), age );
	man_set_job ( man, job );
	return man;
}
static void man_bye(void)
{
	g_print ( "Goodbye everyone !/n" );
}
void man_info(Man *man)
{
	g_print ( "the man name is %s/n", BOY(man)->name );
	g_print ( "the man age is %d/n", BOY(man)->age );
	g_print ( "the man job is %s/n", man->job );
}
 
关键在于定义对象时将父对象实例定义为Boy,父类设定为BoyClass,在注册此对象时将其父对象类型设为BOY_TYPE,
在设定对象属性时如用到父对象的属性要强制转换下,如取得对象的name属性,就必须用BOY(obj)->name,因为Man本身没有name属性,
而其父对象Boy有,所以用BOY宏将其强制为Boy类型的对象。

测试我们定义的对象

 

#include <glib.h>
#include "boy.h"
#include "man.h"
int main ( int argc, char *argv[] )
{
	Boy *tom, *peter;
	Man *green, *brown;
	
	g_type_init();//注意,初始化类型系统,必需
	tom = boy_new_with_name("Tom");
	tom->cry();
	boy_info(tom);
	peter = boy_new_with_name_and_age("Peter", 10);
	peter->cry();
	boy_info(peter);
	green = man_new();
	boy_set_name(BOY(green), "Green");
        //设定Man对象的name属性用到其父对象Boy的方法
	boy_set_age(BOY(green), 28);
	man_set_job(green, "Doctor");
	green->bye();
	man_info(green);
	brown = man_new_with_name_age_and_job( "Brown", 30, "Teacher" );
	brown->bye();
	man_info(brown);
}
 
Makefile文件如下:
CC = gcc
all:
	$(CC) -c boy.c `pkg-config --cflags glib-2.0 gobject-2.0`
	$(CC) -c man.c `pkg-config --cflags glib-2.0 gobject-2.0`
	$(CC) -c main.c `pkg-config --cflags glib-2.0 gobject-2.0`
	$(CC) -o simple boy.o man.o main.o `pkg-config --libs glib-2.0 gobject-2.0`
执行make命令编译,编译结束后,执行./simple运行此测试程序,输出结果如下:
Message : A boy was born .
The Boy is crying ......
The Boy name is Tom
The Boy age is 0
Message : A boy was born .
The Boy is crying ......
The Boy name is Peter
The Boy age is 10
Goodbye everyone !
the man name is Green
the man age is 28
the man job is Doctor
Goodbye everyone !
the man name is Brown
the man age is 30
the man job is Teacher

Makefile中用到`pkg-config -cflags -libs gobject-2.0`,在GLIB中将线程(gthread),插件(gmoudle)和对象系统(gobject)

这三个子系统区别对待,编译时要注意加入相应的参数。

 

本文只是概要的介绍了如何定义和实现GObject对象,GObject系统中还有很多相关内容,

如:枚举和标识类型(Enumeration and flags types);Gboxed,是Gtype系统中注册一种封装为不透明的C语言结构类型的机制;

许多对象用到的参数对象都是C结构类型,使用者不必了解其结构的内部定义,即不透明,GBoxed即是实现这一功能的机制;

标准的参数和变量类型的定义(Standard Parameter and Value Types)等,它们都以C语言来开发,是深入了解和掌握GObject的关键。

透过以上代码实现,我们还可以看出,以GLIB为基础的GTK+/GNOME开发环境所具有的独特的编程风格和独到的开发思想。

这一点在长期的编程实践中会体验得更深刻。

有了GObject系统这一基础,GTK+通过它将X窗口环境中的控件(Widget)巧妙的封装起来,这使开发LINUX平台上的GUI应用程序

更方便,更快捷。

 

以上代码在Redhat 8.0 Linux平台,GLIB2.2.1环境下编译通过。

 

感谢

本文的写作参考了中国LINUX论坛的网友hoyt的文章,可以在gtkvb.cffd.org.cn找到,在此表示感谢。



参考资料



关于作者

 

宋国伟,乡村小学英语教师,他是《GTK+2.0编程范例》(清华大学出版社出版)一书的作者,业余时间致力于用GTK+开发LINUX GUI应用程序,可以通过电子邮件地址 gwsong52@sohu.com与他联系。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值