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

 本文引用自 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 void
maman_bar_instance_init (GTypeInstance   *instance,
                         gpointer         g_class)
{
  MamanBar *self = (MamanBar *)instance;
}

static void
maman_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 void
maman_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 void
maman_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”信号同样会在每个属性改变后发射。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值