#10 フォーム上でのマウスの動きを追いかける

ここに出てくるイベント
  • Click/クリック時
  • MouseDown/マウスボタンクリック時
  • MouseMove/マウスボタン移動時
  • MouseUp/マウスボタン解放時


複数オブジェクト間のマウス関連イベントについて

フォームにおいては、フォームオブジェクトや"詳細"などのセクション、あるいはテキストボックスコントロールなど、みな同様のマウス操作関連のイベントを持っています。それらのイベントとは、
  • クリック時
  • ダブルクリック時
  • マウスボタンクリック時
  • マウスボタン移動時
  • マウスボタン解放時
の5つです。これら5つのイベントの動きや違いについては「#4 コマンドボタンのイベント」のところで取り上げていますので、ある1つのオブジェクト(#4では"コマンドボタン")におけるイベントについては、そちらを参照していただければよいでしょう。ここでは、複数のオブジェクト間でマウスの移動や操作があった場合に、どのようなイベントが発生するかに焦点を当てて、トレースを行ってみたいと思います。


ここでは、イベント調査用のフォームとして次のようなフォームを用意しました。
テスト用フォーム

ここでは、「詳細」セクション・「電話番号」テキストボックス・「FAX番号」テキストボックスの3つのオブジェクトにイベントをトレースするためのプロシージャ呼び出しを記述し、その流れを追ってみたいと思います。
  • 「詳細」セクションのイベントプロパティ
    「詳細」セクションのイベントプロパティ

  • 「電話番号」テキストボックスのイベントプロパティ
    「電話番号」テキストボックスのイベントプロパティ

  • 「FAX番号」テキストボックスのイベントプロパティ
    「FAX番号」テキストボックスのイベントプロパティ



フォームの下から「電話番号」にマウスを移動すると?

まず、マウスがフォームの外にある状態から、マウスを上へ向けて「電話番号」テキストボックスまで移動させてみます。その際、「FAX番号」テキストボックスの上を通過するようにします。

マウスの動き

その結果は次のようになりました。

発生順序 オブジェクト名 イベント名
1 詳細セクション マウスボタン移動時
2 詳細セクション マウスボタン移動時
3 FAX番号 マウスボタン移動時
4 FAX番号 マウスボタン移動時
5 FAX番号 マウスボタン移動時
6 FAX番号 マウスボタン移動時
7 FAX番号 マウスボタン移動時
8 詳細セクション マウスボタン移動時
9 詳細セクション マウスボタン移動時
10 詳細セクション マウスボタン移動時
11 電話番号 マウスボタン移動時
12 電話番号 マウスボタン移動時
13 電話番号 マウスボタン移動時
14 電話番号 マウスボタン移動時


ここではマウスボタンの操作は一切行っていませんので、発生するイベントとしては「マウスボタン移動時」だけです。ご覧のように、マウスを移動させた通りに、それぞれのオブジェクトでイベントが発生しています。なお、ここでのイベントの発生回数は特に問題ではありません。これはマウスの移動速度によって大きく変わるからです。マウスをゆっくり少しずつ移動させれば、同じオブジェクトでより多くのイベントが発生します。ここでは、「詳細セクション→FAX番号→詳細セクション→電話番号」という順番でイベントが発生していることだけに着目してください。きっと、ご推測どおりの結果になっているはずです。



「電話番号」・「FAX番号」を順番にクリックすると?

今度はマウスのクリック操作を追加してみましょう。まず、「電話番号」のテキストボックス上にマウスがある状態にします。そこでマウスの左ボタンをクリックしたあと、「FAX番号」にマウスを移動、そこでまたクリックを行います。

その結果は次のようになりました。

発生順序 オブジェクト名 イベント名
1 電話番号 マウスボタン移動時
2 電話番号 マウスボタン移動時
3 電話番号 マウスボタンクリック時
4 電話番号 マウスボタン移動時
5 電話番号 マウスボタン解放時
6 電話番号 クリック時
7 電話番号 マウスボタン移動時
8 電話番号 マウスボタン移動時
9 詳細セクション マウスボタン移動時
10 詳細セクション マウスボタン移動時
11 FAX番号 マウスボタン移動時
12 FAX番号 マウスボタン移動時
13 FAX番号 マウスボタンクリック時
14 FAX番号 マウスボタン移動時
15 FAX番号 マウスボタン解放時
16 FAX番号 クリック時
17 FAX番号 マウスボタン移動時


実際にはかなりの数の"マウスボタン移動時"イベントが発生していますが、分かりやすくするために、結果からは一部除外してあります。"マウスボタンクリック時"イベントと"マウスボタン解放時"イベントの間にある"マウスボタン移動時"イベントは、マウスの左ボタンを押してから離すまでの間の、微妙なマウスの動きまでもトレースされているためで、ここではあまり気にするところではないでしょう。それらを除外して整理してみると、この結果は次のようになります。
  1. 「電話番号」テキストボックスで、"マウスボタンクリック時"・"マウスボタン解放時"・"クリック時"イベントが発生する

  2. 電話番号→詳細セクション→FAX番号という順番で"マウスボタン移動時"イベントが発生する

  3. 「FAX番号」テキストボックスで、"マウスボタンクリック時"・"マウスボタン解放時"・"クリック時"イベントが発生する

これも、「#4 コマンドボタンのイベント」の内容を念頭に入れておけば、推測通りの結果となっているはずです。



「電話番号」から「FAX番号」にマウスをドラッグすると?

先ほどは、2つのテキストボックスを続けてクリックするという操作を行ってみました。"クリックする(=ボタンを押して離す)"という操作によって、各テキストボックスにおいて、"マウスボタンクリック時"・"マウスボタン解放時"・"クリック時"という3つのイベントが連続して発生していました。それでは、クリックではなく、マウスのボタンを押しっ放しにしたまま2つのテキストボックス間を移動する、つまり、テキストボックスから別のテキストボックスへのドラッグを行うと、どのようなイベントが発生するのか、ここで確認してみたいと思います。

ここでは次のような手順でマウス操作を行ってみます。
  1. 「電話番号」テキストボックス上でマウスの左ボタンを押す
  2. ボタンを押したまま、マウスを「FAX番号」テキストボックス上まで移動する
  3. 「FAX番号」テキストボックス上でマウスの左ボタンを離す

そのイベント発生の結果は次のようなものになりました。

発生順序 オブジェクト名 イベント名
1 電話番号 マウスボタン移動時
2 電話番号 マウスボタンクリック時
3 電話番号 マウスボタン移動時
4 電話番号 マウスボタン移動時
5 電話番号 マウスボタン移動時
6 電話番号 マウスボタン解放時
7 電話番号 クリック時
8 FAX番号 マウスボタン移動時
9 FAX番号 マウスボタン移動時
10 FAX番号 マウスボタン移動時


ここでもまた、実際にはもっと多くの"マウスボタン移動時"イベントが発生していますが、あまりそれにとらわれる必要はないので、上記ではかなり省略してあります。それよりも、ここでの大きなポイントは、
  • 「FAX番号」上でマウスのボタンを離したにも関わらず、「FAX番号」テキストボックスで"マウスボタン解放時"イベントなどは発生していない

  • 「FAX番号」上までマウスを移動させてからボタンを離したにも関わらず、「電話番号」テキストボックスでマウスボタンを離したときのイベント、つまり"マウスボタン解放時"や"クリック時"などのイベントが発生している

  • 詳細セクション上をマウスが移動したにも関わらず、「詳細」セクションでの"マウスボタン移動時"イベントは発生していない
という、実際のマウス操作から想像できるものとは異なる結果が出ている点です。マウス操作から考えれば、「詳細」セクションでの"マウスボタン移動時"や、「FAX番号」テキストボックスでの"マウスボタン解放時"・"クリック時"のイベントが発生してもよいはずなのですが.....。これはこれで、Accessフォームのイベント発生の実態として押さえておきましょう。



「電話番号」から「FAX番号」へのドラッグ&ドロップにトライ

Visual Basicのフォームの場合には、ドラッグ&ドロップに関するイベントがあらかじめ用意されていて、比較的容易にドラッグ&ドロップの仕組みを組み込むことが可能です。しかし、Accessにはそのようなイベントがないため、これまで説明した既存のイベントをうまく組み合わせることによって、擬似的にその処理を行わなければなりません。ここでは、それにトライしてみたいと思います。

まず、ドラッグ&ドロップというマウス操作の流れを確認しておきましょう。ここでは、あるテキストボックスから別のテキストボックスにドラッグ&ドロップ操作を行うことによってその内容をコピーするという操作を考えてみます。
  1. ドラッグ元のテキストボックス上でマウスのボタンを押し下げする
  2. マウスのボタンを押し下げしたまま、コピー先のテキストボックス上までマウスを移動させる
  3. コピー先のテキストボックス上でマウスのボタンを離す

これを、上述の『「電話番号」から「FAX番号」にマウスをドラッグすると?』で説明したようなイベントの発生動作を考慮して、Accessにおけるドラッグ&ドロップの処理手順として考えてみましょう。ここでは「電話番号」テキストボックスの内容を「FAX番号」テキストボックスにドラッグ&ドロップによってコピーするという操作を考えてみます。


まず、基本的な処理は次のようなものになります。
  1. 「電話番号」テキストボックス上でマウスボタンの押されたこと(ドラッグのスタート)を検出する
  2. マウスが移動中もボタンが押されていることを検出する
  3. 「FAX番号」テキストボックス上にマウスが移動したことを検出する
  4. 「FAX番号」テキストボックス上でマウスのボタンが離された(ドロップされた)ことを検出する

まず1については、「電話番号」テキストボックスの"マウスボタンクリック時"イベントによって簡単に検出することができるでしょう。イベントが発生したこと=ボタンが押されたと判断することができます。


続いて2ですが、これは"マウスボタン移動時"イベントが発生したというだけでは、ボタンが押されていると判断することはできません。ここで"マウスボタン移動時"イベントのプロシージャの宣言を見てみましょう。

Private Sub 電話番号_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)


どうやら、最初の引数"Button"によって、マウスの移動中のボタンの状態を検出できそうです。オンラインヘルプでこの引数の内容を調べてみると次のようなことが分かります。
  • この引数によってイベント発生時のマウスボタンの状態を取得することができる
  • 組み込み定数をビットマスクとして使うことによって、どのボタンが押されているか知ることができる。
    • acLeftButton → マウスの左ボタン用のビットマスク
    • acRightButton → マウスの右ボタン用のビットマスク
    • acMiddleButton → マウス中央ボタン用のビットマスク

この内容から、"マウスボタン移動時"イベントが発生したら、引数"Button"の値を調べることによって2の判定を行うことが可能であることが分かります。この際、左ボタンが押されていたら当然ドラッグ&ドロップが実行中であると判断しますが、同時に、もしボタンが押されていなければドラッグ&ドロップが中断されたという判断も行わなければなりません。また、"マウスボタン移動時"イベントは何回も発生しますので、その発生する可能性のあるオブジェクトすべての"マウスボタン移動時"イベントでそれらの判断をしなければなりません。つまり、「電話番号」テキストボックス、「FAX番号」テキストボックス、「詳細」セクションの3つすべてにその処理を記述する必要があるわけです。


さて、問題は3と4です。普通に考えれば、「FAX番号」テキストボックスで"マウスボタン移動時"イベントが発生すればそれを判断基準とすることができるのですが、『「電話番号」から「FAX番号」にマウスをドラッグすると?』の結果をみれば分かるように、そのイベントはマウスのボタンを離したあとでないと発生しないのです。つまり、「FAX番号」のイベントは一切使うことができず、「電話番号」テキストボックスのイベントだけでそれらを判断しなければならないのです。

そこで、「電話番号」テキストボックスの"クリック時"と"マウスボタン解放時"イベントプロシージャの利用を検討してみましょう。それらの宣言は次のようになっています。

Private Sub 電話番号_Click()

Private Sub 電話番号_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)


この宣言から、まず"クリック時"イベントでは何ら判断を行うことができないということが分かります。一方の"マウスボタン解放時/MouseUp"イベントは引数がいろいろあるので、何となく利用方法がありそうです。

そこで、このように考えてみることにしました。『「電話番号」テキストボックスの"マウスボタン解放時"イベントが発生したらイベントプロシージャの引数 X と Y からマウスの位置を調べ、それが「FAX番号」テキストボックス上にあるかどうか判断する。もし「FAX番号」テキストボックス上にあればドロップされた、そうでなければ別のオブジェクト上でドロップされた、つまりドロップが中止されたと判断する』。


以上のことを踏まえ、実際に各イベントプロシージャのコーディングを行ってみました。まず、実際のコピー処理は行わず、そのスケルトンとなるコードのみを次に示します。このコードで、どんなときにドラッグか開始され、どんなときにドラッグ中、ドラッグ中止あるいはドラッグ完了と判断されるか確認してみてください。

Private Sub FAX番号_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  If (Button And acLeftButton) > 0 Then
    Debug.Print "ドラッグ中"
  Else
    Debug.Print "ドラッグ中止"
  End If

End Sub

Private Sub 詳細_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  If (Button And acLeftButton) > 0 Then
    Debug.Print "ドラッグ中"
  Else
    Debug.Print "ドラッグ中止"
  End If

End Sub

Private Sub 電話番号_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

  Debug.Print "ドラッグ開始"

End Sub

Private Sub 電話番号_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  If (Button And acLeftButton) > 0 Then
    Debug.Print "ドラッグ中"
  Else
    Debug.Print "ドラッグ中止"
  End If

End Sub

Private Sub 電話番号_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)

  Dim lngAbsX As Long
  Dim lngAbsY As Long

  '引数XとYは、電話番号テキストボックスの左上端の座標値に対する
  '相対位置を表すものなので、これをフォーム左上端に対する
  '絶対座標値に置き換える
  lngAbsX = Me!電話番号.Left + X
  lngAbsY = Me!電話番号.Top + Y

  With Me!FAX番号
    'FAX番号テキストボックスの座標範囲の中にあるか調べる
    If ((lngAbsX >= .Left) And (lngAbsX <= .Left + .Width)) _
        And _
        ((lngAbsY >= .Top) And (lngAbsY <= .Top + .Height)) Then
      Debug.Print "ドラッグ完了"
    Else
      Debug.Print "ドラッグ中止"
    End If
  End With

End Sub


それでは、最後に、実際にドラッグ&ドロップによって電話番号の内容をFAX番号欄にコピーするコードを紹介します。ここでは、ドラッグしているかどうかの状態管理を、フォームモジュール内でPublicな変数 pblnDragNow で行っています。ドラッグ中はこの値がTrueとなり、中止または完了でFalseがセットされます。残念ながら、ドラッグ中を表すマウスのポインタ形状を変えるまでの機能は付いていませんが、"ドラッグ&ドロップによってコピーする"という処理は実現できるはずです。

Option Compare Database
Option Explicit

Private pblnDragNow As Boolean  'ドラッグ中かどうかを示すフラグ

Private Sub FAX番号_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  pblnDragNow = ((Button And acLeftButton) > 0)

End Sub

Private Sub 詳細_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  pblnDragNow = ((Button And acLeftButton) > 0)

End Sub

Private Sub 電話番号_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

  pblnDragNow = True

End Sub

Private Sub 電話番号_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

  pblnDragNow = ((Button And acLeftButton) > 0)

End Sub

Private Sub 電話番号_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)

  Dim lngAbsX As Long
  Dim lngAbsY As Long

  If pblnDragNow Then
    'ドラッグ中のとき
    lngAbsX = Me!電話番号.Left + X
    lngAbsY = Me!電話番号.Top + Y
    With Me!FAX番号
      If ((lngAbsX >= .Left) And (lngAbsX <= .Left + .Width)) _
          And _
          ((lngAbsY >= .Top) And (lngAbsY <= .Top + .Height)) Then
        '電話番号の内容をFAX番号にコピー
        .Value = Me!電話番号
      Else
        pblnDragNow = False
      End If
    End With
  End If

End Sub

実行結果:
「電話番号」テキストボックス上でマウスのボタンを押し下げ

「FAX番号」テキストボックス上でドロップ

| Index | Prev | Next |

 

Copyright © T'sWare All rights reserved