]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/demo/CustomDragAndDrop.py
   5 #---------------------------------------------------------------------- 
   8 class DoodlePad(wx
.Window
): 
   9     def __init__(self
, parent
, log
): 
  10         wx
.Window
.__init
__(self
, parent
, -1, style
=wx
.SUNKEN_BORDER
) 
  12         self
.SetBackgroundColour(wx
.WHITE
) 
  17         self
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnLeftDown
) 
  18         self
.Bind(wx
.EVT_LEFT_UP
,  self
.OnLeftUp
) 
  19         self
.Bind(wx
.EVT_RIGHT_UP
, self
.OnRightUp
) 
  20         self
.Bind(wx
.EVT_MOTION
, self
.OnMotion
) 
  21         self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
) 
  24     def SetMode(self
, mode
): 
  26         if self
.mode 
== "Draw": 
  27             self
.SetCursor(wx
.StockCursor(wx
.CURSOR_PENCIL
)) 
  29             self
.SetCursor(wx
.STANDARD_CURSOR
) 
  32     def OnPaint(self
, event
): 
  34         self
.DrawSavedLines(dc
) 
  36     def DrawSavedLines(self
, dc
): 
  38         dc
.SetPen(wx
.Pen(wx
.BLUE
, 3)) 
  39         for line 
in self
.lines
: 
  45     def OnLeftDown(self
, event
): 
  46         if self
.mode 
== "Drag": 
  47             self
.StartDragOpperation() 
  48         elif self
.mode 
== "Draw": 
  50             self
.x
, self
.y 
= event
.GetPositionTuple() 
  54             self
.log
.write("unknown mode!\n") 
  57     def OnLeftUp(self
, event
): 
  59             self
.lines
.append(self
.curLine
) 
  63     def OnRightUp(self
, event
): 
  67     def OnMotion(self
, event
): 
  68         if self
.HasCapture() and event
.Dragging() and not self
.mode 
== "Drag": 
  69             dc 
= wx
.ClientDC(self
) 
  71             dc
.SetPen(wx
.Pen(wx
.BLUE
, 3)) 
  72             coords 
= (self
.x
, self
.y
) + event
.GetPositionTuple() 
  73             self
.curLine
.append(coords
) 
  75             self
.x
, self
.y 
= event
.GetPositionTuple() 
  79     def StartDragOpperation(self
): 
  80         # pickle the lines list 
  81         linesdata 
= cPickle
.dumps(self
.lines
, 1) 
  83         # create our own data format and use it in a 
  85         ldata 
= wx
.CustomDataObject("DoodleLines") 
  86         ldata
.SetData(linesdata
) 
  88         # Also create a Bitmap version of the drawing 
  90         bmp 
= wx
.EmptyBitmap(size
.width
, size
.height
) 
  93         dc
.SetBackground(wx
.WHITE_BRUSH
) 
  95         self
.DrawSavedLines(dc
) 
  96         dc
.SelectObject(wx
.NullBitmap
) 
  98         # Now make a data object for the bitmap and also a composite 
  99         # data object holding both of the others. 
 100         bdata 
= wx
.BitmapDataObject(bmp
) 
 101         data 
= wx
.DataObjectComposite() 
 105         # And finally, create the drop source and begin the drag 
 106         # and drop opperation 
 107         dropSource 
= wx
.DropSource(self
) 
 108         dropSource
.SetData(data
) 
 109         self
.log
.WriteText("Begining DragDrop\n") 
 110         result 
= dropSource
.DoDragDrop(wx
.Drag_AllowMove
) 
 111         self
.log
.WriteText("DragDrop completed: %d\n" % result
) 
 113         if result 
== wx
.DragMove
: 
 118 #---------------------------------------------------------------------- 
 121 class DoodleDropTarget(wx
.PyDropTarget
): 
 122     def __init__(self
, window
, log
): 
 123         wx
.PyDropTarget
.__init
__(self
) 
 127         # specify the type of data we will accept 
 128         self
.data 
= wx
.CustomDataObject("DoodleLines") 
 129         self
.SetDataObject(self
.data
) 
 132     # some virtual methods that track the progress of the drag 
 133     def OnEnter(self
, x
, y
, d
): 
 134         self
.log
.WriteText("OnEnter: %d, %d, %d\n" % (x
, y
, d
)) 
 138         self
.log
.WriteText("OnLeave\n") 
 140     def OnDrop(self
, x
, y
): 
 141         self
.log
.WriteText("OnDrop: %d %d\n" % (x
, y
)) 
 144     def OnDragOver(self
, x
, y
, d
): 
 145         #self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d)) 
 147         # The value returned here tells the source what kind of visual 
 148         # feedback to give.  For example, if wxDragCopy is returned then 
 149         # only the copy cursor will be shown, even if the source allows 
 150         # moves.  You can use the passed in (x,y) to determine what kind 
 151         # of feedback to give.  In this case we return the suggested value 
 152         # which is based on whether the Ctrl key is pressed. 
 157     # Called when OnDrop returns True.  We need to get the data and 
 158     # do something with it. 
 159     def OnData(self
, x
, y
, d
): 
 160         self
.log
.WriteText("OnData: %d, %d, %d\n" % (x
, y
, d
)) 
 162         # copy the data from the drag source to our data object 
 164             # convert it back to a list of lines and give it to the viewer 
 165             linesdata 
= self
.data
.GetData() 
 166             lines 
= cPickle
.loads(linesdata
) 
 167             self
.dv
.SetLines(lines
) 
 169         # what is returned signals the source what to do 
 170         # with the original data (move, copy, etc.)  In this 
 171         # case we just return the suggested value given to us. 
 176 class DoodleViewer(wx
.Window
): 
 177     def __init__(self
, parent
, log
): 
 178         wx
.Window
.__init
__(self
, parent
, -1, style
=wx
.SUNKEN_BORDER
) 
 180         self
.SetBackgroundColour(wx
.WHITE
) 
 183         dt 
= DoodleDropTarget(self
, log
) 
 184         self
.SetDropTarget(dt
) 
 185         self
.Bind(wx
.EVT_PAINT
, self
.OnPaint
) 
 188     def SetLines(self
, lines
): 
 192     def OnPaint(self
, event
): 
 193         dc 
= wx
.PaintDC(self
) 
 194         self
.DrawSavedLines(dc
) 
 196     def DrawSavedLines(self
, dc
): 
 198         dc
.SetPen(wx
.Pen(wx
.RED
, 3)) 
 200         for line 
in self
.lines
: 
 205 #---------------------------------------------------------------------- 
 207 class CustomDnDPanel(wx
.Panel
): 
 208     def __init__(self
, parent
, log
): 
 209         wx
.Panel
.__init
__(self
, parent
, -1) 
 211         self
.SetFont(wx
.Font(10, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
, False)) 
 214         text1 
= wx
.StaticText(self
, -1, 
 215                             "Draw a little picture in this window\n" 
 216                             "then switch the mode below and drag the\n" 
 217                             "picture to the lower window or to another\n" 
 218                             "application that accepts Bitmaps as a\n" 
 222         rb1 
= wx
.RadioButton(self
, -1, "Draw", style
=wx
.RB_GROUP
) 
 224         rb2 
= wx
.RadioButton(self
, -1, "Drag") 
 227         text2 
= wx
.StaticText(self
, -1, 
 228                              "The lower window is accepting a\n" 
 229                              "custom data type that is a pickled\n" 
 230                              "Python list of lines data.") 
 232         self
.pad 
= DoodlePad(self
, log
) 
 233         view 
= DoodleViewer(self
, log
) 
 236         sizer 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 237         box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 238         rbox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 242         box
.Add(text1
, 0, wx
.ALL
, 10) 
 243         box
.Add(rbox
, 0, wx
.ALIGN_CENTER
) 
 245         box
.Add(text2
, 0, wx
.ALL
, 10) 
 249         dndsizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 250         dndsizer
.Add(self
.pad
, 1, wx
.EXPAND|wx
.ALL
, 5) 
 251         dndsizer
.Add(view
, 1, wx
.EXPAND|wx
.ALL
, 5) 
 253         sizer
.Add(dndsizer
, 1, wx
.EXPAND
) 
 255         self
.SetAutoLayout(True) 
 259         self
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
, rb1
) 
 260         self
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
, rb2
) 
 263     def OnRadioButton(self
, evt
): 
 264         rb 
= self
.FindWindowById(evt
.GetId()) 
 265         self
.pad
.SetMode(rb
.GetLabel()) 
 268 #---------------------------------------------------------------------- 
 269 #---------------------------------------------------------------------- 
 271 class TestPanel(wx
.Panel
): 
 272     def __init__(self
, parent
, log
): 
 273         wx
.Panel
.__init
__(self
, parent
, -1) 
 275         self
.SetAutoLayout(True) 
 276         sizer 
= wx
.BoxSizer(wx
.VERTICAL
) 
 278         msg 
= "Custom Drag-And-Drop" 
 279         text 
= wx
.StaticText(self
, -1, "", style
=wx
.ALIGN_CENTRE
) 
 280         text
.SetFont(wx
.Font(24, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
, False)) 
 282         w
,h 
= text
.GetTextExtent(msg
) 
 283         text
.SetSize(wx
.Size(w
,h
+1)) 
 284         text
.SetForegroundColour(wx
.BLUE
) 
 285         sizer
.Add(text
, 0, wx
.EXPAND|wx
.ALL
, 5) 
 286         sizer
.Add(wx
.StaticLine(self
, -1), 0, wx
.EXPAND
) 
 288         sizer
.Add(CustomDnDPanel(self
, log
), 1, wx
.EXPAND
) 
 293 #---------------------------------------------------------------------- 
 295 def runTest(frame
, nb
, log
): 
 296     #win = TestPanel(nb, log) 
 297     win 
= CustomDnDPanel(nb
, log
) 
 301 if __name__ 
== '__main__': 
 305         def WriteText(self
, text
): 
 306             sys
.stdout
.write(text
) 
 308     class TestApp(wx
.App
): 
 310             wx
.InitAllImageHandlers() 
 314         def MakeFrame(self
, event
=None): 
 315             frame 
= wx
.Frame(None, -1, "Custom Drag and Drop", size
=(550,400)) 
 317             item 
= menu
.Append(-1, "Window") 
 319             mb
.Append(menu
, "New") 
 321             frame
.Bind(wx
.EVT_MENU
, self
.MakeFrame
, item
) 
 322             panel 
= TestPanel(frame
, DummyLog()) 
 324             self
.SetTopWindow(frame
) 
 326     #---------------------------------------------------------------------- 
 331 #---------------------------------------------------------------------- 
 334 overview 
= """<html><body> 
 335 This demo shows Drag and Drop using a custom data type and a custom 
 336 data object.  A type called "DoodleLines" is created and a Python 
 337 Pickle of a list is actually transfered in the drag and drop 
 340 A second data object is also created containing a bitmap of the image 
 341 and is made available to any drop target that accepts bitmaps, such as 
 344 The two data objects are combined in a wx.DataObjectComposite and the 
 345 rest is handled by the framework.