【Access VBA】「マウス追随ボタン」と「逃げて押下できないボタン」をMouseMoveイベントで作る

MS Access
スポンサーリンク

世の中のAccessユーザーの皆さんは、真面目に実用的な業務アプリケーションの開発に勤しんでいることだと思います。

ただ、世の中のすべてで実用的かどうかを優先し、「無駄」という遊び心を無くしてしまってはつまらない社会になってしまいます。

そんな未来を憂いた私が、今回はAccess VBAを使って、「マウスの動きに追随して移動するコマンドボタン」と「押下しようとすると逃げて押せないコマンドボタン」を実装するVBAのサンプルプログラムを紹介します。

Accessユーザーの誰もこのような需要は無いかと思いますが、一般的なAccessアプリケーションではあまり使われない「MouseMove」イベントと「Timer」イベントの簡単な解説もしていくので、そこも踏まえて御一読ください。
 
 

実際の動作サンプル

今回のサンプルプログラムでは、実際の動作を動画で確認していただいた方がイメージし易いかと思います。
最近Twitterの当ブログアカウント内で、「マウスの動きに追随して移動するコマンドボタン」の動画を紹介していますので、良ければそちらも確認してみてください。

 
 

「マウスの動きに追随して移動するコマンドボタン」の紹介

当項では、前項で動画でも掲載した「マウスの動きに追随して移動するコマンドボタン」を紹介していきます。

 
 

サンプルプログラム実装用フォーム例

今回紹介するサンプルプログラムでは、VBE内にコピペしてもらえれば動くように作ってありますが、その為には以下のコントロールを設置してください。

コントロール種類 名前
フォーム なんでもよい
コマンドボタン btn_test
※もし変更する場合は次項のサンプルプログラムも修正してください。


 
 

「マウスの動きに追随して移動するコマンドボタン(Timer有り)」サンプルプログラム

当項では「逃げて押下できないボタン」のサンプルプログラムを紹介します。
当サンプルプログラムでは「MouseMoveイベント」とともに「Timerイベント」も併せて使用します。

前項で作成したフォームのVBAのコードに以下の処理を丸っと貼り付けてください。

Option Compare Database
Option Explicit


Dim MoveLeftPosition As Long    'ボタンの座標(Y)を格納します。
Dim MoveTopPosition As Long     'ボタンの座標(X)を格納します。
Dim HalfWidth As Long           'ボタンの幅の半分の長さを格納します。
Dim HalfHeight As Long          'ボタンの高さの半分の長さを格納します。

Private Sub btn_test_Click()

    'クリックされたらTimerを停止して自フォームを閉じます。
    Me.TimerInterval = 0
    DoCmd.Close acForm, Me.Name

End Sub

Private Sub btn_test_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

    'Timerイベント開始※1ミリ秒
    Me.TimerInterval = 1

End Sub

Private Sub Form_Load()

    'ボタンコントロールの中心の幅と高さを取得します。
    HalfWidth = Round(Me.btn_test.Width / 2, 0)
    HalfHeight = Round(Me.btn_test.Height / 2, 0)

End Sub

Private Sub Form_Timer()

    'ボタンコントロールの座標を指定します。
    Me.btn_test.Left = MoveLeftPosition
    Me.btn_test.Top = MoveTopPosition

End Sub

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

    'マウスの座標を元に、ボタン幅や高さを考慮して変数に格納します。
    MoveLeftPosition = X - HalfWidth
    MoveTopPosition = Y - HalfHeight

End Sub

サンプルプログラム解説

10行目

コマンドボタンクリック時のイベントで自フォームを閉じています。
これは、MouseMoveイベントのなかでコマンドボタンを動かす処理の特性上、MouseMoveから抜け出せないからです。
他にも良い抜け方はあるとは思いますが、考えるのが面倒なのでフォームを閉じる処理で逃げました。
後、「Me.TimerInterval = 0」と指定することで、後述するTimerイベントを止めることができます。

18行目

MouseMoveイベント内で「Me.TimerInterval = 1」と指定することで、Timerイベントを1ミリ秒ごとに動かしす指示になります。

25行目

フォームのLoadイベント内で、配置しているコマンドボタンの幅と高さのそれぞれ半分の値を取得しています。
なぜ半分の値が必要なのかは後述します。

41行目

フォームの詳細セクションのMouseMoveイベント内でマウスの座標を取得して、それに対して25行目の処理で取得した、コマンドボタンの幅と高さの半分の値を引いて、それを変数に代入しています。
この処理は、マウスの座標に対してコマンドボタンの幅と高さの半分の値を引いた座標位置を作成して、コマンドボタンがマウスの動きに追随して動く際に、常にマウスの位置がコマンドボタンの中央をキープさせることを目的としています。
33行目のTimerイベント内でその変数をコマンドボタンの「Left」プロパティと「Top」プロパティに指定し続けることで、コマンドボタンがマウスに追随して動きます。

 
 

「マウスの動きに追随して移動するコマンドボタン(Timer無し)」サンプルプログラム

前述したサンプルプログラムでは、Timerイベントを使用しましたが、実はTimerイベントは使わなくても、マウスの動きに追随する処理は作れます。
前述のサンプルプログラムでTimerイベントを使用したのは、マウスのポインターがコマンドボタンの上に移動した際に、自動的に追随を開始するようにしたかったからであり、追随を開始するきっかけを別で作れるならTimerイベントは不要です。

当項では、「Timerイベントを使わないパターン」のサンプルプログラムを紹介します。

尚、前述したフォームに対して、当サンプルプログラムでは、更にテキストボックスを一つ追加する必要があります。

コントロール種類 名前
フォーム なんでもよい
コマンドボタン btn_test
※もし変更する場合は次項のサンプルプログラムも修正してください。
テキストボックス txt_Run
※もし変更する場合は次項のサンプルプログラムも修正してください。

Option Compare Database
Option Explicit


Dim HalfWidth As Long         'ボタンの幅の半分の長さを格納します。
Dim HalfHeight As Long        'ボタンの高さの半分の長さを格納します。

'クリック時に、マウス追随を有効化無効化します。
Private Sub btn_test_Click()

    Dim EnableFlag As Integer
    
        EnableFlag = Me.txt_Run.Value

        'MouseMoveイベント制御フラグを有効化、又は無効化します。
        If EnableFlag = 0 Then
            Me.txt_Run.Value = 1
        Else
            Me.txt_Run.Value = 0
        End If

End Sub

Private Sub Form_Load()

    'ボタンコントロールの中心の幅と高さを取得します。
    HalfWidth = Round(Me.btn_test.Width / 2, 0)
    HalfHeight = Round(Me.btn_test.Height / 2, 0)

    'MouseMoveイベント制御フラグを初期化します。
    Me.txt_Run.Value = 0

End Sub

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

    'MouseMoveイベント制御フラグが0なら処理をしない。
    If Me.txt_Run.Value = 1 Then
        
        'ボタン幅や高さを考慮してボタン位置の座標を指定します。
        Me.btn_test.Left = X - HalfWidth
        Me.btn_test.Top = Y - HalfHeight
    End If

End Sub

サンプルプログラム解説

9行目

コマンドボタンのClickイベントで、フォーム内のテキストボックスに0又は1を入れています。
当プログラムでは、マウスの動きにコマンドボタンを追随させる際の開始と停止のトリガーとして、コマンドボタンのクリック時に書き込まれたテキストボックス内の値を使用しており、その制御の為にこの処理が必要です。

24行目

フォームのLoadイベント時に、前述したサンプルプログラムと同様に、コマンドボタンの幅と高さの半分の値を取得しています。
また、MouseMove制御用のテキストボックスの値を初期化しています。

35行目

フォームの詳細セクションのMouseMoveイベント内で、マウスポインターの座標を取得して、24行目の処理で取得したコマンドボタンの幅と高さの半分の値をマウスポインターの座標から引いた値とコマンドボタンの位置に指定しています。
また、MouseMove制御用のテキストボックスの値が1の場合のみ追随処理が動くように指定しています。

 
 

「押下しようとすると逃げて押せないコマンドボタン」の紹介

当項では、「押下しようとすると逃げて押せないコマンドボタン」を紹介していきます。
尚、ボタンは押すためにあるので、押せないボタンに存在意義はありません。
 
 

サンプルプログラム実装用フォーム例

今回紹介するサンプルプログラムでは、VBE内にコピペしてもらえれば動くように作ってありますが、その為には以下のコントロールを設置してください。

コントロール種類 名前
フォーム なんでもよい
コマンドボタン btn_test
※もし変更する場合は次項のサンプルプログラムも修正してください。


 
 

「押下しようとすると逃げて押せないコマンドボタン」サンプルプログラム

当項では「逃げて押下できないボタン」のサンプルプログラムを紹介します。
前項で作成したフォームのVBAのコードに以下の処理を丸っと貼り付けてください。

Option Compare Database
Option Explicit


Dim IniLeft As Long         'コマンドボタン初期Left
Dim IniTop As Long          'コマンドボタン初期Top
Dim FormWidth As Long       'フォーム幅
Dim FormHeight As Long      'フォーム高さ

Const MoveLength As Long = 2000     '移動時の長さ

Private Sub btn_test_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

    'ランダムな値によって移動先を判別します。
    Select Case Get_RandomDirection()
    
        Case 1
            If Not Is_OutOfFormSize(1) Then
                Me.btn_test.Left = Me.btn_test.Left + MoveLength
            End If
        Case 2
            If Not Is_OutOfFormSize(2) Then
                Me.btn_test.Top = Me.btn_test.Top + MoveLength
            End If
        Case 3
            If Not Is_OutOfFormSize(3) Then
                Me.btn_test.Left = Me.btn_test.Left - MoveLength
            End If
        Case 4
            If Not Is_OutOfFormSize(4) Then
                Me.btn_test.Top = Me.btn_test.Top - MoveLength
            End If
    End Select

End Sub

Private Sub Form_Load()

    'コマンドボタンの初期位置を取得します。
    IniLeft = Me.btn_test.Left
    IniTop = Me.btn_test.Top

    'フォームの幅と高さを取得します。
    FormWidth = Me.Width
    FormHeight = Me.詳細.Height

End Sub

Private Sub 詳細_Click()

    '移動したボタンを元に位置に戻します。
    Me.btn_test.Left = IniLeft
    Me.btn_test.Top = IniTop

End Sub

'1から4までの数値をランダムに返します。
Function Get_RandomDirection() As Integer

    '乱数を初期化
    Randomize
    '1から4までのランダムな値を戻り値にセットします。
    Get_RandomDirection = Int(4 * Rnd + 1)

End Function

'移動先がフォームのサイズの範囲外かを返します。
Function Is_OutOfFormSize(MoveType As Integer) As Boolean

    Is_OutOfFormSize = False

    Select Case MoveType
        Case 1
            If FormWidth < Me.btn_test.Left + MoveLength Then
                Is_OutOfFormSize = True
            End If
        Case 2
            If FormHeight < Me.btn_test.Top + MoveLength Then
                Is_OutOfFormSize = True
            End If
        Case 3
            If 0 > Me.btn_test.Left - MoveLength Then
                Is_OutOfFormSize = True
            End If
        Case 4
            If 0 > Me.btn_test.Top - MoveLength Then
                Is_OutOfFormSize = True
            End If
    End Select

End Function

サンプルプログラム解説

10行目

ボタンを座標を移動させる際に加算又は減算する座標の値を指定します。
ここの値が大きいほど、ボタンは大きく逃げます。
適当な値で調整してみてください。

12行目

コマンドボタンのMouseMoveイベントが呼び出されることで、マウスの座標を元に、ランダムな方向にコマンドボタンが移動します。
ボタンの移動処理では、コマンドボタンの「Left」プロパティ、又は「Top」プロパティに移動先の座標位置をセットしています。

49行目

フォーム内の「詳細」セクションをクリックすることで、ボタンをフォーム読み込み時の位置に戻します。

58行目

乱数を生成し、1から4までの数値をランダムに生成します。

68行目

コマンドボタンの移動先がフォームサイズの範囲外が指定されるとプログラムがエラーになる為、44行目~45行目で取得したフォームの幅と高さを元に、ボタンの移動先がその座標の範囲内か否かをチェックするための処理です。

 
 

【おまけ】「MouseMoveイベント」と「Timerイベント」の簡単な解説

今回の記事では、普段あまり使われることのない、Access VBAの「MouseMoveイベント」と「Timerイベント」を簡単に解説しておきます。
 
 

MouseMoveイベント

MouseMoveイベントは、Accessのフォームのデザイナー画面でプロパティを表示した際に、イベント欄のなかの「マウス移動時」です。

「マウス移動時」のイベントを有効にすると、VBAのコードに以下の行が追加されます。

Private Sub コントロール名_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)

引数が四つもあり独特です。
まずはこの引数の意味を紹介します。

引数 説明
Button マウスの押したボタンを整数で返します。
1:左ボタン
2:右ボタン
3:中央ボタン
Shift 第一引数「Button」引数が渡された際に、併せて、Shift、Ctrl、Altキーが押下された際に整数で返します。
0:押下キー無し
1:Shiftキー
2:Ctrlキー
3:Altキー
X 対象のコントロールに対するマウスポインターの現在の位置をX座標で返します。
Y 対象のコントロールに対するマウスポインターの現在の位置をY座標で返します。
「MouseMoveイベント」は対象のコントロールにマウスポインターが重なったら実行されますが、そこで呼び出しが終わる訳ではなく、そのコントロールの上をマウスポインターが僅かでも移動する度に「MouseMoveイベント」が何度でも呼ばれます。
座標を返す以上、当然の仕様なのですが、初めてこのイベントを利用する場合は直観的にOnMouse的に、そのコントロールにマウスポインターが重なったら実行されて、マウスポインターが移動してオブジェクトの上部から座標を外れ、また再度コントロールにマウスポインターが重なるまで実行されないと思い込みがちなので、注意が必要です。
※ってか私がそうでした・・・。
「MouseMoveイベント」はマウスポインターの座標を返しますが、注意が必要なのは、「MouseMoveイベント」が返す座標は、「MouseMoveイベント」を有効にしたコントロール上の座標です。
例えば、フォーム(フォーム内のセクション)に「MouseMoveイベント」を指定した場合は、フォームの左上をX:0,Y:0とした座標を返します。
コマンドボタンに「MouseMoveイベント」を指定した場合は、そのコマンドボタンの形状の左上をX:0,Y:0とした座標を返してきます。
直観的には、コマンドボタンで指定した「MouseMoveイベント」であっても、返してくる座標はフォーム内のマウスポインターの位置を返してくると思い込みがちなので気を付けてください。
※ってか私がそうでした・・・。

詳しくはMicrosoft公式ドキュメントをご参照ください。
Microsoft Office VBAリファレンス -Access Formオブジェクト MouseMoveイベント-
 
 

Timerイベント

「Timerイベント」は、Accessのフォームのデザイナー画面でプロパティを表示した際に、イベント欄のなかの「タイマー時」です。

「タイマー時」のイベントを有効にすると、VBAのコードに以下の行が追加されます。

Private Sub Form_Timer()

このイベントのプロシージャに処理を記述すると、指定した実行間隔で繰り返し呼び出されます。
例えば、「特定のフォルダを監視し、指定したファイルが存在していたら、それをトリガーに何らかの処理を実行する」といった処理を実装する場合などによく使われます。

この「Timerイベント」を呼び出す際には、以下の様に記述します。

Me.TimerInterval = 1000

フォームに「TimerInterval」プロパティを指定することでTimerイベントが開始されます。
「TimerInterval」プロパティの値は「ミリ秒」単位なので、例えば1秒間隔で実行させる場合は、上記の様に1000と指定します。

また、「Timerイベント」を停止する場合は以下のように記述します。

Me.TimerInterval = 0

「Timerイベント」の実行間隔を0で指定することで、「Timerイベント」の呼び出しそのものが停止します。

「Timerイベント」は一度実行すると、指定された実行間隔で延々と呼び出され、実行元のフォームを閉じるか、上記の様に明示的にTimerIntervalプロパティに0を渡さない限り停止しません。
「Timerイベント」がバックグランドで呼び出されていても、画面に変化がある処理ではない可能性もある為、ユーザーは気付きません。
その為、意図しない「Timerイベント」が裏で延々と実行されないように、「Timerイベント」の開始と終了は適切に制御してあげる必要があります。

詳しくはMicrosoft公式ドキュメントをご参照ください。
Microsoft Office VBAリファレンス -Access Formオブジェクト Timerイベント-
 
 

最後に

今回は、Access VBAを使用して、「マウスの動きに追随して移動するコマンドボタン」と「押下しようとすると逃げて押せないコマンドボタン」を作成するサンプルプログラムを紹介しました。

これまでのブログの記事では、VBAやVBScriptなどのサンプルプログラムを紹介する場合は、なるべく実用性のあると思われるものを掲載してきました。
自分自身が「何の役に立つのだろうか?」と思った情報を掲載するのは初めての試みです。

今回のサンプルプログラムを利用して、ユーザーの業務を妨害してみたり、同僚を驚かせてみたりするぐらいしか活用する術はありませんが、是非気分転換に実装してみてもらえると嬉しいです。

今回も読んでいただきましてありがとうございました。
それでは皆さまごきげんよう!

タイトルとURLをコピーしました