📄 gnome-canvas-events.html
字号:
{ /* Process event for Shift-Ctrl combination, but ignore * Shift-only and Ctrl-only combinations. */} </PRE></TD></TR></TABLE><P> For the most part you can ignore the remaining fields of GdkEventButton. They are used primarily for full-blooded GTK+ event handling and don't really apply to Canvas item events. Most of them exist to handle alternative pointer hardware, like graphics tablets. The time field will come in handy later, when we need to grab a Canvas item (see Section 11.5.6). </P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1282">Mouse Motion</A></H2><P> In addition to tracking mouse clicks, the Canvas keeps track of mouse motion events, using the GdkEventMotion structure, which is the motion field from Listing 11.8. As you can see in Listing 11.11, the only difference between this event and GdkEventButton is that the is_hint field replaces the button field of GdkEventButton. The is_hint field describes the volume of motion events that the X server is sending. If is_hint is TRUE (which implies that GDK_POINTER_MOTION_MASK is not enabled), the application knows that the X server is sending only one unsolicited motion event at a time-only hints of motion-and will send further motion events only if the user clicks another button or key, or moves the cursor to a different GdkWindow. Conversely, an is_hint value of FALSE tells the application that the X server is sending a constant stream of updates for every change in mouse position: Each motion event is the real thing, not just a hint. Hinting can be turned on and off separately for each GdkWindow but is typically left on unless a window needs detailed knowledge of the mouse position. As we'll see, the Canvas requires the full, unthrottled flow of mouse events and will thus set the GDK_POINTER_MOTION_MASK on its GdkWindow. This means that the is_hint flag will always be FALSE for Canvas item motion events. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.11 GdkEventMotion Structurestruct _GdkEventMotion{ GdkEventType type; GdkWindow *window; gint8 send_event; guint32 time; gdouble x; gdouble y; gdouble pressure; gdouble xtilt; gdouble ytilt; guint state; gint16 is_hint; GdkInputSource source; guint32 deviceid; gdouble x_root, y_root;}; </PRE></TD></TR></TABLE><P> Listing 11.12 shows an example of a diagnostic event handler that prints out a potential flood of messages as you move the cursor around inside a Canvas item. The handler also prints out messages when you click mouse buttons and hold down modifier keys: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.12 Sample Motion Event Handlergint handle_canvas_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data){ gchar keystate[30]; gboolean shift_pressed = event->button.state & GDK_SHIFT_MASK; gboolean ctrl_pressed = event->button.state & GDK_CONTROL_MASK; gboolean alt_pressed = event->button.state & GDK_MOD1_MASK; g_snprintf(keystate, sizeof(keystate), "%s%s%s", shift_pressed ? "[Shift] " : "", ctrl_pressed ? "[Ctrl] " : "", alt_pressed ? "[Alt] " : ""); switch ((int)event->type) { case GDK_BUTTON_PRESS: g_message("Button %d press (state = %d) %s", event->button.button, event->button.state, keystate); return TRUE; case GDK_BUTTON_RELEASE: g_message("Button %d release (state = %d) %s", event->button.button, event->button.state, keystate); return TRUE; case GDK_MOTION_NOTIFY: g_message("Mouse movement (state = %d) (%4.1f, %4.1f) %s", event->button.state, event->motion.x, event->motion.y, keystate); return TRUE; } /* Event not handled; try parent item */ return FALSE;} </PRE></TD></TR></TABLE><P> The sample output will look something like this excerpt: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Message: Mouse movement (state = 0) (174.0, 41.0)Message: Mouse movement (state = 0) (174.0, 47.0)Message: Mouse movement (state = 0) (174.0, 50.0)Message: Mouse movement (state = 1) (174.0, 51.0) [Shift]Message: Mouse movement (state = 1) (174.0, 54.0) [Shift]Message: Mouse movement (state = 1) (174.0, 55.0) [Shift]Message: Button 1 press (state = 1) [Shift]Message: Mouse movement (state = 257) (174.0, 56.0) [Shift]Message: Mouse movement (state = 257) (174.0, 58.0) [Shift]Message: Mouse movement (state = 257) (174.0, 61.0) [Shift]Message: Mouse movement (state = 257) (173.0, 65.0) [Shift]Message: Mouse movement (state = 257) (173.0, 67.0) [Shift]Message: Button 1 release (state = 257) [Shift]Message: Mouse movement (state = 1) (173.0, 68.0) [Shift]Message: Mouse movement (state = 1) (173.0, 70.0) [Shift]Message: Mouse movement (state = 0) (172.0, 71.0)Message: Mouse movement (state = 0) (172.0, 73.0)Message: Mouse movement (state = 0) (172.0, 74.0) </PRE></TD></TR></TABLE><P> In this slightly unrealistic example, the user enters the item from above and moves the mouse downward. During the drag, the user presses the Shift button and then the left mouse button, then releases the mouse button and the Shift key, and then stops. Note that the motion events don't enjoy a one-to-one correspondence to world coordinates. Also, the faster the mouse is moving, the larger the jump is between each consecutive point. This is a side effect of the sampling rate of the mouse's movement by the X server. Notice that the state value during the Shift-drag is 257, which is exactly equal to (GDK_SHIFT_MASK | GDK_BUTTON1_MASK). </P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1291">Rollovers</A></H2><P> Now you can detect when and how the user clicks and moves around inside a Canvas item. But how can you tell when the cursor enters or leaves a specific item? Normally GDK sends only GDK_ENTER_NOTIFY and GDK_LEAVE_NOTIFY events to GdkWindow instances. GDK has no knowledge of the Canvas's abstract notion of Canvas items, and it can't be expected to know when the cursor rolls into a new item. As far as GDK is concerned, you are still just moving around in the same widget window, and it will continue to generate GDK_MOTION_NOTIFY events until you completely leave the Canvas window. </P><P> Only the Canvas can know when you enter and leave a Canvas item, so it is up to the Canvas to handle these notifications. To make things easier for the developer, the Canvas watches the cursor position and internally synthesizes enter and leave events from scratch. GTK+ is oblivious to these synthetic events. The Canvas items are aware of them only because the Canvas sends the fake events to the same event handlers that it sends the other item events. All of this is transparent to the Canvas-using developer, though. You can set up entries in your handler's switch( ) statement for enter and leave events just as you would with any normal GTK+ event handler. </P><P> Thus rollover events are as simple as adding a GDK_ENTER_NOTIFY case to your handler's switch( ) statement. If you need to clean up anything after the rollover-perhaps you changed the color or shape of the item and need to revert back to its original state-just add a GDK_LEAVE_NOTIFY case as well. Listing 11.13 shows a modified version of the event handler template from Listing 11.7. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.13 GnomeCanvasItem Event Handler with Rollover Supportgint handle_canvas_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data){ switch (event->type) { case GDK_BUTTON_PRESS: /* Handle mouse button press */ return TRUE; case GDK_BUTTON_RELEASE: /* Handle mouse button release */ return TRUE; case GDK_MOTION_NOTIFY: /* Handle mouse movement */ return TRUE; case GDK_ENTER_NOTIFY: /* Handle rollover */ return TRUE; case GDK_LEAVE_NOTIFY: /* Clean up after rollover */ return TRUE; } /* Event not handled; try parent item */ return FALSE;} </PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1297">Keyboard Events</A></H2><P> Handling keyboard events is analogous to handling button-press events. GTK+ generates GDK_KEY_PRESS and GDK_KEY_RELEASE events (although the key-release event is not always as predictable as the key-press event, depending on your hardware, so be careful not to base too much on receiving the release event) and passes the concurrent key modifiers as bit flags in the state field of the GdkEventKey structure (see Listing 11.14), which is just like the state field in GdkEventButton. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.14 GdkEventKey Structurestruct _GdkEventKey{ GdkEventType type; GdkWindow *window; gint8 send_event; guint32 time; guint state; guint keyval; gint length; gchar *string;}; </PRE></TD></TR></TABLE><P> The only fields we haven't seen before are the last three, which tell us which key the user just pressed. The keyval field is the one you'll most often use in Canvas item keyboard event handlers. It contains the GDK value of the key, as defined in gtk+/gdk/gdkkeysyms.h. Each such key value is prefixed by "GDK_" followed by a descriptive name for the key-for example, GDK_t for the lowercase letter t, GDK_Up for the up arrow, GDK_Shift_L for the left Shift key, and GDK_F5 for the F5 function key. You can use the gdk_keyval_*( ) functions to further process this value. </P><P> The length and string fields represent a printable version of the key, if any, which you might use to render the user's text input to a text display or entry widget. If you decide to use the string field, you should make sure the value of length is greater than 0 to avoid printing out potential junk to your text buffer. </P><P> The key-press event sits in the item's event handler, alongside the other events, like this: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">gint handle_canvas_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data){ switch (event->type) { ... case GDK_KEY_PRESS: /* Handle keyboard input */ return TRUE; ... } /* Event not handled; try parent item */ return FALSE;} </PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1305">Grabbing Items</A></H2><P> GTK+, or more specifically GDK, allows you to grab a window and funnel some or all mouse events to that window. A window grab does for the mouse what window focus does for the keyboard. Just as the currently focused window receives all keyboard input until it loses focus, a grabbed window potentially receives all mouse events until it relinquishes the grab. This feature is critical for drag-and-drop operations, as we'll see in Section 11.5.7. The GDK function for this is gdk_pointer_grab( ); its companion function is gdk_pointer_ungrab( ). These functions act on a GdkWindow instance as a whole. </P><P> The Canvas supplies its own function for grabbing, called gnome_canvas_item_grab( ): </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -