Drag&Drop

ListBox を使った Drag&Drop の基礎です。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. Drag&Drop を使うと、ウインドウからウインドウにマウスの操作で直接ファイルなどを転送することが出来ます。
    Copy&Paste や Drag&Drop は .NET のバージョンによって違いがあります。
    このプログラムは .NET Framework 2.0 以降に対応します。
    私がテストした実行環境は DLL(Dynamic Link Library) を参照して下さい。
    最も簡単な例題として、ListBox を使ったアイテムの Drag&Drop を紹介します。
  2. ListBox1 から ListBox2 にドラッグする DragDropBox2.cs の全ソースコードです。
    完成したプログラムなので Command Line から Windows プログラムを実行 でもOKです。
    /******************************************************/
    /*★ ListBox1 → ListBox2 ドラッグします    前田 稔 ★*/
    /******************************************************/
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    public class MyForm : Form
    {
        private ListBox listBox1;
        private ListBox listBox2;
        static string[] str1 =  { "りんご", "バナナ", "いちご" };
        static string[] str2 =  { "にんじん", "ごぼう", "レタス" };
    
        public MyForm()
        {
            InitializeComponent();
            Load += new System.EventHandler(MyForm_Load);
        }
    
        private void InitializeComponent()
        {
            this.listBox1 = new System.Windows.Forms.ListBox();
            this.listBox2 = new System.Windows.Forms.ListBox();
            this.SuspendLayout();
            // listBox1
            this.listBox1.AllowDrop = true;
            this.listBox1.FormattingEnabled = true;
            this.listBox1.ItemHeight = 18;
            this.listBox1.Location = new System.Drawing.Point(2, 2);
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(175, 112);
            this.listBox1.TabIndex = 0;
            this.listBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ListBox1_MouseDown);
            // listBox2
            this.listBox2.AllowDrop = true;
            this.listBox2.FormattingEnabled = true;
            this.listBox2.ItemHeight = 18;
            this.listBox2.Location = new System.Drawing.Point(183, 2);
            this.listBox2.Name = "listBox2";
            this.listBox2.Size = new System.Drawing.Size(174, 112);
            this.listBox2.TabIndex = 1;
            this.listBox2.DragDrop += new System.Windows.Forms.DragEventHandler(this.ListBox2_DragDrop);
            this.listBox2.DragEnter += new System.Windows.Forms.DragEventHandler(this.ListBox2_DragEnter);
            // MyForm
            this.ClientSize = new System.Drawing.Size(361, 116);
            this.Controls.Add(this.listBox2);
            this.Controls.Add(this.listBox1);
            this.Name = "MyForm";
            this.ResumeLayout(false);
        }
    
        private void MyForm_Load(object sender, System.EventArgs e)
        {
            for (int i = 0; i < str1.GetLength(0); i++)
            {   listBox1.Items.Add(str1[i]);  }
            for (int i = 0; i < str2.GetLength(0); i++)
            {   listBox2.Items.Add(str2[i]);  }
        }
    
        private void ListBox1_MouseDown(object sender, MouseEventArgs e)
        {   if (e.Button == MouseButtons.Left)  //マウスの左ボタン
            {
                //ドラッグの準備
                ListBox lbx = (ListBox) sender;
                //ドラッグするアイテムのインデックスを取得する
                int itemIndex = lbx.IndexFromPoint(e.X, e.Y);
                if (itemIndex < 0) return;
                //ドラッグするアイテムの内容を取得する
                string itemText = (string) lbx.Items[itemIndex];
                //ドラッグ&ドロップ処理を開始する
                DragDropEffects dde = lbx.DoDragDrop(itemText, DragDropEffects.All);
            }
        }
    
        private void ListBox2_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;    //マウスの形状が変わる
        }
    
        private void ListBox2_DragDrop(object sender, DragEventArgs e)
        {
            string str = e.Data.GetData(DataFormats.Text).ToString();
            listBox2.Items.Add(str);    //受け取った Item を追加
        }
    }
    
    class form01
    {
        [STAThread]
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    }
    
  3. ListBox1 と ListBox2 を左右に並べて、Box1 から Box2 に Drag&Drop します。
    ページ先頭の画像を参照して下さい。
    str1 が ListBox1 の、str2 が ListBox2 に表示するデータです。
        static string[] str1 =  { "りんご", "バナナ", "いちご" };
        static string[] str2 =  { "にんじん", "ごぼう", "レタス" };
        
  4. Drag&Drop の送り側(ListBox1)の設定です。
    AllowDrop を true にします。
    MouseDown に Drag を開始するメソッドを設定します。
            this.listBox1.AllowDrop = true;
            this.listBox1.MouseDown +=
                new System.Windows.Forms.MouseEventHandler(this.ListBox1_MouseDown);
        
  5. Drag を開始するメソッド(ListBox1_MouseDown)です。
    マウスの左ボタンが押されているとき、その座標からアイテム番号を計算して itemText を取得します。
    lbx.DoDragDrop() で Drag を開始します。
        private void ListBox1_MouseDown(object sender, MouseEventArgs e)
        {   if (e.Button == MouseButtons.Left)  //マウスの左ボタン
            {
                //ドラッグの準備
                ListBox lbx = (ListBox) sender;
                //ドラッグするアイテムのインデックスを取得する
                int itemIndex = lbx.IndexFromPoint(e.X, e.Y);
                if (itemIndex < 0) return;
                //ドラッグするアイテムの内容を取得する
                string itemText = (string) lbx.Items[itemIndex];
                //ドラッグ&ドロップ処理を開始する
                DragDropEffects dde = lbx.DoDragDrop(itemText, DragDropEffects.All);
            }
        }
        
  6. Drag&Drop の受取側(ListBox2)の設定です。
    AllowDrop を true にします。
    DragEnter に Drop の開始メソッドを設定します。
    DragDrop に Drop されたデータを受け取って処理するメソッドを設定します。
            // listBox2
            this.listBox2.AllowDrop = true;
            this.listBox2.DragEnter +=
                new System.Windows.Forms.DragEventHandler(this.ListBox2_DragEnter);
            this.listBox2.DragDrop +=
                new System.Windows.Forms.DragEventHandler(this.ListBox2_DragDrop);
        
  7. Drop の開始メソッド(ListBox2_DragEnter)です。
    e.Effect = DragDropEffects.Copy; でマウスの形状が Drag&Drop 用に変わります。
        private void ListBox2_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;    //マウスの形状が変わる
        }
        
  8. Drop されたデータを受け取って処理するメソッド(ListBox2_DragDrop)です。
    渡されたデータを string str で受け取って、listBox2 にアイテムを追加します。
        private void ListBox2_DragDrop(object sender, DragEventArgs e)
        {
            string str = e.Data.GetData(DataFormats.Text).ToString();
            listBox2.Items.Add(str);    //受け取った Item を追加
        }
        

プログラムを分ける

  1. 一般的に Drag 側(送り側)と Drop 側(受取側)は、別のプログラムになります。
    今度は、Drag 側のプログラムと、Drop 側のプログラムを同時に起動してテストします。
    次のプログラムは Drag と Drop の両方の機能を備えているので、相互に Drag&Drop することが出来ます。
    /************************************************/
    /*★ 両方の機能を設定した ListBox     前田 稔 ★*/
    /************************************************/
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    public class MyForm : Form
    {
        private ListBox listBox1;
        private Point   mouseDownPoint = Point.Empty;
        static string[] str1 =  { "りんご", "バナナ", "いちご" };
    
        public MyForm()
        {
            InitializeComponent();
            Load += new System.EventHandler(MyForm_Load);
        }
    
        private void InitializeComponent()
        {
            this.listBox1 = new System.Windows.Forms.ListBox();
            this.SuspendLayout();
            // listBox1
            this.listBox1.FormattingEnabled = true;
            this.listBox1.ItemHeight = 18;
            this.listBox1.Location = new System.Drawing.Point(12, 12);
            this.listBox1.Name = "listBox1";
            this.listBox1.Size = new System.Drawing.Size(147, 130);
            this.listBox1.TabIndex = 0;
            this.listBox1.AllowDrop = true;
            this.listBox1.MouseDown += new MouseEventHandler(this.ListBox1_MouseDown);
            this.listBox1.MouseMove += new MouseEventHandler(this.ListBox1_MouseMove);
            this.listBox1.MouseUp += new MouseEventHandler(this.ListBox1_MouseUp);
            this.listBox1.QueryContinueDrag +=
                new QueryContinueDragEventHandler(ListBox1_QueryContinueDrag);
            this.listBox1.DragDrop += new DragEventHandler(this.ListBox1_DragDrop);
            this.listBox1.DragEnter += new DragEventHandler(this.ListBox1_DragEnter);
    
            // MyForm
            this.ClientSize = new System.Drawing.Size(176, 155);
            this.Controls.Add(this.listBox1);
            this.Name = "MyForm";
            this.ResumeLayout(false);
    
        }
    
        private void MyForm_Load(object sender, System.EventArgs e)
        {
            for (int i = 0; i < str1.GetLength(0); i++)
            {   listBox1.Items.Add(str1[i]);  }
        }
    
        private void ListBox1_MouseDown(object sender, MouseEventArgs e)
        {   if (e.Button == MouseButtons.Left)
            {
                ListBox lbx = (ListBox) sender;
                if (lbx.IndexFromPoint(e.X,e.Y)>=0) mouseDownPoint = new Point(e.X, e.Y);
            }
            else    mouseDownPoint = Point.Empty;
        }
    
        private void ListBox1_MouseUp(object sender, MouseEventArgs e)
        {
            mouseDownPoint = Point.Empty;
        }
    
        private void ListBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (mouseDownPoint != Point.Empty)
            {
                //ドラッグとしないマウスの移動範囲を取得する
                Rectangle moveRect = new Rectangle(
                    mouseDownPoint.X - SystemInformation.DragSize.Width / 2,
                    mouseDownPoint.Y - SystemInformation.DragSize.Height / 2,
                    SystemInformation.DragSize.Width,
                    SystemInformation.DragSize.Height);
                //ドラッグとする移動範囲を超えたか調べる
                if (!moveRect.Contains(e.X, e.Y))
                {
                    //ドラッグの準備
                    ListBox lbx = (ListBox) sender;
                    //ドラッグするアイテムのインデックスを取得する
                    int itemIndex = lbx.IndexFromPoint(mouseDownPoint);
                    if (itemIndex < 0) return;
                    //ドラッグするアイテムの内容を取得する
                    string itemText = (string) lbx.Items[itemIndex];
    
                    //ドラッグ&ドロップ処理を開始する
                    DragDropEffects dde = lbx.DoDragDrop(itemText, 
                        DragDropEffects.All | DragDropEffects.Link);
    
                    //ドロップ効果がMoveの時はもとのアイテムを削除する
                    if (dde == DragDropEffects.Move)
                        lbx.Items.RemoveAt(itemIndex);
    
                    mouseDownPoint = Point.Empty;
                }
            }
        }
    
        //ドラッグをキャンセルする
        private void ListBox1_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            //マウスの右ボタンが押されていればドラッグをキャンセル("2"はマウスの右ボタン)
            if ((e.KeyState & 2) == 2)  e.Action = DragAction.Cancel;
        }
    
        private void ListBox1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;    //マウスの形状が変わる
        }
    
        private void ListBox1_DragDrop(object sender, DragEventArgs e)
        {
            string str = e.Data.GetData(DataFormats.Text).ToString();
            listBox1.Items.Add(str);
        }
    }
    
    class form01
    {
        [STAThread]
        public static void Main()
        {
            MyForm mf = new MyForm();
            Application.Run(mf);
        }
    }
    
  2. ListBox1 に先の例のように Drag 側のメソッドと Drop 側のメソッドをそのまま記述しても動くのですが、 それでは ListBox1 でアイテムをクリックするだけで、自分自身にアイテムがコピー(Drag&Drop)されてしまいます。
    そこで左クリックされたマウスがある距離移動するのを待ってドラッグを開始します。
  3. ListBox1_MouseDown では、クリックされた座標を mouseDownPoint に保存するだけです。
        private void ListBox1_MouseDown(object sender, MouseEventArgs e)
        {   if (e.Button == MouseButtons.Left)
            {
                ListBox lbx = (ListBox) sender;
                if (lbx.IndexFromPoint(e.X,e.Y)>=0) mouseDownPoint = new Point(e.X, e.Y);
            }
            else    mouseDownPoint = Point.Empty;
        }
        
  4. ListBox1_MouseMove で移動距離を調べてドラッグを開始します。
        private void ListBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (mouseDownPoint != Point.Empty)
            {
                //ドラッグとしないマウスの移動範囲を取得する
                    ・・・
                //ドラッグとする移動範囲を超えたか調べる
                if (!moveRect.Contains(e.X, e.Y))
                {   //ドラッグの準備
                        ・・・
                    //ドラッグ&ドロップ処理を開始する
                        ・・・
                }
            }
        }
        
  5. ListBox1_DragEnter() と ListBox1_DragDrop() は前回と同じです。
    このプログラムを二個同時に起動して下さい。
    相互にドラッグ&ドロップすることが出来ます。

超初心者のプログラム入門(C# Frame Work)