テキストのドラッグ&ドロップによるムーブ への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/9/10 06:21:37
> 他のアプリ(たとえばワードパッド)にMoveしようといたしますと、
> 勝手にCopyになってしまう点です。
それはワードパッド側の仕様です。
他のアプリへのドロップ時の動作は、VB からは制御できません。
VB から指定できるのは、DoDragDrop の引数である データ(data As Object)と、
使用可能な動作(allowedEffects As DragDropEffects)のみです。
ワードパッドの場合、ドラッグ元とドロップ先が、それぞれ同一アプリ上の内であれば、
「そのままでは Move」「Ctrl 押下で Copy」という動作モードになるのですが、
ワードパッドを 2 つ起動して、その間で文字列をドラッグしようとした場合、
「そのままでは Copy」「Alt 押下で Move」という動作になっています。
そして、VB からドロップした場合というのは、後者の状態にあたりますから、
Alt を押さない限りは、Move 扱いにならないのです。
ただしこれは、DoDragDrop に渡す DragDropEffects を
Move のみを指定した場合には、ワードパッドは「常に Move」として処理されますし、
Copy のみを指定した場合には、ワードパッドは「常に Copy」として処理されます。
これはドロップ先は、allowedEffects で許可されている動作モードのみが
利用可能であるからです。(allowedEffects を無視するアプリもありますが…)
# DragDropEffects には、他にも Scroll や Link など幾つかのモードがありますが、
# それらをドロップ先のアプリがどのように処理するかは、ドロップ先が決める事であって、
# ドラッグ元である VB 側は一切関与する必要がありませんし、関与すべきではありません。
> 勝手にCopyになってしまう点です。
それはワードパッド側の仕様です。
他のアプリへのドロップ時の動作は、VB からは制御できません。
VB から指定できるのは、DoDragDrop の引数である データ(data As Object)と、
使用可能な動作(allowedEffects As DragDropEffects)のみです。
ワードパッドの場合、ドラッグ元とドロップ先が、それぞれ同一アプリ上の内であれば、
「そのままでは Move」「Ctrl 押下で Copy」という動作モードになるのですが、
ワードパッドを 2 つ起動して、その間で文字列をドラッグしようとした場合、
「そのままでは Copy」「Alt 押下で Move」という動作になっています。
そして、VB からドロップした場合というのは、後者の状態にあたりますから、
Alt を押さない限りは、Move 扱いにならないのです。
ただしこれは、DoDragDrop に渡す DragDropEffects を
'コピーと移動を許可する
Dim effect As DragDropEffects
effect = DragDropEffects.Copy Or DragDropEffects.Move
にしていた場合の話です。Move のみを指定した場合には、ワードパッドは「常に Move」として処理されますし、
Copy のみを指定した場合には、ワードパッドは「常に Copy」として処理されます。
これはドロップ先は、allowedEffects で許可されている動作モードのみが
利用可能であるからです。(allowedEffects を無視するアプリもありますが…)
# DragDropEffects には、他にも Scroll や Link など幾つかのモードがありますが、
# それらをドロップ先のアプリがどのように処理するかは、ドロップ先が決める事であって、
# ドラッグ元である VB 側は一切関与する必要がありませんし、関与すべきではありません。
投稿者 (削除されました)  ()
投稿日時
2009/9/10 05:22:36
(削除されました)
投稿者 kmkm  (社会人)
投稿日時
2009/9/10 03:44:06
刈谷勇さん、魔界の仮面弁士さん。
ありがとうございます。
おかげさまで、Moveそのものにつきましては、
お二方がおっしゃられているDoDragDrapの戻り値を
見ることでうまく処理することができました。
ただ残念ながら一点問題が残っており、
もし解決法がお分かりでしたら、ご助言ください。
問題といいますのは、Moveだけでなく、Copyもサポートした後で、
他のアプリ(たとえばワードパッド)にMoveしようといたしますと、
勝手にCopyになってしまう点です。
・魔界の仮面弁士さんのコードでも、ちゃんとシフトを押して、
マウスの右ボタンでドラッグしていっても、私の環境では、
Copyになってしまいます。
・Textの選択状態などを考慮してしないで行ったもともとの
私のコードに手を入れたものでも同様にだめでした。(左ボタン使用)
・どちらのコードにおいても、TextBox2への、MoveやCopyは
それぞれちゃんと正常に動いております。
・ワードパッドにマウスカーソルを移動すると、
「コピーマーク」(+がついたマーク)のカーソルに勝手になってしまいます。
・Moveしかサポートしていなかった私のコードを単に
DoDragDropの戻り値を見るようにしただけのMoveのみを行うコードは
さすがにコピーにならず、Moveのまんまでした。
(マウスカーソルも+がつかず、また、TextBox1のTextが消えます)
よろしくお願いいたします。
ありがとうございます。
おかげさまで、Moveそのものにつきましては、
お二方がおっしゃられているDoDragDrapの戻り値を
見ることでうまく処理することができました。
ただ残念ながら一点問題が残っており、
もし解決法がお分かりでしたら、ご助言ください。
問題といいますのは、Moveだけでなく、Copyもサポートした後で、
他のアプリ(たとえばワードパッド)にMoveしようといたしますと、
勝手にCopyになってしまう点です。
・魔界の仮面弁士さんのコードでも、ちゃんとシフトを押して、
マウスの右ボタンでドラッグしていっても、私の環境では、
Copyになってしまいます。
・Textの選択状態などを考慮してしないで行ったもともとの
私のコードに手を入れたものでも同様にだめでした。(左ボタン使用)
・どちらのコードにおいても、TextBox2への、MoveやCopyは
それぞれちゃんと正常に動いております。
・ワードパッドにマウスカーソルを移動すると、
「コピーマーク」(+がついたマーク)のカーソルに勝手になってしまいます。
・Moveしかサポートしていなかった私のコードを単に
DoDragDropの戻り値を見るようにしただけのMoveのみを行うコードは
さすがにコピーにならず、Moveのまんまでした。
(マウスカーソルも+がつかず、また、TextBox1のTextが消えます)
よろしくお願いいたします。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/9/9 21:05:02
なお、TextBox2 のテキスト全体を書き換えるのではなく、
ドロップさせた位置にドロップしたテキスト挿入させたいのであれば
TextBox2 の部分を以下のように書き換えてみてください。
ドロップさせた位置にドロップしたテキスト挿入させたいのであれば
TextBox2 の部分を以下のように書き換えてみてください。
Private Sub TextBox2_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) Handles TextBox2.DragOver
If e.Data.GetDataPresent(GetType(String)) Then
'Shift キーが押されていれば移動扱い/押されていなければコピー
Dim IsShift As Boolean = CBool(ModifierKeys And Keys.Shift)
If IsShift AndAlso CBool(e.AllowedEffect And DragDropEffects.Copy) Then
e.Effect = DragDropEffects.Move
ElseIf CBool(e.AllowedEffect And DragDropEffects.Copy) Then
e.Effect = DragDropEffects.Copy
End If
Dim mousePos As Point = TextBox2.PointToClient(MousePosition)
Dim caretPos As Integer = TextBox2.GetCharIndexFromPosition(mousePos)
TextBox2.SelectionStart = caretPos
TextBox2.Focus()
End If
End Sub
Private Sub TextBox2_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles TextBox2.DragDrop
TextBox2.SelectedText = e.Data.GetData(GetType(String))
End Sub
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2009/9/9 20:45:37
ドロップされる側は、ドラッグ元がどのようにデータを管理しているかを知りません。
ドラッグする側は、ドロップ先がどのようにデータを表示しているのかを知りません。
なので、ドラッグ & ドロップの処理では、ドラッグ元ドロップ先のそれぞれが、
自身のデータのみを扱うべきであり、相手側を直接操作してはいけません。
刈谷勇さんが書かれているように、DoDragDrop の戻り値で判定してください。
ドラッグする側は、ドロップ先がどのようにデータを表示しているのかを知りません。
なので、ドラッグ & ドロップの処理では、ドラッグ元ドロップ先のそれぞれが、
自身のデータのみを扱うべきであり、相手側を直接操作してはいけません。
刈谷勇さんが書かれているように、DoDragDrop の戻り値で判定してください。
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
TextBox1.Text = "これはドラッグ元のテキストです。右ボタンでドラッグできます(Shiftで移動)。"
TextBox1.Select(3, 5)
TextBox1.AllowDrop = False
TextBox2.Text = ""
TextBox2.AllowDrop = True
End Sub
Private Sub TextBox2_DragOver(ByVal sender As Object, _
ByVal e As DragEventArgs) Handles TextBox2.DragOver
If e.Data.GetDataPresent(GetType(String)) Then
'Shift キーが押されていれば移動扱い/押されていなければコピー
Dim IsShift As Boolean = CBool(ModifierKeys And Keys.Shift)
If IsShift AndAlso CBool(e.AllowedEffect And DragDropEffects.Copy) Then
e.Effect = DragDropEffects.Move
ElseIf CBool(e.AllowedEffect And DragDropEffects.Copy) Then
e.Effect = DragDropEffects.Copy
End If
End If
End Sub
Private Sub TextBox2_DragDrop(ByVal sender As Object, _
ByVal e As DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(GetType(String))
End Sub
Private downPos As Point = Point.Empty
Private Sub TextBox1_MouseDown(ByVal sender As Object, _
ByVal e As MouseEventArgs) Handles TextBox1.MouseDown
'テキストの範囲選択と区別するために、
'ドラッグ & ドロップをマウス 右ボタンに割り当てる。
If CBool(e.Button And System.Windows.Forms.MouseButtons.Right) Then
'ドラッグの開始位置
downPos = e.Location
End If
End Sub
Private Sub TextBox1_MouseMove(ByVal sender As Object, _
ByVal e As MouseEventArgs) Handles TextBox1.MouseMove
If downPos.IsEmpty Then
'ドラッグが開始されていない
Return
End If
'マウスの移動量がドラッグ開始量を越えているかを判定
Dim dragSize As Size = SystemInformation.DragSize
Dim moveRect As New Rectangle( _
downPos.X - dragSize.Width \ 2, _
downPos.Y - dragSize.Height \ 2, _
dragSize.Width, _
dragSize.Height)
If moveRect.Contains(e.Location) Then
Return
End If
downPos = Point.Empty
'コピーと移動を許可する
Dim effect As DragDropEffects
effect = DragDropEffects.Copy Or DragDropEffects.Move
'選択されたテキスト範囲をドラッグ
effect = TextBox1.DoDragDrop(TextBox1.SelectedText, effect)
If CBool(effect And DragDropEffects.Move) Then
'移動されたので選択範囲をクリアする
TextBox1.SelectedText = ""
End If
End Sub
End Class
投稿者 刈谷勇  (社会人)
投稿日時
2009/9/9 19:27:31
こんにちは、kmkmさん。
先にことわっておきますが、ドラッグ&ドロップについては詳しくないのでほかにベストな方法や間違った回答をしているかも知れません。
DoDragDropの戻り値を判断して、ドラッグ&ドロップの対象となった文字列を削除してあげればいいのではないかと思います。
先にことわっておきますが、ドラッグ&ドロップについては詳しくないのでほかにベストな方法や間違った回答をしているかも知れません。
DoDragDropの戻り値を判断して、ドラッグ&ドロップの対象となった文字列を削除してあげればいいのではないかと思います。
投稿者 kmkm  (社会人)
投稿日時
2009/9/9 07:59:31
まだまださん。ありがとうございます。
しかし、うーん。それはちょっと強引ですね。
TextBox1から2というのは
あくまで例示と考えていただけると幸いです。
TextBox3からかもしれませんし、TextBox4からかもしれません。
さらに、たとえば、ワードパッドの方に、ドラッグ&ドロップしても、
ムーブなんですからTextBox1のテキストが消えてほしいわけですが
現状は消えません。
場当たり的な解決法ではなく、
もう少し根本的な解決策をご教授願いたく。
よろしくお願いいたします。
しかし、うーん。それはちょっと強引ですね。
TextBox1から2というのは
あくまで例示と考えていただけると幸いです。
TextBox3からかもしれませんし、TextBox4からかもしれません。
さらに、たとえば、ワードパッドの方に、ドラッグ&ドロップしても、
ムーブなんですからTextBox1のテキストが消えてほしいわけですが
現状は消えません。
場当たり的な解決法ではなく、
もう少し根本的な解決策をご教授願いたく。
よろしくお願いいたします。
投稿者 まだまだ  (中学生)
投稿日時
2009/9/9 07:50:57
強引ですが、TextBox2_DragDropを
Private Sub TextBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(GetType(String))
TextBox1.Text = ""
End Sub
にしたらどうでしょうか?
Private Sub TextBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(GetType(String))
TextBox1.Text = ""
End Sub
にしたらどうでしょうか?
投稿者 kmkm  (社会人)
投稿日時
2009/9/9 06:29:53
TextBox1から2にドラッグ&ドロップで文字列をムーブしたいと思って、
以下のようにしたのですが、コピーと同じように、TextBox1に文字列が
残ったままとなってしまいます。
ムーブなので、元の文字列(TextBox1.Text)が消えてほしいのです。
どのようにすればよいのでしょうか。
ちなみに、ワードパッドのテキストは、TextBox2にドロップすると、
ちゃんとワードパッド側で消えてくれます。
Private Sub TextBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(GetType(String))
End Sub
Private Sub TextBox2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragEnter
If e.Data.GetDataPresent(GetType(String)) Then
'e.Effect = DragDropEffects.Copy
e.Effect = DragDropEffects.Move
End If
End Sub
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
'TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)
TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Move)
End Sub
なお、環境はVista、VB2008EEです。
以下のようにしたのですが、コピーと同じように、TextBox1に文字列が
残ったままとなってしまいます。
ムーブなので、元の文字列(TextBox1.Text)が消えてほしいのです。
どのようにすればよいのでしょうか。
ちなみに、ワードパッドのテキストは、TextBox2にドロップすると、
ちゃんとワードパッド側で消えてくれます。
Private Sub TextBox2_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragDrop
TextBox2.Text = e.Data.GetData(GetType(String))
End Sub
Private Sub TextBox2_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles TextBox2.DragEnter
If e.Data.GetDataPresent(GetType(String)) Then
'e.Effect = DragDropEffects.Copy
e.Effect = DragDropEffects.Move
End If
End Sub
Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles TextBox1.MouseDown
'TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Copy)
TextBox1.DoDragDrop(TextBox1.Text, DragDropEffects.Move)
End Sub
なお、環境はVista、VB2008EEです。
大変ご丁寧にありがとうございました。
おっしゃられていた内容すべてを確認いたしました。
*ちなみに秀丸エディタでも、エディタ内(CTRLでコピー)と、
別のアプリから(SHIFTを押して初めてムーブになる)で
動きが違うことを初めて確認いたしました。
(もう長く使っているんですが知りませんでした。。。)
これにてひとまず一件落着とさせていただきます。
ありがとうございました。