分类:
2009-10-16 16:34:00
/* myipaddress.h */
#include
#include
#include
G_BEGIN_DECLS
/* 这5个宏是定义 GObject 子类的“规定动作” */
#define MY_IP_ADDRESS_TYPE (my_ip_address_get_type ())
#define MY_IP_ADDRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MY_IP_ADDRESS_TYPE, MyIPAddress))
#define MY_IP_ADDRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MY_IP_ADDRESS_TYPE, MyIPAddressClass))
#define IS_MY_IP_ADDRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MY_IP_ADDRESS_TYPE))
#define IS_MY_IP_ADDRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MY_IP_ADDRESS_TYPE))
typedef struct _MyIPAddress MyIPAddress;
typedef struct _MyIPAddressClass MyIPAddressClass;
/* instance 结构 */
struct _MyIPAddress
{
/* 父类的 instance 结构必须作为第一个域 */
GtkEntry entry;
};
/* class 结构 */
struct _MyIPAddressClass
{
GtkEntryClass parent_class;
/* “默认”信号处理函数 */
void (* ip_changed) (MyIPAddress *ipaddress);
};
/* 必须定义的一个函数,被上面的 MY_IP_ADDRESS_TYPE 宏使用,返回该类的 GType */
GType my_ip_address_get_type (void) G_GNUC_CONST;
/* 也可以不定义,只是一个 convenience,完全可以用 g_object_new (MY_IP_ADDRESS_TYPE) 来代替 */
GtkWidget* my_ip_address_new (void);
/* 对外提供两个接口函数 */
gchar* my_ip_address_get_address (MyIPAddress *ipaddress);
void my_ip_address_set_address (MyIPAddress *ipaddress, gint address[4]);
G_END_DECLS
/* myipaddress.c */
GType
my_ip_address_get_type (void)
{
static GType entry_type = 0;
if (!entry_type)
{
static const GTypeInfo entry_info =
{
sizeof (MyIPAddressClass),
NULL,
NULL,
(GClassInitFunc) my_ip_address_class_init,
NULL,
NULL,
sizeof (MyIPAddress),
0,
(GInstanceInitFunc) my_ip_address_init,
};
entry_type = g_type_register_static (GTK_TYPE_ENTRY, "MyIPAddress",
&entry_info, 0);
}
return entry_type;
}
不过上面的代码不是线程安全的。在 gtype.h 中(只要包含了 glib-object.h 就会自动包含这个文件)定义了一个方便的宏,它是线程安全的。这个宏是 #define G_DEFINE_TYPE(TN, t_n, T_P),不过它的实现只使用了 g_type_register_static_simple 函数(见下面),不够灵活,如果需要自己完整定义 GTypeInfo 结构的话,可以参考这个宏的实现。
GType g_type_register_static (GType parent_type,
const gchar *type_name,
const GTypeInfo *info,
GTypeFlags flags);
GType g_type_register_static_simple (GType parent_type,
const gchar *type_name,
guint class_size,
GClassInitFunc class_init,
guint instance_size,
GInstanceInitFunc instance_init,
GTypeFlags flags);
struct _GTypeInfo
{
/* interface types, classed types, instantiated types */
guint16 class_size;
GBaseInitFunc base_init;
GBaseFinalizeFunc base_finalize;
/* interface types, classed types, instantiated types */
GClassInitFunc class_init;
GClassFinalizeFunc class_finalize;
gconstpointer class_data;
/* instantiated types */
guint16 instance_size;
guint16 n_preallocs;
GInstanceInitFunc instance_init;
/* value handling */
const GTypeValueTable *value_table;
};
实现子类的过程其实就是实现 GTypeInfo 结构中各个函数指针以及该类的接口函数的过程,因此首先需要了解 GTypeInfo 各个域的作用,在中还会进一步介绍这些函数被调用的顺序。
static void
my_ip_address_class_init (MyIPAddressClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
/* Override the standard functions for setting and retrieving properties. */
gobject_class->set_property = my_ip_address_set_property;
gobject_class->get_property = my_ip_address_get_property;
/* Add MyIPAddressPrivate as a private data class of MyIPAddressClass. */
g_type_class_add_private (klass, sizeof (MyIPAddressPrivate));
/* Register the ip-changed signal, which will be emitted when the ip changes. */
my_ip_address_signals[CHANGED_SIGNAL] =
g_signal_new ("ip-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (MyIPAddressClass, ip_changed),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
/* Register four GObject properties, one for each ip address number. */
g_object_class_install_property (gobject_class, PROP_IP1,
g_param_spec_int ("ip-number-1",
"IP Address Number 1",
"The first IP address number",
0, 255, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_IP2,
g_param_spec_int ("ip-number-2",
"IP Address Number 2",
"The second IP address number",
0, 255, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_IP3,
g_param_spec_int ("ip-number-3",
"IP Address Number 3",
"The third IP address number",
0, 255, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_IP4,
g_param_spec_int ("ip-number-4",
"IP Address Number 1",
"The fourth IP address number",
0, 255, 0,
G_PARAM_READWRITE));
}
static void
my_ip_address_init (MyIPAddress *ipaddress)
{
MyIPAddressPrivate *priv = MY_IP_ADDRESS_GET_PRIVATE (ipaddress);
PangoFontDescription *fd;
guint i;
for (i = 0; i < 4; i++)
priv->address[i] = 0;
fd = pango_font_description_from_string ("Monospace");
gtk_widget_modify_font (GTK_WIDGET (ipaddress), fd);
my_ip_address_render (ipaddress);
pango_font_description_free (fd);
/* The key-press-event signal will be used to filter out certain keys. We will
* also monitory the cursor-position property so it can be moved correctly. */
g_signal_connect (G_OBJECT (ipaddress), "key-press-event",
G_CALLBACK (my_ip_address_key_pressed), NULL);
g_signal_connect (G_OBJECT (ipaddress), "notify::cursor-position",
G_CALLBACK (my_ip_address_move_cursor), NULL);
}