[ruby-gnome2-doc-cvs] [Ruby-GNOME2 Project Website] update - tut-gtk2-dnd-intro

Back to archive index

ruby-****@sourc***** ruby-****@sourc*****
2012年 12月 9日 (日) 05:40:32 JST


-------------------------
REMOTE_ADDR = 184.145.81.223
REMOTE_HOST = 
        URL = http://ruby-gnome2.sourceforge.jp/hiki.cgi?tut-gtk2-dnd-intro
-------------------------
@@ -339,11 +339,76 @@
     Do not pay too much attention to the above 'HikiDnDdbg' auxiliary module. It provides rather useful drag-and-drop debugging methods, which if commented out of the example programs that use them should in no way effect user's experience, unless of course that user is a developer, that would like to observe some of the behind the scene run-time program characteristics. The only thing you should pay attention to is how we are including such auxiliary modules into our programs and developing environment.
 
 
-Our 'button-to-label-dnd.rb' example program consists of a single 'DnDWindow' class which is the subclass of the 'BasicWindow' base class, i.e. the class defined in the module 'HikiGTK'. The BasicWindow base class is a Gtk::Window class, implementing the most rudimentary Gtk::Window behaviour, that any application should always implement. It sets up the top level 'delete_event' and 'destroy' widget signals, sets up the window title if, it is passed to its window constructor, and takes care of the window size and its border. Indeed, you can override all these properties and behaviours in your main (driving) window subclass you are defining. 
 
+Our 'button-to-label-dnd.rb' example program consists of a single 'DnDWindow' class which is a subclass of the 'BasicWindow' base class, i.e. the class defined in the module 'HikiGTK'. The BasicWindow base class is a Gtk::Window class, implementing the most rudimentary Gtk::Window behaviour, that any application should always implement. It sets up the top level 'delete_event' and 'destroy' widget signals, sets up the window title if, it is passed to its window constructor, and takes care of the window size and its border. Indeed, you can override all these properties and behaviours in your main (driving) window subclass you are defining.
+
+
+
 :A Note About the DnD Widgets And 'HikiDnDdbg' Module In This Example:
 
     Note, that the 'HikiDnDdbg' module is not terribly important in this program, we could easily live without it. We included it only to add a single method, called 'show_if_widget_contains_its_own_gdk_window', to our 'DnDWindow' class, to show that neither the button nor the label widget contains its own Gdk::Window, and yet, contrary to the official Gtk API documentation, we can set these two widgets as dnd source and destination. 
+
+
+Our 'DnDWindow' class contains three methods. The default Ruby constructor (initialize), and three methods of our own, namely the 'set_dnd_source_widget', 'set_dnd_destination_widget', and on_drag_drop methods.
+
+The UI for this program is initialized in the 'initialize' method, where we create both dnd source button and destination label widgets, register them as the source and the destination widget respectively, and finally pack the two into a horizontal box, which is then added to the DnDWindow, and exposed by calling 'show_all' on self, i.e. on the DnDWindow itself. Initialization is concluded by the mandatory 'Gtk::main' call. From the dnd prospective, except the indirect source and destination dnd widget registration there is nothing new revealed in the 'initialize' method. Our interest lies within the two registration 'set_dnd_{source|destination}_widgets' methods. Both of these two methods take as arguments, beside the widget object either Gtk constants or the constants we defined at the beginning of our DnDWindow class. Following is code segment from our DnDWindow class where these constants are defined:
+
+  B2LDND_FLAGS   = Gtk::Drag::TARGET_SAME_APP
+  B2LDND_INFO    = 105
+  B2LDND_TARGETS = [["btt-2-label dnd test", B2LDND_FLAGS, B2LDND_INFO]]
+  B2LDND_ACTIONS = Gdk::DragContext::ACTION_ASK	           # _ASK,_COPY,_LINK,_MOVE,_DEFAULT,_PRIVATE
+
+We already discussed how these constants are assembled above in the paragraph with the title '((<Identifying the DnD Objects|tut-gtk2-dnd#Identifying the DnD Objects>))'. Basically, these constants are used as a convenience to help a developer synchronize the source and destination widget registration. Namely, source and destination widget must agree on the targets, i.e. objects allowed to be dragged and dropped. These objects are described in tuples called 'targets'. If you recall, a tuple consists of three items '[target, flags, info]'. The((*'target'*))parameter is a string identifying the object to be dragged. The((*'flags'*))parameter is one of the constants defined in Gtk::Drag#TargetFlags (TARGET_SAME_APP, TARGET_SAME_WIDGET, TARGET_OTHER_APP, and TARGET_OTHER_WIDGET). And the((*'info'*))element is by the application or the developer defined identification integer. Both source and destination registration methods accept a list (an array) of tuples, which means that th
 ere could be different kinds of objects that are dragged from a source (or perhaps from many different sources), as well that on a destination widget many different kinds of objects can be dropped. Whether the objects can come from different source widgets or even different applications is defined with the flag element in each tuple. Note also the '*_ACTIONS' constant, this constant is not part of the tuple, or 'targets' definition, it is usually different for source widget registration, than for registration of the destination, however interestingly enough not for or our button and label source and destination widgets! (Note that for both sides we defined the same action, namely, Gdk::DragContext::ACTION_ASK). You can already tell, this constant is defined in Gdk::DragContext#GdkDragAction, and determines how a dragging item is handled on the either source or destination side.
+
+:'set_dnd_source_widget' instance method:
+
+    As already mentioned, our DnDWindow class has three instance methods we added. First we define the 'set_dnd_source_widget' method to register our 'Drag Here' button as source widget. As you can see from the code, we do not define a signal handler and subsequently also no callback for the source widget. You will see in a moment, that in this program all the work to swap the location of source and destination widgets is performed entirely on the receiving (destination) side. All the dnd work that Gtk does for us here is managing the display, namely, taking care a proper dnd cursor icons are shown during the drag operation. When registering source we also have to provide the argument for 'start_button_mask' parameter, so Gtk knows that if that mouse button is pressed while the cursor is hovering over the source widget, it has to change the cursor icon to 'drag-document' icon. Following is the code segment with our 'set_dnd_source_widget' instance method:
+
+     def set_dnd_source_widget(widg)
+
+       # -- Gtk::Drag.source_set sets up a widget so that GTK+ will start a drag
+       #    operation when the user clicks and drags on the widget. The widget
+       #    must have its own gdk window. (Well, Gtk::Button widget does not as
+       #    the following DEBUG line reveals, nevertheless, we can set a button
+       #    as the source dnd widget):
+       puts "DEBUG: #{show_if_widget_contains_its_own_gdk_window(widg)}"
+
+       Gtk::Drag.source_set(
+         widget=widg, 
+         start_button_mask=Gdk::Window::BUTTON1_MASK,
+         targets=B2LDND_TARGETS,
+         actions=B2LDND_ACTIONS
+       )
+     end
+
+    The only thing this method does is registers the button widget. We really did not have to wrap this registration into a method of its own, however, it provides us with better and cleaner ways to add new testing and debugging features, as well as a pack away registration of any additional callbacks, we may wish to implement for the source side.
+
+    (Note also our 'debug-line' the reason we 'required' our 'HikiDnDdbg' module.)
+
+It is important to realize that in this program source widget represents both the location from which we start dragging the object, as well as the object we are dragging. On the other hand our destination here, the label, seems more natural - namely it does represent the location to which we are dragging our button object. However, as you will see next, this destination object is removed to make place for the button, we drop on it. (By now you should know that label widget is not a container, and hence it may not hold any other widget, except its text, and optionally an image.)
+
+:'set_dnd_destination_widget' instance method:
+
+    In the 'set_dnd_destination_widget' method we undoubtedly find the gist of this dnd example. But let's first talk about the basics, namely, about setting up the destination, i.e. (Gtk::Drag.dest_set). The firs thing to notice is that beside the 'flags' item in the tuple, we have an extra 'flags' argument, that is not a part of a 'targets' tuple, namely, Gtk::Drag::DEST_DEFAULT_ALL. These flags are defined in Gtk::Drag#DestDefaults. Other thing you should see is, that 'targets' and 'actions' arguments are the same as those used when we registered the source widget. Particularly interesting is the fact, that actions for both source and destination here are also the same, though usually when mixing source and destination widgets with and without native dnd support they differ.
+
+    As before note the 'debug-line' tese two lines in source set-up method and here are the only reasons we 'required' our 'HikiDnDdbg' module. However, they serve their purpose, by making a point that widgets without their own Gdk::Window can, indeed, be set up as dnd source and destination widgets. 
+
+    But the most important or interesting part on destination side is the signal handler for the 'drag-drop' signal. We have wrapped it into its own instance method, called 'on_drag_drop'. We'll look at it next, but first lets see the code segment with our 'set_dnd_destination_widget' instance method:
+
+     def set_dnd_destination_widget(dest_widg)	### See:toolbars eg.: (src_widg, toolbar, dest_widg)
+   
+       puts "DEBUG: #{show_if_widget_contains_its_own_gdk_window(dest_widg)}"
+   
+       Gtk::Drag.dest_set(
+         widget=dest_widg,
+         flags=Gtk::Drag::DEST_DEFAULT_ALL,
+         targets=B2LDND_TARGETS,    # [["btt-2-label dnd test", Gtk::Drag::TARGET_SAME_APP, 105]]
+         actions=B2LDND_ACTIONS	    # Gdk::DragContext::ACTION_ASK
+       )
+       dest_widg.signal_connect('drag-drop') { |w, e| on_drag_drop(w, e) }
+     end
+
+
 
 
 




ruby-gnome2-cvs メーリングリストの案内
Back to archive index