GObject的物件屬性

李先靜發表於2020-04-06

GObject的物件屬性

 

glib物件系統中,一般的類都是從Gobject類繼承過來的。儘管glib是用C語言開發的,它卻幾乎支援所有的物件導向的特性。這裡不談glib的物件導向機制,只是說說關於GObject物件屬性的一些問題。

 

OOP中,物件的屬性一般用成員變數來表示。程式設計高手常常告誡我們,把物件的屬性隱藏起來,用成員函式去訪問,可以減少與使用者之間的耦合,同時可以提高程式的健壯性。

 

實際上,僅僅是把物件的屬性封裝起來,有時是不夠的。比如,你無法通過基類的指標去訪問子類的屬性。要做到這一點,需要把這些setter/getter函式實現成虛擬函式,在子類中去過載它們。不過,這樣做會讓基類的介面顯示很龐雜,而且實際上你也無法預知子類中的會有哪些屬性。

 

另外一個更重要問題是,有時候外部物件可能會關心某個物件的屬性改變。比如,像對話方塊可能關心其上控制元件的屬性的變化,控制元件的屬性變化時,對話方塊需要做一些調整。如果能實現一種機制支援這種功能將有很大用處。

 

Gobject定義了兩個函式(get_property/set_propery),用於存取物件的屬性,在子類中過載這兩個函式就行了,不用實現一大堆setter/getter函式,同時它提供了一種物件屬性監視機制,在物件屬性改變時通知相關關注者。

 

下面這個例子演示了以上所有功能:

 

/*

 * fooobject.h

 * Copyright (C) 2006 gclassfactory

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2 of the License, or (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details.

 *

 * You should have received a copy of the GNU Lesser General Public

 * License along with this library; if not, write to the

 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,

 * Boston, MA 02111-1307, USA.

 */

#ifndef FOO_OBJECT_H

#define FOO_OBJECT_H

 

#include <glib.h>

#include <glib-object.h>

 

G_BEGIN_DECLS

 

#define FOO_TYPE_OBJECT                 (foo_object_get_type ())

#define FOO_OBJECT(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), FOO_TYPE_OBJECT, FooObject))

#define FOO_OBJECT_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), FOO_TYPE_OBJECT, FooObjectClass))

#define FOO_IS_OBJECT(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FOO_TYPE_OBJECT))

#define FOO_IS_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), FOO_TYPE_OBJECT))

#define FOO_OBJECT_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), FOO_TYPE_OBJECT, FooObjectClass))

 

typedef struct _FooObject        FooObject;

typedef struct _FooObjectClass   FooObjectClass;

 

struct _FooObject

{

         GObject gobject;

 

         gint width;

         gint height;

         gboolean visible;

 

};

 

struct _FooObjectClass

{

         GObjectClass parent_class;

 

 

 

};

 

GType foo_object_get_type(void) G_GNUC_CONST;

FooObject* foo_object_new(void);

 

G_END_DECLS

 

#endif /*FOO_OBJECT_H*/

/*

 * fooobject.c

 * Copyright (C) 2006 gclassfactory

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

 * License as published by the Free Software Foundation; either

 * version 2 of the License, or (at your option) any later version.

 *

 * This library is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

 * Lesser General Public License for more details.

 *

 * You should have received a copy of the GNU Lesser General Public

 * License along with this library; if not, write to the

 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,

 * Boston, MA 02111-1307, USA.

 */

#include "fooobject.h"

 

enum {

         PROP_0,

         PROP_VISIBLE,

         PROP_WIDTH,

         PROP_HEIGHT,

         PROP_LAST

};

 

static GObjectClass* parent_class = NULL;

 

static void foo_object_class_init(FooObjectClass   *class);

static void foo_object_init      (FooObject        *object);

static void foo_object_set_property     (GObject        *object,

                                         guint           property_id,

                                         const GValue   *value,

                                         GParamSpec     *pspec);

static void foo_object_get_property     (GObject        *object,

                                         guint           property_id,

                                         GValue         *value,

                                         GParamSpec     *pspec);

GType

foo_object_get_type (void)

{

         static GType object_type = 0;

 

         if (!object_type)

         {

                   static const GTypeInfo object_info =

                   {

                            sizeof (FooObjectClass),

                            NULL,       /* base_init */

                            NULL,       /* base_finalize */

                            (GClassInitFunc) foo_object_class_init,

                            NULL,       /* class_finalize */

                            NULL,       /* class_data */

                            sizeof (FooObject),

                            0,      /* n_preallocs */

                            (GInstanceInitFunc) foo_object_init,

                   };

                  object_type = g_type_register_static (G_TYPE_OBJECT, "FooObject", &object_info, 0);

         };

 

         return object_type;

}

 

FooObject* foo_object_new(void)

{

         return (FooObject*)g_object_new(FOO_TYPE_OBJECT, 0);

}

 

static void foo_object_class_init(FooObjectClass   *class)

{

         GObjectClass* gobject_class = G_OBJECT_CLASS(class);

 

         gobject_class->set_property = foo_object_set_property;

         gobject_class->get_property = foo_object_get_property;

 

         g_object_class_install_property (gobject_class,

                   PROP_VISIBLE,

                   g_param_spec_boolean ("visible",

                             ("Visible"),

                             ("Whether the widget is visible"),

                             FALSE,

                             G_PARAM_READWRITE));

 

  g_object_class_install_property (gobject_class,

                   PROP_HEIGHT,

                   g_param_spec_int ("height",

                             ("Height"),

                             ("Override for height request of the widget, or -1 if natural request should be used"),

                             -1,

                             G_MAXINT,

                             -1,

                             G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,

                   PROP_WIDTH,

                   g_param_spec_int ("width",

                             ("Width request"),

                             ("Override for width request of the widget, or -1 if natural request should be used"),

                             -1,

                             G_MAXINT,

                             -1,

                             G_PARAM_READWRITE));

 

         return;

}

 

static void foo_object_init      (FooObject        *object)

{

         return;

}

 

static void foo_object_set_property     (GObject        *object,

                                         guint           property_id,

                                         const GValue   *value,

                                         GParamSpec     *pspec)

{

         FooObject* foo_object = FOO_OBJECT(object);

 

         switch(property_id)

         {

                   case PROP_VISIBLE:

                   {

                            foo_object->visible = g_value_get_boolean(value);

                            break;

                   }

                   case PROP_WIDTH:

                   {

                            foo_object->width = g_value_get_int(value);

                            break;

                   }

                   case PROP_HEIGHT:

                   {

                            foo_object->height = g_value_get_int(value);

                            break;

                   }

                   default:

                   {

                            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);

                            break;

                   }

         }

 

         return;

}

static void foo_object_get_property     (GObject        *object,

                                         guint           property_id,

                                         GValue         *value,

                                         GParamSpec     *pspec)

{

         FooObject* foo_object = FOO_OBJECT(object);

 

         switch(property_id)

         {

                   case PROP_VISIBLE:

                   {

                            g_value_set_boolean(value, foo_object->visible);

                            break;

                   }

                   case PROP_WIDTH:

                   {

                            g_value_set_int(value, foo_object->width);

                            break;

                   }

                   case PROP_HEIGHT:

                   {

                            g_value_set_int(value, foo_object->height);

                            break;

                   }

                   default:

                   {

                            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);

                            break;

                   }

         }

 

         return;

}

 

static void property_change (gpointer     data1,

         gpointer     arg_1,

         gpointer     data2)

{

         GParamSpec     *pspec = (GParamSpec*) arg_1;

 

         g_printf("property %s change/n", g_param_spec_get_name(pspec));

         return;

}

        

int main(int argc, char* argv[])

{

         GValue value = {0};

 

         FooObject* object = NULL;

        

         g_type_init();

        

         object = foo_object_new();

 

         g_signal_connect(G_OBJECT(object), "notify", G_CALLBACK(property_change), object);

         g_value_init(&value, G_TYPE_BOOLEAN);

         g_value_set_boolean(&value, TRUE);

         g_object_set_property(G_OBJECT(object), "visible", &value);

 

         g_value_unset(&value);

        

         g_value_init(&value, G_TYPE_INT);

        

         g_value_set_int(&value, 400);

         g_object_set_property(G_OBJECT(object), "width", &value);

        

         g_value_set_int(&value, 300);

         g_object_set_property(G_OBJECT(object), "height", &value);

        

         g_object_unref(object);

        

         return 0;

}

相關文章