GObject参考手册(10)--GObject的对象属性

来源:互联网 发布:淘宝客模式加活动 编辑:程序博客网 时间:2024/06/06 00:01
 本文引用自http://imtx.cn,原文作者:TualatriX 

原文:http://library.gnome.org/devel/gobject/2.14/gobject-properties.html

GObject的其中一个漂亮特性就是它那为对象属性准备的通用get/set机制。当一个对象被实例化以后,对象的类初始化处理将用g_object_class_install_property来注册对象的属性(由gobject.c中实现)。

理解对象属性是如何工作的最好就是看下面的例子:

/************************************************//* Implementation                               *//************************************************/enum {  MAMAN_BAR_CONSTRUCT_NAME = 1,  MAMAN_BAR_PAPA_NUMBER,};static voidmaman_bar_instance_init (GTypeInstance   *instance,                         gpointer         g_class){  MamanBar *self = (MamanBar *)instance;}static voidmaman_bar_set_property (GObject      *object,                        guint         property_id,                        const GValue *value,                        GParamSpec   *pspec){  MamanBar *self = (MamanBar *) object;  switch (property_id) {  case MAMAN_BAR_CONSTRUCT_NAME: {    g_free (self->priv->name);    self->priv->name = g_value_dup_string (value);    g_print ("maman: %s/n",self->priv->name);  }    break;  case MAMAN_BAR_PAPA_NUMBER: {    self->priv->papa_number = g_value_get_uchar (value);    g_print ("papa: %u/n",self->priv->papa_number);  }    break;  default:    /* We don't have any other property... */    G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);    break;  }}static voidmaman_bar_get_property (GObject      *object,                        guint         property_id,                        GValue       *value,                        GParamSpec   *pspec){  MamanBar *self = (MamanBar *) object;  switch (property_id) {  case MAMAN_BAR_CONSTRUCT_NAME: {    g_value_set_string (value, self->priv->name);  }    break;  case MAMAN_BAR_PAPA_NUMBER: {    g_value_set_uchar (value, self->priv->papa_number);  }    break;  default:    /* We don't have any other property... */    G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);    break;  }}static voidmaman_bar_class_init (gpointer g_class,                      gpointer g_class_data){  GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);  MamanBarClass *klass = MAMAN_BAR_CLASS (g_class);  GParamSpec *pspec;  gobject_class->set_property = maman_bar_set_property;  gobject_class->get_property = maman_bar_get_property;  pspec = g_param_spec_string ("maman-name",                               "Maman construct prop",                               "Set maman's name",                               "no-name-set" /* default value */,                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);  g_object_class_install_property (gobject_class,                                   MAMAN_BAR_CONSTRUCT_NAME,                                   pspec);  pspec = g_param_spec_uchar ("papa-number",                              "Number of current Papa",                              "Set/Get papa's number",                              0  /* minimum value */,                              10 /* maximum value */,                              2  /* default value */,                              G_PARAM_READWRITE);  g_object_class_install_property (gobject_class,                                   MAMAN_BAR_PAPA_NUMBER,                                   pspec);}/************************************************//* Use                                          *//************************************************/GObject *bar;GValue val = {0,};bar = g_object_new (MAMAN_TYPE_SUBBAR, NULL);g_value_init (&val, G_TYPE_CHAR);g_value_set_char (&val, 11);g_object_set_property (G_OBJECT (bar), "papa-number", &val);

上面的例子看起来应该是简单的,但是很多事情发生了:

g_object_set_property先确保相应名称的属性已经在bar的class_init处理函数中被注册。如果是的话,它依次调用类继承关系中的object_set_property,从底至顶,基础类型用来找到注册了这个属性的类。接着它尝试转换用户提供的GValue到属性所关联的GValue。

如果用户提供了一个有符号的字符GValue,就像这里所示,如果对象的属性被注册为一个无符号的整型,g_value_transform将会试着转换输入的有符号的字符到一个无符号的整型。当然,转换是否成功取取决于可用的转换函数。实际上,如果需要的时候,总会有相关的转换函数可以用。

在转型以后,GValue将被g_param_value_validata来验证,以确保用户保存在GValue中的数据吻合由属性的GParamSpea所描述的字符特性。在这里,我们在class_init里提供的GParamSpec有一个验证函数来确保GValue包含了一个代表最小和最大边界的GParamSpec。在上面的例子中,客户端的GValue并没有尊重规范(它设置为了11,而最大值是10)。因为这样,所了g_object_set_property函数将返回一个错误。

如果用户的GValue已经被设置成了一个可用的值,g_object_set_property将处理一下呼叫至对象的set_property的类方法。在这里,因为我们在Foo的实现代码中并没有重载这个函数,代码路径将会跳到foo_set_property在收到g_object_class_install_property存储了GParamSpec的param_id后。

一时已经用对象的set_property类方法来设置好属性以后,代码路径将调用g_object_nofity_queue_thaw使返回到g_object_set_property 。这个函数确保“notify”信号”已经在对象实例完成改变属性后被发出,除非通知台已经被g_object_free_notify所冻洁。

g_object_thaw_nofity可以被用来重新启用通过“notify”信号的属性修改的通知中心。这是非常重要的,记住当属性被改变时通知中心是否被冻结,“notify”信号将会当在属性改变的一睡意由通知中心所发出:没有属性改变会因“notify”所信号。只有通过通知中心的冻结机制才能使信号发身被延误。

这听起来像是一个无聊的任务每次设置GValues当我想需要一个属性时。实际上我们仅仅很少这样做。g_object_set_property和g_object_get_property一般是用来语言绑定的。对应用程序来说,有一个更简单的方法,在下面描述。

同时修改多个属性

我想这很有趣,我们可以通过g_object_set和g_object_set_valist函数来同时设置多个属性值。客户端代码可以被重写为:

MamanBar *foo;foo = /* */;g_object_set (G_OBJECT (foo),              "papa-number", 2,              "maman-name", "test",              NULL);

这个节省了我们管理用g_object_set_property来处理GValue的时间。在被修改时这个代码同样会触发每个属性。

当然,_get的版本同样是存在的:g_object_get和g_object-get_valist可以用来一次性得到很多属性。

这些高级的方法有一个缺点──它们不提供一个返回值。在使用它们时,你需要注意这些参数类型和范围 。(暂时不会了)

These high level functions have one drawback - they don’t provide a return result. One should pay attention to the argument types and ranges when using them. A know source of errors is to e.g. pass a gfloat instead of a gdouble and thus shifting all subsequent parameters by four bytes. Also forgetting the terminating NULL will lead to unexpected behaviour.

如果你认真看这章的话,现在你应该已经知道了g_object_new,g_object_newv和g_object_new_valist是如何工作的:它们解析用户提供的变量数目和参数并当对象成功的创建以后,用这些参数调用g_object_set。当然,“notify”信号同样会在每个属性改变后发射。

原创粉丝点击