📄 gnome-canvas-events.html
字号:
>int gnome_canvas_item_grab (GnomeCanvasItem *item, unsigned int event_mask, GdkCursor *cursor, guint32 etime);void gnome_canvas_item_ungrab (GnomeCanvasItem *item, guint32 etime); </PRE></TD></TR></TABLE><P> This function lets you apply grab operations to single Canvas items instead of an entire GdkWindow. The Canvas version is merely a wrapper around the gdk_pointer_grab( ) function, with a few customizations to help distinguish a specific Canvas item from the other items in that particular Canvas. These functions are much more intrusive and dangerous than gnome_canvas_item_grab_focus( ), which grabs the keyboard focus only. The grab function locks the focus at the X11 level, whereas the grab_focus function claims input focus only until the next GTK+ widget asks for it, and it doesn't need to be explicitly released. </P><P> The event_mask parameter specifies which events you want to grab. You load it just like the state field for GdkEvent structures, as a bitmask of GdkEventMask values that has been processed by the binary OR (|) operator. At the very least you'll want to pass in a value of (GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK) to allow mouse motion and button-release events into the item while the drag is active. You should release the drag during the next GDK_BUTTON_RELEASE event, so you must make sure you allow that event to pass into the grabbed item. On the other hand, the GDK_BUTTON_PRESS_MASK flag isn't normally necessary because you'll usually call gnome_canvas_item_grab( ) after you're already inside the GDK_BUTTON_PRESS event. The only time you would need to allow the button-press event into a Canvas item grab is if you wanted to support functionality for clicking more than one button at the same time during a drag. This is very strange, confusing behavior, and you should think long and hard before trying it. In nearly all cases you can ignore the button-press event during a grab. </P><P> It is usually a good idea to give users some visual feedback when they make a grab. Such feedback lets them know that the application's behavior is different from usual. It also lets them know if the initial grab click has failed. They will expect the cursor to change, and if it doesn't they will know that they clicked in the wrong place, instead of blaming the failed grab on the application. The cursor parameter of the grab function lets you change the mouse cursor for the duration of the grab. You can either create a cursor and pass it into the grab function, or pass in NULL and make no change to the cursor. </P><P> Creating a cursor is simple. You call gdk_cursor_new( ), passing in a single parameter of GdkCursorType, as defined in gtk+/gdk/gdkcursors.h. After invoking the grab, you can immediately destroy the cursor you just created. The grab function copies the cursor to the X server, where it resides as a server-side resource until the grab is over, so there's no need to keep a local copy. The process looks something like this: </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">/* Create four-arrowed cursor for drag operation */GdkCursor *cursor = gdk_cursor_new(GDK_FLEUR);gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->button.time);gdk_cursor_destroy(cursor); </PRE></TD></TR></TABLE><P> This example also shows what you can do with the final parameter, etime. The etime parameter is used mostly to break ties between two simultaneous attempts to grab windows. A GDK grab is a global possession, which applies even across applications. GDK allows only one window on the entire X server to own the current grab, so if GDK notices two grab requests at the same time, it uses the etime value to settle the dispute. You can pass in the value of event->button.time from the event handler, or GDK_CURRENT_TIME if you aren't inside an event handler. </P><P> When you're done with the grab, you must release the grab, using gnome_canvas_item_ungrab( ) if the grab is on a Canvas item. This step is mandatory, because the grab is such a global action. If your application grabs the cursor and never lets it go, other applications won't be able to receive the grabbed mouse events until you close the errant application. This is a very serious bug, so be very careful when using grabs. As long as you always release the grab in the GDK_BUTTON_RELEASE event and don't try anything too complicated, you should be fine. </P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN1317">Dragging and Dropping Canvas Items</A></H2><P> Drag-and-drop inside the Canvas is pretty straightforward to implement with what we know so far. You start by grabbing the cursor in the GDK_BUTTON_PRESS event; then you update the grabbed item's position in the Canvas according to the stream of GDK_MOTION_NOTIFY events you receive during the grab, and finally you release the grab in the GDK_BUTTON_RELEASE event. The only tricky parts are keeping track of when you're dragging and when you're not, and calculating the offsets for each successive motion event. Listing 11.15 shows one way to implement all this. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Listing 11.15 Drag-and-Drop Event Handlergint handle_canvas_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data){ /* Static variables for drag-and-drop */ static gboolean dragging = FALSE; static double previous_x, previous_y; double event_x = event->button.x; double event_y = event->button.y; switch (event->type) { case GDK_BUTTON_PRESS: if (event->button.button == 1) { GdkCursor *cursor; /* Store these coordinates for later... */ previous_x = event_x; previous_y = event_y; cursor = gdk_cursor_new(GDK_FLEUR); gnome_canvas_item_grab(item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, event->button.time); gdk_cursor_destroy(cursor); dragging = TRUE; } break; case GDK_MOTION_NOTIFY: if (dragging && (event->motion.state & GDK_BUTTON1_MASK)) { gnome_canvas_item_move(item, event_x - previous_x, event_y - previous_y); /* Remember these for the next pass */ previous_x = event_x; previous_y = event_y; } break; case GDK_BUTTON_RELEASE: gnome_canvas_item_ungrab(item, event->button.time); dragging = FALSE; break; default: break; } return FALSE;} </PRE></TD></TR></TABLE><P> The key to keeping the drag state and the motion offsets straight is to declare both as static variables inside the handler. We set dragging to TRUE when we grab, then back to FALSE when we ungrab, so that we know when to track the cursor movement and update the item's position inside the GDK_MOTION_NOTIFY event, and when to just ignore it. We don't have to worry about any other Canvas item receiving a GDK_MOTION_NOTIFY event during a drag because we've explicitly claimed those events with the GDK_POINTER_MOTION_MASK in the grab command. By definition, only the grabbed item can receive those events until the ungrab. </P><P> The offsets are a little more work. Each time we pass through the event handler, we update the current location of the pointer. We can compare the new position of the cursor (event_x and event_y) with the position we saved the last time around (previous_x and previous_y). By moving the grabbed Canvas item by the offset between the two sets of coordinates, we can keep the item in sync with the cursor position. We're not really dragging the Canvas item around, so much as mimicking the exact motions of the cursor. </P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.1 Common Properties for All Vector-Based Canvas Items </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.2 Unique Properties for Closed-Shape Canvas Items </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.3 Unique Properties for Canvas Line Items </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.4 Placement Properties for Vector-Based Canvas Items </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.5 Properties for GnomeCanvasWidget </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.6 Properties for GnomeCanvasText </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.7 Properties for GnomeCanvasImage </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.8 Properties for GnomeCanvasPixbuf </PRE></TD></TR></TABLE><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">Table 11.9 Behavior of Boolean Properties </PRE></TD></TR></TABLE></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="gnome-canvas-items.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="fdl.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Canvas Items</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="gnome-canvas.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">GNU Free Documentation License</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -