Visual Basic 初級講座
VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

 

Visual Basic 中学校 > 初級講座 >

第22回 ドラッグ&ドロップ

マウスの操作で文字や画像・ファイルといったデータを操作する「ドラッグ&ドロップ」は快適な操作にはかかせない動作です。今回はこのドラッグ&ドロップの基本について解説します。

この回の要約

・コントロールにドロップできるようにするには

  • AllowDropプロパティをTrueにして
  • DragEnterイベントでe.Effect = DragDropEffects.Copyとして
  • DragDropイベントで e.Data.GetDataをつかってデータを受け取る。

・ドラッグするにはDoDragDropメソッドを使う

・ファイルのドラッグ&ドロップではファイルはあらかじめ存在していなければならず、ドラッグデータとしては必ず「ファイル名の配列」を使用する。

・コントロールをマウスでドラッグして移動する方法

 

1.使いやすいソフトを作る

 

あなたが作ったアプリケーションを他人に使ってもらおうとするなら使いやすいようにプログラムしなければなりません。どうすれば使いやすいか考えるとなかなか難しいものがあるのですが、誰でも賛成できる点として「他のアプリケーションと同じ感覚で操作できること」が挙げられるでしょう。

たとえば、Wordの操作に慣れている人ならメモ帳は初めてでもすらすら使えます。もし、その人が音楽作成ソフトCubaseをはじめて使ったとすると使い方がほとんどわからないでしょうが、ファイルを開いたり保存したりするためには[ファイル]メニューを使えばよいと言うことはすぐにわかります。これは驚くべきことではありませんか?まったく初めてのソフト、初めてのジャンルなのに操作方法がすぐにわかるのですよ!

このように、「他のアプリケーションと同じ感覚」ということはとても重要です。あなたのアプリケーションは独自の操作方法を採用していませんか?それがよほど画期的で優れていると言う自信がない限り、独自の操作方法はあきらめて他のアプリケーションと同じ操作方法を採用しましょう。たとえば、ファイルを開くときには[ファイル]メニューを使うか、ツールバーのアイコンを使うようにしましょう。

さて、多くの市販のアプリケーションが実装しているのに、多くのVBプログラマが無視している操作方法があります。それが今回のテーマ「ドラッグ&ドロップ」です。

みなさんのソフトにもドラッグ&ドロップを実装して親切で使いやすいソフトを目指しましょう。

 

参考  VB6との違い

ドラッグ&ドロップの構造的な仕組みについてはVB6からVB2005まで同じですが、その手法となるとVB.NET2002の時点で大きく変更されました。

特にVB6の場合は同じアプリケーション内のドラッグ&ドロップと、他のアプリケーションとの間で行うOLEドラッグ&ドロップが明確に区別されていましたが、VB.NET2002以降ではこれらは同じ手法で扱うようになりました。

 

2.ドロップの基本

 

では、簡単な「ドロップ」の方から説明しましょう。ドロップはドラッグされてきたものを受け入れる動作です。

今回はフォームにテキストボックスを1つ配置して、外部のアプリケーションからこのテキストボックスへのドラッグ&ドロップを実現させます。「外部のアプリケーション」はドラッグ&ドロップ対応のアプリケーションなら何でも良いのですが、ここではWindowsに付属しているワードパッドを例にとって説明します。

プログラムを紹介する前にドロップの流れについて簡単に説明します。

何かがドラッグされてくると、コントロールのDragEnterイベント(読み方:DragEnter = ドラッグエンター)が発生します。DragEnterイベントでは、このコントロールがどのようなドロップを受け入れるのかをドラッグ元に通知しなければなりません。ここで通知をしないとドラッグ元は「ここにはドロップできない」と判断してしまいます。また、ここでの通知はドロップされた際のドラッグ元の反応にも影響を与えます。

いよいよマウスボタンが離されると、今度はDragDropイベント(読み方:DragDrop = ドラッグドロップ)が発生します。ここではドラッグされたデータを受け取って具体的にどのようなことをするのかプログラムします。プログラムは何でも書けますので予想外の動作を行わせることもできますが、通常はドラッグされてきたデータを表示したりします。

なお、ドロップ対象となるコントロールは、AllowDorpプロパティ(読み方:AllowDrop = アロゥドロップ)をTrueにしておかなければなりません。いくらプログラムしてもAllowDropプロパティがFalseではドラッグドロップを受け入れることができないので注意してください。

以上の一連の流れを具体的にプログラムすると次のようになります。AllowDropプロパティはプロパティウィンドウを使ってあらかじめTrueにしておいてください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub TextBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragEnter

    'ドラッグされている内容が文字列型に変換可能な場合
   
If e.Data.GetDataPresent(GetType(String)) Then
       
'コピーを許可するようにドラッグ元に通知する
       
e.Effect = DragDropEffects.Copy
    End
If

End Sub

Private Sub TextBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragDrop

    'ドロップされた内容を表示する
   
TextBox1.Text = e.Data.GetData(GetType(String))

End Sub

■リスト1:単純なテキストのドロップ

これで、ワードパッドからこのテキストボックスに文字列をドラッグしてコピーすることができるようになりました。試すにはワードパッドに何か入力してから何文字か選択して、その選択部分をテキストボックスまでマウスでドラッグしてください。

ドラッグ&ドロップの具体的なデータや効果・マウス・キーボードの状態の管理にはDragEventArgs(読み方:DragEventArgs = ドラッグイベントオーグス)を使います。

DragEventArgsはドラッグ&ドロップ関連のイベントの第2引数となっていて、次の処理を行うことができます。

処理 説明
データ Dataプロパティを使ってドラッグ&ドロップに関連付けられたデータの操作・情報の取得を行うことができます。
キーボード・マウスのボタン KeyStateプロパティを使うと、キーボードの[Ctrl]キー、[Alt]キー、[Shift]キーの状態や、マウスのボタンの状態を取得することができます。
マウスの位置 Xプロパティ、Yプロパティでマウスの座標がわかります。
ドラッグ&ドロップ効果 EffectプロパティとAllowedEffectプロパティでドラッグ&ドロッププロパティの挙動を設定・取得できます。

■表1:DragEventArgesの機能

今回の例でもDragEnterイベントではコピーを許可するために、e.Effect = DragDropEffects.Copyとしています。ただし、テキストボックスですから文字列以外のもののコピーを許可するわけには行きません。そこでコピーを許可する前にドラッグされているデータが文字列に変換可能かどうか調べています。これはGetDataPresentメソッド(読み方:GetDataPresent = ゲットデータプレゼント)を使えば簡単にできます。

DragDropイベントでは既に文字列に変換可能なことがチェック済みなので安心してチェックなしで文字列としてデータを受け取れます。これにはGetDataメソッド(読み方:GetData = ゲットデータ)を使います。

GetDataPresentGetDataDataObject(読み方:DataObject = データオブジェクト)のメンバですが、このDataObjectにはイベントプロシージャの引数e(つまり、DragEventArgs)のDataプロパティを使ってアクセスできるようになっています。DataObjectにはこのほかにもドラッグ&ドロップのデータを制御するためにいくつかのメンバがあります。

なお、DragEnterイベント内で、コピーを許可している部分を移動を許可に変更するとドロップされたときにドラッグ元の文字列が削除されます。移動許可にするにはe.Effect = ... の行を次のように書き換えます。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応


e.Effect = DragDropEffects.Move
 

■リスト2

 

3.ファイルのドロップ

 

次にもう少し複雑で役に立つ例としてファイルのドロップを紹介します。

まずは、ドロップされたファイル名をテキストボックスに表示するようにプログラムしてみます。といっても最初の例とさほど変わりはありません。最初の例で文字列に変換可能かどうか調べていたところを、ファイルかどうか調べるように修正して、DragDropイベントのデータの表示の仕方をちょっとだけ変えるだけです。

次のようになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub TextBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragEnter

    'ドラッグされている内容が文字列型に変換可能な場合
   
If e.Data.GetDataPresent(DataFormats.FileDrop) Then
       
'コピーを許可するようにドラッグ元に通知する
       
e.Effect = DragDropEffects.Copy
    End
If

End Sub

Private Sub TextBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragDrop

    'ドロップされた内容を表示する
   
TextBox1.Text = e.Data.GetData(DataFormats.FileDrop)(0)

End Sub

■リスト3:ファイルがドロップされるとそのファイル名を表示する

先ほどの例からの変更箇所を説明します。まず、DragEnterイベントでのGetDataPresentメソッドの引数が変わりました。はじめの例ではGetType(String)となっていたのが、ここでは、DataFormats.FileDropとなっています。これは、はじめの例が「String型に変換可能かどうか」調べていたのに対し、今回は「ファイルかどうか」を調べているからです。このようにGetDataPresentは柔軟な引数と取ることができます。

.NET Framework( = VB)の型に変換できるか調べたい場合は GetType(String) のように書くことができますし、それとは別にドラッグ内容のデータを表すDataFormats列挙体(読み方:DataFormats = データフォーマッツ)を使うこともできます。(列挙体とは何かについて種類がある場合の各種類を見分けるために使うVBの手法です。)

ところで、このプログラムは最終的にはファイル名を表示するのですから文字列に変換できそうにも思えますが、あくまで「ファイルがドロップされている」という判定になりますので、e.Data.GetDataPresent(GetType(String))と記述するとFalseが返ります。

もう一箇所の変更点はDragDropイベントですが、ここではドロップされた「物」をファイルとして受け取るように、やはりDataFormats.FileDropを指定します。ファイルとして受け取った場合、具体的な扱いとしては文字列の配列になります。(配列については今後初級講座で詳しく取り上げる予定です)。

なぜ、単純な文字列にならないかというと複数のファイルをまとめてドロップする場合があるからです。ここでは、はじめの1つめのファイルだけを対象とするので (0) を指定します。

なお、2番目のファイルを対象とする場合は (1) 、3番目なら (2) のように記述します。

 

4.ドロップされたファイルを開く

 

ドロップの最後にドロップされたファイルを開く例を紹介します。「ファイルを開く」という動作に関してはドラッグ&ドロップとは直接関係ありませんし、また今後初級講座で詳しく取り上げる予定ですが、やはりファイルがドロップされたらそのファイルを処理するところまでプログラムで書きたくなると思いますのでここでも簡単に紹介します。

まず、ドロップされたテキストファイルを開くには次のようにします。この場合、テキストボックスのプロパティはあらかじめ次のように設定しておいてください。

プロパティ 説明
AllowDrop True ドロップを受け入れる。
MultiLine True 複数行表示できるようにする。
ScrollBars Both 縦横両方向のスクロールバーを使用する。
WordWrap False 自動的に改行しない。

■表2

具体的なコードは先ほどの例をほとんど同じです。DragDropイベントだけ次のように書き換えてください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub TextBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox1.DragDrop

    Dim FileName As String
   
Dim Reader As IO.StreamReader

    FileName = e.Data.GetData(DataFormats.FileDrop)(0)

    Reader = New IO.StreamReader(FileName, System.Text.Encoding.GetEncoding("Shift-JIS"))

    TextBox1.Text = Reader.ReadToEnd

    Reader.Close()

End Sub

■リスト4:ドロップされたテキストファイルの内容を表示する。

 

今度は画像がファイルがドロップされたらその画像を表示するようにします。

この場合のプログラムもほとんど前のと同じですが、ここでは全体を紹介します。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    PictureBox1.AllowDrop = True

End Sub

Private Sub PictureBox1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles PictureBox1.DragEnter

    If e.Data.GetDataPresent(DataFormats.FileDrop) Then
       
e.Effect = DragDropEffects.Copy
    End
If

End Sub

Private Sub PictureBox1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles PictureBox1.DragDrop

    Dim FileName As String

    FileName = e.Data.GetData(DataFormats.FileDrop)(0)

    PictureBox1.Image = Image.FromFile(FileName)

End Sub

■リスト5:ドロップされた画像ファイルを表示する

ちょっとだけドラッグ&ドロップがらみでポイントになるのはフォームのLoadイベントでPictureBox1AllowDropプロパティをTrueにしている点です。なぜかピクチャーボックスのAllowDropプロパティはプロパティウィンドウでは変更できないので仕方なくコードで変更しています。

このようにプロパティウィンドウからはできなくてもプログラムでできることはいろいろあります。

 

5.ドラッグ

 

今度はドラッグを説明します。ドロップに比べてドラッグが活躍するシーンはそれほど多くありません。

まずは、単純にテキストボックスの文字列をワードパッドにドラッグドロップでコピーしてみます。

このくらいのドラッグなら簡単です。ドラッグを開始するためにDoDragDropメソッド(読み方:DoDragDrop = ドゥードラッグドロップ)を呼び出すだけです。ただ、どのタイミングでドラッグを開始するのかが悩ましいのですが今回は単純にMouseDownイベントでドラッグを開始することにします。MouseDownイベントでドラッグを開始すると、マウスで文字列が選択できなくなるなど好ましくない現象が発生しますので実用化するときは要注意です。

プログラムは次のようになります。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown

    TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)

End Sub

■リスト6:単純なテキストのドラッグ

これだけで、テキストボックスから他のドラッグ&ドロップ対応アプリケーションへドロップができます。当然、VBのテキストボックス間でのドラッグ&ドロップもできます。

 

6.ドロップしてファイルに保存する

 

今度はテキストボックスからデスクトップやフォルダにドロップして、テキストをファイルとして保存する例を紹介します。

このところちょっとばかり癖があるのですが、まずはプログラムから見てください。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown

    Dim Data As New DataObject
    Dim FileName As
String
   
Dim Writer As IO.StreamWriter

    '▼ファイル作成

    FileName = Application.StartupPath & "\TextBox1.txt"
    Writer = New IO.StreamWriter(FileName)
    Writer.Write(TextBox1.Text)
    Writer.Close()

    '▼ファイルをドラッグデータとしてセット

    Data.SetData(DataFormats.FileDrop, New String() {FileName})

    '▼ドラッグ開始

    TextBox1.DoDragDrop(Data, DragDropEffects.Copy)

End Sub

■リスト7:ドラッグドロップしてファイルに保存する

だんだん、プログラムも長くなってきました。私はどうも嫌なのですが、どうやらファイルとしてドラッグするときはドラッグを開始する時点でファイルが存在していないとダメなようなのです。普通の発想ではドロップが完了した時点で、「ドロップ完了」のようなイベントが発生して、 そのイベントの中でファイルを書き込む…のような流れだと思うのですが、違うのです。

そのため、このサンプルでもDoDragDropは一番最後で、ファイルを作るのが最初です。そのファイルもドラッグ開始の前に作成しますから、とりあえず適当な場所に作成するしかありません。ここではexeファイルと同じ場所にTextBox1.txtという名前でとりあえずファイルを作成しています。

その後の流れは初級講座の現段階では理解しなくても構わないと思いますが、一応ざっと触れておきます。まず作成したファイルをドラッグデータとしてセットするところなのですが、単なる文字列の場合と違って一旦DataObjectに設定して、その後でそのDataObjectDoDragDropメソッドの引数に指定すると言う手順を踏まなければなりません。そして、DataObjectにデータをセットするときに、ファイルは常に文字列型の配列としてセットしなければならないので、New String() {FileName} のようなちょっと妙な指定方法となります。

 

7.コントロールのドラッグ

 

時にはラベルやピクチャーボックスなどコントロールをマウスのドラッグにより移動できるようにしたい場合があるかもしれません。

特にピクチャーボックスには画像を表示できるわけですからアイディアしだいでさまざまな視覚効果のあるドラッグを実現できます。たとえば、WordやExcelではオートシェイプと呼ばれる図形をマウスでドラッグして位置を調節することができますが、ちょうどそんなものを想像していただければ結構です。

このようなコントロールのドラッグ&ドロップですが、実はいままでのドラッグ&ドロップの仕組みは使わないでマウス系のイベントを使って自分ですべてを管理するのが良いです。

次の例ではフォーム上でボタン(Button1)をドラッグして、自由に位置を変えられます。

VB.NET 2002 対応 VB.NET 2003 対応 VB2005 対応

Dim IsDragging As Boolean 'ドラッグ中の場合True
Dim DiffPoint As Point
'ドラッグ開始地点とドラッグ開始時のボタンの位置とのずれ

Private Sub Button1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseDown

    If e.Button = MouseButtons.Left Then
       
IsDragging = True
       
DiffPoint = New Point(e.X, e.Y)
    End
If

End Sub

Private Sub Button1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseUp

    If e.Button = MouseButtons.Left Then
       
IsDragging = False
   
End If

End Sub

Private Sub Button1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseMove

    If IsDragging Then

        Dim DestX As Integer = Button1.Location.X + e.X - DiffPoint.X
        Dim DestY As Integer = Button1.Location.Y + e.Y - DiffPoint.Y

        Button1.Location = New Point(DestX, DestY)

    End If

End Sub

■リスト8:ドラッグしてコントロールの位置を変更する。

少し長いコードに感じられるかもしれませんが、前回のマウス系のイベントの知識があれば特にこれといったポイントはありません。あげるとすれば、MouseMoveイベントでのButton1の位置の移動です。

ボタンの位置の指定にはLocationプロパティ(読み方:Location = ロケーション)を使用しています。Locationプロパティには新しい位置を表すPoint構造体(読み方:Point = ポイント)をセットするだけなのですが、Locationプロパティは正確にはコントロールの左上の座標を表しているため、この新しい位置を算出するときに次の3つの座標を考慮に入れる必要があります。

  意味上の座標 プログラム上の座標 備考
A 現在のボタンの左上の座標 Button1.Location  
B 現在のマウスの座標 e.x , e.y この座標はボタンの左上の座標を(0, 0)としたときの相対的な座標です。
C ドラッグを開始したときのマウスの座標 DiffPoint この座標もボタンの左上の座標を(0, 0)としたときの相対的な座標です。

■表3:考慮すべき2つの座標

この3つを考慮に入れると、新しい座標は A + B - C となります。このあたりを図入りでもっと丁寧に解説することも考えたのですが今回のテーマからははずれてきてしまうし、とりたてて応用があるわけでもないので結論だけ載せます。

なお、VB2005ならばMouseMoveイベントの中は次のように書くこともできます。

VB2005 対応

Private Sub Button1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseMove

    If IsDragging Then

        Dim Dest As Point

        Dest = Button1.Location + New Size(e.X, e.Y) - New Size(DiffPoint)

        Button1.Location = Dest

    End If

End Sub

■リスト9:VB2005ではPoint構造体とSize構造体を直接演算できる。

 

8.さらに高度なドラッグ&ドロップのために

 

ドラッグとドロップの基本の説明は以上です。VBにはさらに高度なドラッグ&ドロップを実現するために今回は紹介しなかった仕組みやメソッド、プロパティが用意されています。たとえば、ドラッグ中に発生するGiveFeedBackイベント(読み方:GiveFeedBack = ギブフィードバック)は今回は紹介しませんでしたが、ドラッグ中にもっとこった視覚効果を適用することができます。

他にも画像のドラッグや、独自のデータのドラッグなどいろいろあります。ただ、こういったトピックを扱っていくと明らかに初級講座の範囲を逸脱してしまいます。興味のある方は調べてみてください。