Home  Contents

Drag & Drop in Mono Winforms

This part of the IronPython Mono Winforms tutorial will be dedicated to the drag & drop operations.

In computer graphical user interfaces, drag-and-drop is the action of (or support for the action of) clicking on a virtual object and dragging it to a different location or onto another virtual object. In general, it can be used to invoke many kinds of actions, or create various types of associations between two abstract objects. (Wikipedia)

Drag and drop functionality is one of the most visible aspects of the graphical user interface. Drag and drop operation enables you to do complex things intuitively.

Dragging a button

In the first example, we will do the drag & drop operation on the button control. The example does the job outside the drag & drop protocol.

dragbutton.py
#!/usr/bin/ipy import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, Button from System.Drawing import Size, Point class IForm(Form): def __init__(self): self.Text = 'Drag & Drop' button = Button() button.Parent = self button.Text = 'Button' button.MouseDown += self.OnMousDown button.MouseUp += self.OnMousUp button.MouseMove += self.OnMousMove button.Location = Point(20, 20) self.isDragging = False self.CenterToScreen() def OnMousDown(self, sender, event): self.isDragging = True self.oldX = event.X self.oldY = event.Y def OnMousMove(self, sender, event): if self.isDragging: sender.Top = sender.Top + (event.Y - self.oldY) sender.Left = sender.Left + (event.X - self.oldX) def OnMousUp(self, sender, event): self.isDragging = False Application.Run(IForm())

The code example puts a regular button control on the form container. By clicking on the button surface and simultaneously dragging it with a mouse we can relocate the button.

There are some supporting variables in our example. The isDragging variable tells us, whether we are in the process of dragging an object. The oldX and oldY variables store the x, y coordinates just before the dragging process begins.

 button.MouseDown += self.OnMousDown
 button.MouseUp += self.OnMousUp
 button.MouseMove += self.OnMousMove

We plug in three different mouse handlers for our button. They implement three different stages of the drag & drop process. The process begins, when we click on the button. This is handled by the OnMousDown() method. The second part is the movement. This is when we move the object to a new position. It is handled in the OnMousMove() method. The final part is when the process stops. It happens when we release the mouse button. The appropriate task is delegated to the OnMousUp() method.

 def OnMousDown(self, sender,  event):
  
    self.isDragging = True
    self.oldX = event.X
    self.oldY = event.Y

The OnMousDown() method implements the first part of the process. It sets three necessary variables.

 def OnMousMove(self, sender, event):
  
     if self.isDragging: 
         sender.Top = sender.Top + (event.Y - self.oldY)
         sender.Left = sender.Left + (event.X - self.oldX)

In the OnMousMove() method, we relocate the button. We calculate the difference between the stored x, y coordinates and the new coordinates of the mouse pointer. The difference is added to the Top and Left properties of the button, thus moving it to a new position.


Dragging a button
Figure: Dragging a button

Dragging Text

In the previous example, we did drag & drop on the control. Next we will do a drag & drop operation on the textual data. Here we will use the drag & drop protocol provided by the Winforms library.

Drag & drop operation is a standardized communication protocol in Winforms. We have two basic objects. The drag source and the drop target.

dragtext.py
#!/usr/bin/ipy import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, Button from System.Windows.Forms import TextBox, DragDropEffects, DataFormats from System.Drawing import Size, Point class IForm(Form): def __init__(self): self.Text = 'Drag & Drop' self.AllowDrop = True button = Button() button.Parent = self textBox = TextBox() textBox.Parent = self button.AllowDrop = True button.Location = Point(150, 50) button.DragDrop += self.OnDragDrop button.DragEnter += self.OnDragEnter textBox.Location = Point(15, 50) textBox.MouseDown += self.OnMousDown self.ClientSize = Size(250, 200) self.CenterToScreen() def OnMousDown(self, sender, event): sender.SelectAll() sender.DoDragDrop(sender.Text, DragDropEffects.Copy) def OnDragEnter(self, sender, event): if event.Data.GetDataPresent(DataFormats.Text): event.Effect = DragDropEffects.Copy def OnDragDrop(self, sender, event): sender.Text = event.Data.GetData(DataFormats.Text) Application.Run(IForm())

We have two controls on the form. A button and a text box. We will drag text from the text box and drop it on the button.

 self.AllowDrop = True

We set the AllowDrop property to true. Dropping is not enabled by default.

 button.DragDrop += self.OnDragDrop
 button.DragEnter += self.OnDragEnter
 ...       
 extBox.MouseDown += self.OnMousDown

Again, the drag & drop process is divided into three steps. We have three methods for each particular step.

 def OnMousDown(self, sender, event):
     sender.SelectAll()
     sender.DoDragDrop(sender.Text, DragDropEffects.Copy)

In the OnMousDown() method we initialize the drap & drop process. We initiate the process with the DoDragDrop() method. The DragDropEffects.Copy parameter specifies the type of the operation. Esentially, we can either copy the text or move it during the drag & drop operation.

 def OnDragEnter(self, sender, event):
    
     if event.Data.GetDataPresent(DataFormats.Text):
         event.Effect = DragDropEffects.Copy

The DragEnter event is launched when the mouse pointer enters the area of the drop target control. The Effect property must be set. The DragDropEffects of the drag source and drop target must be equal. Otherwise the operation will not work.

 def OnDragDrop(self, sender, event):
     sender.Text =  event.Data.GetData(DataFormats.Text)

Finally we have the OnDragDrop() method. Here we get the data from the event object and set it to the button Text property.


Drag & drop of text
Figure: Drag & drop of text

Dragging Image

In our last example, we will drag & drop image on the form.

dragimage.py
#!/usr/bin/ipy import sys import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, PictureBox, PictureBoxSizeMode from System.Windows.Forms import Cursors from System.Drawing import Size, Point, Rectangle, Brushes, Bitmap class IForm(Form): def __init__(self): self.ClientSize = Size(350, 250) self.Text = "Dragging Images" self.Paint += self.OnPaint self.isDragging = False self.dropRect = Rectangle(10, 10, 200, 160) self.brush = Brushes.Gray picBox = PictureBox() self.loadImage() self.isDragging = False self.CenterToScreen() picBox.Parent = self picBox.Location = Point(100, 50) picBox.Size = Size(self.image.Width, self.image.Height) picBox.Image = self.image picBox.MouseDown += self.OnMousDown picBox.MouseUp += self.OnMousUp picBox.MouseMove += self.OnMousMove picBox.Cursor = Cursors.Hand def loadImage(self): try: self.image = Bitmap("image.jpg") except Exception, e: print "Error reading image" print e.msg sys.exit(1) def OnMousMove(self, sender, event): if self.isDragging: sender.Top = sender.Top + (event.Y - self.oldY) sender.Left = sender.Left + (event.X - self.oldX) def OnMousUp(self, sender, event): self.isDragging = False if self.dropRect.Contains(sender.Bounds): self.brush = Brushes.Gold else: self.brush = Brushes.Gray self.Refresh() def OnMousDown(self, sender, event): self.isDragging = True self.oldX = event.X self.oldY = event.Y def OnPaint(self, event): g = event.Graphics g.FillRectangle(self.brush, self.dropRect) Application.Run(IForm())

In our example we have a PictureBox and we draw a gray rectangle. If we drop the picture inside the rectangle, the color of the rectangle changes to gold.

 self.brush = Brushes.Gray

The self.brush variable holds the brush of the rectangle. It is a gray color by default.

 def loadImage(self):
     try:
         self.image = Bitmap("image.jpg")
     except Exception, e: 
         print "Error reading image"
         print e.msg
         sys.exit(1)

The loadImage() method loads a bitmap for the PictureBox control.

 if self.dropRect.Contains(sender.Bounds):
     self.brush = Brushes.Gold
 else: 
     self.brush = Brushes.Gray

In the OnMousUp() method, we determine the brush of the rectangle. If the bounds of the picture box are inside the rectangle, the brush is of gold color; gray otherwise.

 self.Refresh()

We must call the Refresh() method to activate the new brush color.


Drag & drop image
Figure: Drag & drop image

This chapter was dedicated to drag & drop operations using the Mono Winforms library.