Introduction
- Drag and drop support within wxPython is a conversation between a "drop source" and a "drop target". The conversation is accomplished by sharing a "data object" which includes certain pieces of metadata (primarily the data types available from the drop source) as well as the actual shared data.
What Objects are Involved
- Source window -- Interprets an event as the beginning of a new drag-and-drop request. Instantiates a new drop source
and triggers the drag-and-drop sequence by calling DoDragDrop on the drop source object. Responds to the result code of the drag-and-drop sequence (move/copy/cancel/fail).
wxDropSource -- Provides common functionality for drag-and-drop source windows (UI interactions, data object storage)
- Destination window -- Advertises acceptable data types by
calling SetDropTarget with a configured drop target object.
wxDropTarget -- Responds to various "pseudo-events" during the drag-and-drop process, most importantly the OnData "event" which indicates that an object has been dropped on the associated window.
wxDataObject -- Provides storage and metadata relating to the data being transferred during a drag-and-drop operation. May support one of the built-in data types (text, bitmap, file), a single declared data type, or multiple data types. Includes: wxTextDataObject, wxBitmapDataObject, wxFileDataObject, wxDataObjectSimple, wxDataObjectComposite, wxDataObject
Process Overview
Create or choose a wxDataObject subclass appropriate to the data being shared
Provide OnData method to handle incoming data and update your application with the results of the drag-and-drop operation.
- If you are not using a built-in data type, choose a type specifier (a unique string used to identify the datatype). Only targets whose type specifiers include one of the current data source specifiers will be eligible for drops.
Create a wxPyDropTarget subclass (and instance)
Provide an OnData method to handle a drop "event"
Call self.GetData() to transfer data to the target's wxDataObject instance
Call wxDataObject.GetData() to retrieve the actual shared data
- Update your application to reflect drag-and-drop operation (in many cases you will need a pointer to the target window within the drop target instance to accomplish this).
Instantiate an instance of your wxDataObject class
Bind a wxDataObject to the drop target by calling SetDataObject. You will also want to keep a pointer to the wxDataObject in the drop target instance, so that you can call wxDataObject.GetData() within the OnData method.
Bind the drop target to the target window using wxWindow.SetDropTarget
- Handle an event on the source window which signals the start of the drag-and-drop cycle
Create a wxDropSource
Set the data object of the drop source to another instance of your wxDataObject class
Call the drop source DoDragDrop() method to begin the drag-and-drop operation
Respond to the result code of the DoDragDrop method as appropriate to your application
wxDataObjects
- Discuss the various concerns relating to the data object. Python pickling options Multiple formats -- currently only works for source in Python (as far as I can see) Format specifiers, do these need to be discussed? Special Data Types
Code Samples
- Simple drag-and-drop
# A very simple Drag and Drop Example # provided with no warranty whatsoever for any purpose, ever # This code creates a Text Control from which Text can be dragged, # a Text Control to which Text can be dragged (from the first Text Control or from other applications), # and a Text Control to which Files can be dragged from outside this application. # While the later two windows can receive data from outside the application, the first window # does not appear to be able to provide text to other applications. Please feel free to fix # this if you know how, as I think that would be more useful as an example. # It is designed to demonstrate the fundamentals of very simple drag-and-drop operations. """ This mini-ap is designed to demonstrate simple Drag and Drop functioning in wxPython """ __author__ = 'David Woods, Wisconsin Center for Education Research <dwoods@wcer.wisc.edu>' # Import wxPython from wxPython.wx import * # Declare GUI Constants MENU_FILE_EXIT = 101 DRAG_SOURCE = 201 # Define Text Drop Target class class TextDropTarget(wxTextDropTarget): """ This object implements Drop Target functionality for Text """ def __init__(self, obj): """ Initialize the Drop Target, passing in the Object Reference to indicate what should receive the dropped text """ # Initialize the wxTextDropTarget Object wxTextDropTarget.__init__(self) # Store the Object Reference for dropped text self.obj = obj def OnDropText(self, x, y, data): """ Implement Text Drop """ # When text is dropped, write it into the object specified self.obj.WriteText(data + '\n\n') # Define File Drop Target class class FileDropTarget(wxFileDropTarget): """ This object implements Drop Target functionality for Files """ def __init__(self, obj): """ Initialize the Drop Target, passing in the Object Reference to indicate what should receive the dropped files """ # Initialize the wsFileDropTarget Object wxFileDropTarget.__init__(self) # Store the Object Reference for dropped files self.obj = obj def OnDropFiles(self, x, y, filenames): """ Implement File Drop """ # For Demo purposes, this function appends a list of the files dropped at the end of the widget's text # Move Insertion Point to the end of the widget's text self.obj.SetInsertionPointEnd() # append a list of the file names dropped self.obj.WriteText("%d file(s) dropped at %d, %d:\n" % (len(filenames), x, y)) for file in filenames: self.obj.WriteText(file + '\n') self.obj.WriteText('\n') class MainWindow(wxFrame): """ This window displays the GUI Widgets. """ def __init__(self,parent,id,title): wxFrame.__init__(self,parent,-4, title, size = (800,600), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.SetBackgroundColour(wxWHITE) # Menu Bar # Create a MenuBar menuBar = wxMenuBar() # Build a Menu Object to go into the Menu Bar menu1 = wxMenu() menu1.Append(MENU_FILE_EXIT, "E&xit", "Quit Application") # Place the Menu Item in the Menu Bar menuBar.Append(menu1, "&File") # Place the Menu Bar on the ap self.SetMenuBar(menuBar) #Define Events for the Menu Items EVT_MENU(self, MENU_FILE_EXIT, self.CloseWindow) # GUI Widgets # Define a Text Control from which Text can be dragged for dropping # Label the control wxStaticText(self, -1, "Text Drag Source (left-click to select, right-click to drag)", (10, 1)) # Create a Text Control self.text = wxTextCtrl(self, DRAG_SOURCE, "", pos=(10,15), size=(350,500), style = wxTE_MULTILINE|wxHSCROLL) # Make this control a Text Drop Target # Create a Text Drop Target object dt1 = TextDropTarget(self.text) # Link the Drop Target Object to the Text Control self.text.SetDropTarget(dt1) # Put some text in the control as a starting place to have something to copy for x in range(20): self.text.WriteText("This is line %d of some text to drag.\n" % x) # Define Right-Click as start of Drag EVT_RIGHT_DOWN(self.text, self.OnDragInit) # Define a Text Control to recieve Dropped Text # Label the control wxStaticText(self, -1, "Text Drop Target", (370, 1)) # Create a read-only Text Control self.text2 = wxTextCtrl(self, -1, "", pos=(370,15), size=(410,235), style = wxTE_MULTILINE|wxHSCROLL|wxTE_READONLY) # Make this control a Text Drop Target # Create a Text Drop Target object dt2 = TextDropTarget(self.text2) # Link the Drop Target Object to the Text Control self.text2.SetDropTarget(dt2) # Define a Text Control to recieve Dropped Files # Label the control wxStaticText(self, -1, "File Drop Target (from off application only)", (370, 261)) # Create a read-only Text Control self.text3 = wxTextCtrl(self, -1, "", pos=(370,275), size=(410,235), style = wxTE_MULTILINE|wxHSCROLL|wxTE_READONLY) # Make this control a File Drop Target # Create a File Drop Target object dt3 = FileDropTarget(self.text3) # Link the Drop Target Object to the Text Control self.text3.SetDropTarget(dt3) # Display the Window self.Show(true) def CloseWindow(self, event): """ Close the Window """ self.Close() def OnDragInit(self, event): """ Begin a Drag Operation """ # Create a Text Data Object, which holds the text that is to be dragged tdo = wxPyTextDataObject(self.text.GetStringSelection()) # Create a Drop Source Object, which enables the Drag operation tds = wxDropSource(self.text) # Associate the Data to be dragged with the Drop Source Object tds.SetData(tdo) # Intiate the Drag Operation tds.DoDragDrop(wx.true) class MyApp(wxApp): """ Define the Drag and Drop Example Application """ def OnInit(self): """ Initialize the Application """ # Declare the Main Application Window frame = MainWindow(None, -1, "Drag and Drop Example") # Show the Application as the top window self.SetTopWindow(frame) return true # Declare the Application and start the Main Loop app = MyApp(0) app.MainLoop()
- File/bitmap/text
Comments...
I will add a example for dragging items in a wxTreeCtrl and what is more interresting how to drag a branch in a wxTreeCtrl. if added it will be found under ListAndTreeControls.
--René Freund