GTK透過GDK來處理事件,GDK會將每個接受到的XEvent轉換為GdkEvent,然後傳播給GtkWidget,引發一個與事件相對應的事件Signal,再透過Callback函式處理事件。
GdkEvent 是個C union的定義:
union GdkEvent
{
GdkEventType type;
GdkEventAny any;
GdkEventExpose expose;
GdkEventNoExpose no_expose;
GdkEventVisibility visibility;
GdkEventMotion motion;
GdkEventButton button;
GdkEventScroll scroll;
GdkEventKey key;
GdkEventCrossing crossing;
GdkEventFocus focus_change;
GdkEventConfigure configure;
GdkEventProperty property;
GdkEventSelection selection;
GdkEventOwnerChange owner_change;
GdkEventProximity proximity;
GdkEventClient client;
GdkEventDND dnd;
GdkEventWindowState window_state;
GdkEventSetting setting;
GdkEventGrabBroken grab_broken;
};
{
GdkEventType type;
GdkEventAny any;
GdkEventExpose expose;
GdkEventNoExpose no_expose;
GdkEventVisibility visibility;
GdkEventMotion motion;
GdkEventButton button;
GdkEventScroll scroll;
GdkEventKey key;
GdkEventCrossing crossing;
GdkEventFocus focus_change;
GdkEventConfigure configure;
GdkEventProperty property;
GdkEventSelection selection;
GdkEventOwnerChange owner_change;
GdkEventProximity proximity;
GdkEventClient client;
GdkEventDND dnd;
GdkEventWindowState window_state;
GdkEventSetting setting;
GdkEventGrabBroken grab_broken;
};
GdkEvent代表所有的事件型態,其成員 GdkEventType 為enum型態,可透過它來了解目前的事件是哪個類型:
GdkEventType type = event->type; // event 的宣告為 GdkEvent *event
switch(type) {
case GDK_DELETE:
g_print("GDK_DELETE");
...
break;
case GDK_DESTROY:
g_print("GDK_DELETE");
...
break;
...
}
switch(type) {
case GDK_DELETE:
g_print("GDK_DELETE");
...
break;
case GDK_DESTROY:
g_print("GDK_DELETE");
...
break;
...
}
一個使用的例子是,您可以設計一個接受所有事件的處理函式,根據GdkEventType來決定對所有事件作過濾處理,方 式就如上面的程式碼片段所示範的,一個GdkEvent可能對應多個GdkEventType,例如GdkButtonEvent可以對應的 GdkEventType有
GDK_BUTTON_PRESS
、
GDK_2BUTTON_PRESS
、
GDK_3BUTTON_PRESS
與GDK_BUTTON_RELEASE
。每個事件結構有其個別成員,例如GdkEventButton有x與y成員,代表滑鼠游標相對於視窗的位置:
typedef struct {
GdkEventType type;
GdkWindow *window;
gint8 send_event;
guint32 time;
gdouble x;
gdouble y;
gdouble *axes;
guint state;
guint button;
GdkDevice *device;
gdouble x_root, y_root;
} GdkEventButton;
GdkEventType type;
GdkWindow *window;
gint8 send_event;
guint32 time;
gdouble x;
gdouble y;
gdouble *axes;
guint state;
guint button;
GdkDevice *device;
gdouble x_root, y_root;
} GdkEventButton;
您可以這麼存取x或y成員:
gdouble x = event->button.x;
gdouble y = event->button.y;
gdouble y = event->button.y;
或是將之轉型為GdkEventButton再進行存取:
gdouble x = ((GdkEventButton*)event)->x;
gdouble y = ((GdkEventButton*)event)->y;
gdouble y = ((GdkEventButton*)event)->y;
GdkEvent傳播給GtkWidget,引發一個與事件相 對應的事件Signal,您可以使用g_signal_connect()函式連結該Signal與Callback函式來處理事件,事件類型與對應的事 件Signal名稱,基本上就是去掉GDK_名稱,轉為小寫並加上_event名稱,例如:
GDK_DELETE |
delete_event |
GDK_DESTROY |
destroy_event |
GDK_EXPOSE |
expose_event |
GDK_MOTION_NOTIFY |
motion_notify_event |
GDK_BUTTON_PRESS |
button_press_event |
GDK_2BUTTON_PRESS |
button_press_event |
GDK_3BUTTON_PRESS |
button_press_event |
GDK_BUTTON_RELEASE |
button_release_event |
GDK_KEY_PRESS |
key_press_event |
GDK_KEY_RELEASE |
key_release_event |
GDK_ENTER_NOTIFY |
enter_notify_event |
GDK_LEAVE_NOTIFY |
leave_notify_event |
GDK_FOCUS_CHANGE |
focus_in_event, focus_out_event |
GDK_CONFIGURE |
configure_event |
GDK_MAP |
map_event |
GDK_UNMAP |
unmap_event |
GDK_PROPERTY_NOTIFY |
property_notify_event |
GDK_SELECTION_CLEAR |
selection_clear_event |
GDK_SELECTION_REQUEST |
selection_request_event |
GDK_SELECTION_NOTIFY |
selection_notify_event |
GDK_PROXIMITY_IN |
proximity_in_event |
GDK_PROXIMITY_OUT |
proximity_out_event |
GDK_CLIENT_EVENT | client_event |
GDK_VISIBILITY_NOTIFY | visibility_notify_event |
GDK_WINDOW_STATE | window_state_event |
GDK_NO_EXPOSE |
no_expose_event |
如果是"event",則代表所有的事件。多個事件類型可能會對應同一個事件Signal,GDK_BUTTON、GDK_2BUTTON、GDK_3BUTTON,在事件的Signal連結時,都是使用button_press_event,在Callback函式中,再根據GdkEventType加以處理,部份的事件則有特殊的方式處理,例如滑鼠拖曳事件。
您也可以參考 GDK Event Types,以及 Events 中之說明。