Excel VBAで図形を使ったUIを作っていると、「図形をドラッグ移動したあと、自動的にセル位置へ吸着させたい」と考える場面があります。特にカードゲームやスケジュール管理、配置ツールなどでは、図形を移動した瞬間に位置補正したいケースが多くあります。しかし、Excel VBAには図形の“ドラッグ終了イベント”が標準で存在しないため、実装方法に悩む人も少なくありません。この記事では、Excel VBAで図形移動後の位置補正を行う考え方や、実際によく使われる回避方法をわかりやすく解説します。
Excel VBAには「図形を離した瞬間」のイベントが存在しない
まず理解しておきたいのは、Excel VBAでは図形に対する細かいマウスイベントが非常に限定的という点です。
通常のコントロールであれば、以下のようなイベントがあります。
- MouseDown
- MouseMove
- MouseUp
しかし、シート上の通常図形(Shapeオブジェクト)では、ドラッグ終了を直接取得するイベントは用意されていません。
つまり「マウスを離した瞬間」を直接割り込む方法は基本的に存在しません。
図形にマクロを登録すると移動できなくなる理由
質問のように、図形へマクロを割り当てる方法を試す人は非常に多いです。
ただし、図形に設定したマクロは「クリック時」に実行されます。
そのため、以下のような状態になります。
- 図形をクリック
- 即マクロ実行
- ドラッグ操作に入れない
つまり、図形のドラッグとマクロ実行は競合しやすいのです。
これはExcelの仕様に近い動作です。
実務で多いのは「定期監視方式」
実は、Excel VBAで図形ドラッグ後の処理を実装する場合、最もよく使われるのは「位置監視」です。
具体的には以下の流れになります。
- 一定間隔で図形位置を監視
- 前回座標と違えば移動判定
- 移動停止後に補正処理
つまり、“イベント”ではなく“監視”で実現します。
イメージ
| 状態 | 処理 |
|---|---|
| 移動中 | 座標変化を監視 |
| 停止検知 | セルへ吸着 |
ゲーム開発でも似た考え方が使われます。
セルへ吸着させる処理は比較的簡単
図形の位置補正自体は、VBAではそれほど難しくありません。
例えば図形左上の座標から、最も近いセルを取得し、そのセル位置へ移動させます。
よく使われる考え方は以下です。
- Top → 行位置へ丸める
- Left → 列位置へ丸める
- Cells(row,col).Top / Leftへ移動
これにより、ソリティアのカード吸着のような動きが作れます。
Application.OnTimeを使う方法
VBAでは「定期監視」にApplication.OnTimeを使うケースがあります。
これは一定時間後にマクロを再実行する仕組みです。
例えば0.2秒ごとに図形位置を確認することで、ドラッグ終了を擬似的に検知できます。
メリット
- 比較的安定
- 複数図形にも対応しやすい
- 通常図形で利用可能
デメリット
- リアルタイム性はやや低い
- 監視負荷がある
- 処理設計が必要
ただ、Excel VBAではかなり定番の方法です。
もっと高度にやるならUserFormを使う方法もある
もし完全なドラッグイベント制御をしたい場合は、図形ではなくUserForm上のコントロールを使う方法もあります。
UserFormなら以下イベントが利用可能です。
- MouseDown
- MouseMove
- MouseUp
つまり、マウスを離した瞬間を正確に取得できます。
ただし、通常シート上で動かす場合より設計難易度は上がります。
実際によくある実装例
実務では以下のような用途で使われます。
| 用途 | 内容 |
|---|---|
| 工程管理 | タスクカード移動 |
| 座席表 | 人員配置変更 |
| 在庫管理 | 棚位置変更 |
| ゲーム風UI | カード配置 |
特に「セル吸着」はExcel UIとの相性が非常に良いです。
おすすめの実装方針
Excel VBAで無理に“マウス離しイベント”を探すより、以下の構成が現実的です。
- 図形移動を許可
- 一定間隔監視
- 停止後に吸着
この方式は実装難易度と安定性のバランスが良く、多くのVBA開発で採用されています。
「イベント取得」ではなく「状態変化監視」で考えるのがポイントです。
まとめ
Excel VBAでは、通常図形に対して「マウスを離した瞬間」を直接取得するイベントは存在しません。そのため、図形移動後のセル吸着処理を行う場合は、位置監視による疑似判定が一般的です。特にApplication.OnTimeを使った定期監視方式は実務でもよく使われます。もし本格的なドラッグイベント制御が必要なら、UserFormベースの実装も検討できます。Excel VBAでは“イベントを探す”より、“状態変化を監視する”発想が重要になります。

コメント