6/25/2011

GObject 入門 (Part 7) - 發送與接收訊息

訊息發送系統(messaging system)是GObject system內建功能之一,它讓物件於事件發生時,用來發送訊息給其他註冊該訊息者。這樣的設計可以避免系統或物件過於耦合(coupling),大型系統裡常可見到這樣的設計(Mediator pattern)。


在GObject system裡,物件(GObject)可透過g_signal_new()g_signal_newv()註冊新的信號;並以g_signal_emit()發送信號。爾後,經由g_signal_connect()即可連結(connect)或接收某物件發出的信號。
比如,若想要加入「redrawn」事件至本系列文章中的Drawable介面,我們可以先於class_init之時註冊信號(signal);接著於繪圖完畢後,發送信號。範例如下:
static void drawable_class_init(DrawableInterface* self)
{
    g_print("Drawable(0x%08x)::class::initialize\n", (guint)self);

    signals[DRAW_SIGNAL] =
        g_signal_newv("redrawn",
                      DRAWABLE_IFACE,
                      G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
                      NULL /* closure */,
                      NULL /* accumulator */,
                      NULL /* accumulator data */,
                      g_cclosure_marshal_VOID__VOID,
                      G_TYPE_NONE /* return_type */,
                      0     /* n_params */,
                      NULL  /* param_types */);
}

void draw_object(Drawable* drawable)
{
    if (!IS_DRAWABLE(drawable)) {
        g_print("%s(0x%08x) is not drawable.\n",
                G_OBJECT_TYPE_NAME(drawable), (guint)drawable);
        return;
    }

    DRAWABLE_GET_INTERFACE(drawable)->draw(drawable);

    g_signal_emit(drawable, signals[DRAW_SIGNAL], 0 /* details */);
}
每當g_signal_emit()被喚起時,特定的事件就會被發送至GObject system,接著被派送至與其連結的物件或回呼函式(callback function)。要連結至某物件的事件只需要執行g_signal_connect()向GObject system註冊即可。
static void logger(gpointer instance, gpointer user_data)
{
    g_print("logger: Object(0x%08x) redrawed\n", (guint)instance);
}

int main(int argc, char** argv)
{
    ... ... ...
    g_signal_connect(rect, "redrawn", G_CALLBACK(logger), NULL);
    ... ... ...
}

執行範例:
Shape(0x09c0b250)::base::initialize
Shape(0x09c0b250)::class::initialize
Shape(0x09c25fc0)::base::initialize
Rectangle(0x09c25fc0)::base::initialize
Drawable(0x09c0b1e8)::base::initialize
Drawable(0x09c0b1e8)::class::initialize
Drawable(0x09c26010)::base::initialize
Rectangle(0x09c25fc0)::class::initialize
Rectangle(0x09c26010)::Drawable::initialize
Rectangle(0x09c05048)::instance::initialize
Rectangle(0x09c05048)::SetProperty::Width(4)
Rectangle(0x09c05048)::SetProperty::Height(5)
Shape(0x09c05048)::constructor
Rectangle(0x09c05048)::constructor
Rectangle(0x09c05048, 4x5) is created.
Rectangle(0x09c05048)::Drawable::draw
 +------+
 |      |
 +------+
logger: Object(0x09c05048) redrawed
Rectangle(0x09c05048)::dispose
Shape(0x09c05048)::dispose
Rectangle(0x09c05048)::finalize
Shape(0x09c05048)::finalize

完整程式碼

No comments:

Post a Comment