[C#] 拖拉 Windows Form 的 Component

最近有需要想將 Windows Form 上的元件(例如 Label、Button)隨使用者自由拖拉,雖然事件都有 Drag 相關的可以使用,但查了一下似乎不是我想要的,這些 DragDrop()、DrapOver() 事件還有 AllowDrop 屬性好像是拖拉資料,並不是拖拉元件,只好手動用 MouseDown()、MouseMove()、MouseUp() 事件來組合。首先如下兩圖,先設置了一個 Label 叫 label1,有設定背景色和 AutoSize = false,左圖是本來的位置,右圖是用滑鼠左鍵拖拉後的結果:

這些滑鼠事件的參數 MouseEventArgs e 有 X 和 Y 兩個屬性,是滑鼠相對於元件的坐標,不是相對整個表單,也不是相對整個螢幕,例如:

其實相對於什麼倒也不是這麼重要,只要得到位移向量,就能找出後來元件新的位置為何,如下圖,首先要兩個點:P 為最開始點擊 MouseDown() 事件時的定點,而 Q 為 MouseMove() 過程任何時候的動點,然後用PQ連出的向量 t,加上原來物件相對於整個表單的坐標向量 u,就得到物件新的位置的坐標向量 v:

P 點就是 MouseMove() 事件中要先取到的 clickPoint,而 Q 點是 MouseMove() 事件中不停變動的 ( e.X , e.Y ),向量 t 為 ( e.X - clickPoint.X , e.Y - clickPoint.Y ),這個向量 t 再加上之前物件 Location 就得新的 Location ,也就是 ( Location.X + e.X - clickPoint.X , Location.Y + e.Y - clickPoint.Y ),參考程式碼如下:

namespace DragComponentDemo
{
  public partial class Form1 : Form
  {
    bool isDraging = false;
    Point clickPoint;

    public Form1()
    {
      InitializeComponent();
    }

    private void label1_MouseDown(object sender, MouseEventArgs e)
    {
      isDraging = true;                     // 當按下滑鼠按鍵(左右鍵皆可),開始拖拉模式
      clickPoint = new Point(e.X, e.Y);     // 記下最初按鍵點選的坐標
    }

    private void label1_MouseMove(object sender, MouseEventArgs e)
    {
      if (isDraging)
      {
        Label obj = (Label)sender;
        obj.Location = new Point(
            obj.Location.X + e.X - clickPoint.X,    //將此物件(Label)的坐標重設
            obj.Location.Y + e.Y - clickPoint.Y);
      }
    }

    private void label1_MouseUp(object sender, MouseEventArgs e)
    {
      isDraging = false;                         // 放開滑鼠按鍵則離開拖拉模式
    }
  }
}

留言