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.
#!/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 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 standardised communication protocol in Winforms. We have two basic objects. The drag source and the drop target.
#!/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.
Dragging Image
In our last example, we will drag & drop image on the form.
#!/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 colour of the rectangle changes to gold.
self.brush = Brushes.Gray
The self.brush variable holds the brush of the rectangle.
It is a gray colour 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 colour; gray otherwise.
self.Refresh()
We must call the Refresh() method to activate the new brush colour.
This chapter was dedicated to drag & drop operations using the Mono Winforms library.