المحتويات

السحب و الإفلات




سوف نتحدث فى هذه الجزئية من الدرس عن عمليات السحب و الإفلات.

فى التطبيقات الرسومية فعل السحب و الإفلات عبارة عن النقر على عنصر مرئى و سحبه لمكان آخر أو داخل عنصر مرئى آخر و عموماً يمكن استخدامه لفعل الكثير من الأشياء أو لإنشاء العديد من طرق الربط بين عناصر معينة (إقتباس من الموسوعة الحرة WikiPedia أنظر المقال الأصلى ).

عملية السحب و الإفلات من أكثر الجوانب المهمة فى واجهة المستخدم الرسومية و هى تتيح لك تركيب الأشياء حدسياً.

سحب و إفلات زر Dragging a button

فى المثال سوف نقوم بعمليات الإدراج و السحب على زر و لكن ليس باستخدام طرق السحب و الإدراج.

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

ربطنا ثلاثة عمليات للفأرة بالزر و قمنا بعمل ثلاثة مراحل لعملية السحب و الإفلات و تبدأ العملية عن النقر على الزر و تستقبلها الدالة OnMouseDown() و المرحلة الثانية هى تحريك الزر و هو عند ازاحته إلى موقع جديد و تسقبلها الدالة OnMouseMove() و المرحلة الأخيرة عند إيقاف العملية و تحدث عندما نحرر الإصبع من على الفأرة و تستقبلها الدالة OnMouseUp().

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

تنفذ الدالة OnMouseDown() المرحلة الأولى من عملية السحب و الإفلات و هى تضع القيمة لثلاثة متغيرات ضرورية.

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

فى الدالة OnMouseMove() نعيد تحديد مكان الزر فنحسب الفرق بين الإحداثبات س و ص القديمة و الجديدة لمؤشر الفأرة و الفرق سوف يضاف إلى كل من الخاصيتين Top و Left للزر و بنائاً على ذلك يتم تحريك الزر إلى الموقع الجديد.


Dragging a button

Figure: Dragging a button

سحب و إفلات نص Dragging Text

فى السابق تم تطبيق عمليات السحب و الإفلات على أداة أما فى هذا المثال فسو تكون على بيانات نصية و هنا سوف نستخدم الطرق المتاحة فى مكتبات WinForms للسحب و الإفلات.

عمليات السحب و الإفلات فى مكتبات WinForms تعتمد على طرق إتصال ثابته فهناك عنصرين أساسيين هما مصدر السحب drag source و الهدف المراد الإفلات عنده أو فيه 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())

هناك أداتين فى النافذة زر و صندوق نص و سوف نسحب النص من صندوق النصوص و نفلته فى الزر.

 self.AllowDrop = True

و هنا قمنا بتفعيل الخاصية AllowDrop لأن السحب غير مفعل إفتراضياً.

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

مرة ثانية عملية السحب و الإفلات قسمت إلى ثلاثة مراحل و لدينا دالة معينة لكل مرحلة.

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

فى الدالة OnMouseDown() بدأنا عملية السحب و الإفلات عن طريق الدالة DoDrageDrop() و الــDragDropEffects.Copyparameter يحدد نوع العملية و التى من خلالها يمكننا نسخ النص أو تحريكه خلال عملية السحب و الإفلات.

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

يبدأ الحدث DragEnter عندما مؤشر الفأرة فى دخول منطقة الهدف الذى سيتم الإفلات فيه أو عليه و لا بد من تحديد قيمة للخاصية Effect و هنا لا بد من تساوى تأثير السحب و الإفلات DragDropEffect و إلا لن تحدث العملية.

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

و أخيراً لدينا الدالة OnDragDrop() و فيها نأخذ البيانات من عنصر الحدث و نضعها خاصية Text للزر.


Drag & drop of text

Figure: Drag & drop of text

سحب و إفلات صورة Dragging Image

فى هذا المثال سوف نجرى عملية السحب و الإفلات على صورة داخل نافذة التطبيق.

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()) 

فى المثال هنا صندوق صورة PictureBox و لقد رسمنا مستطيل رمادى أيضاً و إذا قمنا بإفلات الصورة داخل المستطيل فسوف يتحول لونه إلى الذهبى.

 self.brush = Brushes.Gray

المتغير self.brush يحوى فرشاة المستطيل التى يتم تلوينه بها و هى إفتراضياً رمادية.

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

الدلة loadImage() تحمل صورة نقطية bitmap داخل صندوق الصورة.

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

فى الدالة OnMouseUp() نحدد إذا كانت حدود صندوق الصورة داخل المستطيل فيكون لون الفرشاة ذهبى و إذا كان عكس ذلك يكون رمادى.

 self.Refresh()

لا بد من استدعاء الدالة Refresh() حتى تنشط لون الفرشاة الجديد.


Drag & drop image

Figure: Drag & drop image

فى هذا الجزء من الدرس تم التعرض إلى عمليات السحب و الإفلات فى مكتبات Mono WinForms.


المحتويات