MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
MFCの基礎 - マウスのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
MFCの基礎 - マウス
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == MFCアプリケーションにおけるマウス処理は、Windowsのメッセージドリブン設計に基づいて実装される。<br> <br> マウス入力は、WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_MOUSEWHEELなどのWindowsメッセージとして処理される。<br> MFCは、これらのメッセージを処理するための便利なメッセージハンドラ (OnLButtonDown、OnMouseMove、OnMouseWheel等) を提供している。<br> <br> * マウスメッセージの種類と処理フロー * マウス位置の取得と座標変換 * マウスボタン状態の取得 * MFCのマウスイベントハンドラ * マウスカーソルの制御 * マウスキャプチャによるドラッグ操作 * マウストラッキングとホバー検出 * マウス入力のシミュレーション <br> マウスメッセージのパラメータには、マウスの座標情報 (lParam) とボタン状態 (wParam) が含まれる。<br> 座標はクライアント座標系で提供されるため、スクリーン座標との変換が必要な場合もある。<br> <br> MFCのマウス処理を理解することにより、以下に示す機能を実装できる。<br> <br> * ドラッグアンドドロップ機能 * 描画アプリケーションのペン操作 * ズーム・パン操作 * コンテキストメニューの表示 * ツールチップやホバー効果の実装 <br><br> == マウスメッセージ == Windowsは、マウス入力を複数のメッセージとして処理する。<br> <br> <center> {| class="wikitable" |+ 主要なマウスメッセージ |- ! メッセージ !! 説明 |- | WM_LBUTTONDOWN<br>WM_LBUTTONUP || 左ボタンが押下された時と離された時に送信される。 |- | WM_RBUTTONDOWN<br>WM_RBUTTONUP || 右ボタンが押下された時と離された時に送信される。 |- | WM_MBUTTONDOWN<br>WM_MBUTTONUP || 中ボタンが押下された時と離された時に送信される。 |- | WM_MOUSEMOVE || マウスカーソルが移動した時に送信される。 |- | WM_MOUSEWHEEL || 垂直マウスホイールが回転した時に送信される。 |- | WM_MOUSEHWHEEL || 水平マウスホイールが回転した時に送信される。 |- | WM_LBUTTONDBLCLK<br>WM_RBUTTONDBLCLK || ダブルクリックされた時に送信される。 |- | WM_NCLBUTTONDOWN 等 || 非クライアント領域でのマウス入力時に送信される。 |} </center> <br> ==== WM_LBUTTONDOWN / WM_LBUTTONUP ==== * WM_LBUTTONDOWNメッセージ *: 左ボタンが押下された時に送信される。 * WM_LBUTTONUPメッセージ *: 左ボタンが離された時に送信される。 <br> <u>※注意</u><br> <u>WM_LBUTTONDOWNメッセージ と WM_LBUTTONUPメッセージ は、クライアント領域内でのマウス操作を検出する場合に使用する。</u><br> <br> <center> {| class="wikitable" |+ メッセージパラメータ |- ! パラメータ !! 説明 |- | wParam (nFlags) || ボタンと修飾キーの状態<br>(MK_LBUTTON、MK_CONTROL、MK_SHIFT等) |- | lParam (point) || マウスカーソルの位置 (クライアント座標)<br>下位ワード: X座標、上位ワード: Y座標 |} </center> <br> <center> {| class="wikitable" |+ nFlagsのビットフラグ |- ! フラグ !! 説明 |- | MK_LBUTTON || 左ボタンが押下されている |- | MK_RBUTTON || 右ボタンが押下されている |- | MK_MBUTTON || 中ボタンが押下されている |- | MK_CONTROL || Ctrlキーが押下されている |- | MK_SHIFT || Shiftキーが押下されている |} </center> <br> ==== WM_RBUTTONDOWN / WM_RBUTTONUP ==== * WM_RBUTTONDOWNメッセージ *: 右ボタンが押下された時に送信される。 * WM_RBUTTONUPメッセージ *: 右ボタンが離された時に送信される。 <br> 右クリックは、通常コンテキストメニューを表示するために使用される。<br> WM_RBUTTONUPメッセージのハンドラ内で、<code>TrackPopupMenu</code> 関数を呼び出してコンテキストメニューを表示する。<br> <br> メッセージパラメータは、WM_LBUTTONDOWN / WM_LBUTTONUPと同様である。<br> <br> ==== WM_MBUTTONDOWN / WM_MBUTTONUP ==== * WM_MBUTTONDOWNメッセージ *: 中ボタンが押下された時に送信される。 * WM_MBUTTONUPメッセージ *: 中ボタンが離された時に送信される。 <br> 中ボタンは、スクロール操作や特殊な機能のトリガーとして使用されることが多い。<br> 例えば、Webブラウザでは、中ボタンクリックで新しいタブでリンクを開く機能が実装されている。<br> <br> メッセージパラメータは、WM_LBUTTONDOWN / WM_LBUTTONUPと同様である。<br> <br> ==== WM_MOUSEMOVE ==== WM_MOUSEMOVEメッセージは、マウスカーソルがクライアント領域内で移動した時に送信される。<br> <br> このメッセージは、マウスカーソルの移動に伴って高頻度で送信されるため、処理内容は軽量に保つ必要がある。<br> 重い処理を実装すると、アプリケーションの応答性が低下する。<br> <br> WM_MOUSEMOVEメッセージは、以下の用途で使用される。<br> * ドラッグ操作の実装 * マウスカーソル追従型のツールチップ表示 * 描画アプリケーションのペン操作 * ホバー効果の実装 <br> メッセージパラメータは、他のマウスメッセージと同様に、wParamにボタン状態、lParamに座標が含まれる。<br> <br> ==== WM_MOUSEWHEEL ==== WM_MOUSEWHEELメッセージは、垂直マウスホイールが回転した時に送信される。<br> <br> <center> {| class="wikitable" |+ メッセージパラメータ |- ! パラメータ !! 説明 |- | wParam || 上位ワード : 回転量 (zDelta)<br>下位ワード : 修飾キーの状態 |- | lParam || マウスカーソルの位置 (スクリーン座標) |} </center> <br> zDelta (回転量) は、WHEEL_DELTA (120) の倍数で表現される。<br> * 正の値 *: ユーザーから見て手前方向 (上方向) への回転 * 負の値 *: ユーザーから見て奥方向 (下方向) への回転 <br> スクロール操作を実装する場合、zDeltaの正負を判定して、スクロール方向を決定する。<br> <br> <u>※注意</u><br> <u><code>WM_MOUSEWHEEL</code> メッセージの <code>lParam</code> は、スクリーン座標で提供されるため、クライアント座標への変換が必要である。</u><br> <br> ==== ダブルクリックメッセージ ==== * WM_LBUTTONDBLCLKメッセージ *: 左ボタンがダブルクリックされた時に送信される。 * WM_RBUTTONDBLCLKメッセージ *: 右ボタンがダブルクリックされた時に送信される。 * WM_MBUTTONDBLCLKメッセージ *: 中ボタンがダブルクリックされた時に送信される。 <br> ダブルクリックメッセージを受信するには、ウィンドウクラスに <code>CS_DBLCLKS</code> スタイルを設定する必要がある。<br> MFCのビュークラスやダイアログクラスでは、このスタイルがデフォルトで設定されている。<br> <br> ダブルクリックの時間間隔は、<code>GetDoubleClickTime</code> 関数で取得できる。<br> デフォルトでは500ミリ秒であり、<code>SetDoubleClickTime</code> 関数で変更できる。<br> <br> メッセージパラメータは、通常のボタンメッセージと同様である。<br> <br> ==== 非クライアント領域メッセージ ==== 非クライアント領域 (タイトルバー、フレーム、スクロールバー等) でのマウス操作は、別のメッセージとして処理される。<br> <br> * WM_NCLBUTTONDOWN *: 非クライアント領域で左ボタンが押下された時に送信される。 * WM_NCRBUTTONDOWN *: 非クライアント領域で右ボタンが押下された時に送信される。 * WM_NCMOUSEMOVE *: 非クライアント領域でマウスが移動した時に送信される。 <br> これらのメッセージは、通常システムがデフォルト処理を行うため、カスタム処理が必要な場合のみハンドラを定義する。<br> <br> ==== メッセージの処理フロー ==== マウスメッセージの処理フローを以下に示す。<br> <br> # ユーザがマウスを操作する。 # Windowsは、適切なマウスメッセージを生成する。 # メッセージは、カーソル位置のウィンドウに送信される。 # ウィンドウプロシージャは、メッセージハンドラを呼び出す。 # ハンドラ内で、マウス操作に応じた処理を実行する。 <br> この処理フローを理解することにより、適切なメッセージハンドラを選択することができる。<br> <br> クリック操作を処理する場合は、WM_LBUTTONUPメッセージを使用する。<br> ドラッグ操作を処理する場合は、WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUPの組み合わせを使用する。<br> <br><br> == マウス位置の取得 == マウスの位置を取得するには、複数の方法がある。<br> <br> <center> {| class="wikitable" |+ マウス位置取得の方法 |- ! 方法 !! 説明 |- | メッセージパラメータ (lParam) || マウスメッセージ内で提供されるクライアント座標 |- | GetCursorPos関数 || 現在のマウスカーソル位置をスクリーン座標で取得 |- | GET_X_LPARAM / GET_Y_LPARAMマクロ || lParamから座標を抽出 |} </center> <br> ==== GetCursorPos関数 ==== <code>GetCursorPos</code> 関数は、現在のマウスカーソル位置をスクリーン座標で取得する関数である。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> BOOL GetCursorPos(LPPOINT lpPoint); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) と 戻り値 |- ! 種別 !! 項目 !! 説明 |- | パラメータ || lpPoint || カーソル位置を受け取るPOINT構造体へのポインタ |- | 戻り値 || BOOL || 成功した場合はTRUE、失敗した場合はFALSE |} </center> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> POINT pt; GetCursorPos(&pt); CString str; str.Format(_T("カーソル位置 (スクリーン座標): x=%d, y=%d"), pt.x, pt.y); AfxMessageBox(str); </syntaxhighlight> <br> GetCursorPos関数は、スクリーン座標を返すため、クライアント座標への変換が必要な場合が多い。<br> <br> ==== ScreenToClient関数 / ClientToScreen関数 ==== 座標系の変換には、<code>ScreenToClient</code> 関数 と <code>ClientToScreen</code> 関数を使用する。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> BOOL ScreenToClient(HWND hWnd, LPPOINT lpPoint); BOOL ClientToScreen(HWND hWnd, LPPOINT lpPoint); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) |- ! 項目 !! 説明 |- | hWnd || 座標変換の基準となるウィンドウのハンドル |- | lpPoint || 変換する座標を持つPOINT構造体へのポインタ |} </center> <br> * ScreenToClient関数 *: スクリーン座標をクライアント座標に変換する。 * ClientToScreen関数 *: クライアント座標をスクリーン座標に変換する。 <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::ShowCursorPosition() { // スクリーン座標でカーソル位置を取得 POINT pt; GetCursorPos(&pt); // クライアント座標に変換 ScreenToClient(&pt); CString str; str.Format(_T("カーソル位置 (クライアント座標): x=%d, y=%d"), pt.x, pt.y); AfxMessageBox(str); } </syntaxhighlight> <br> MFCでは、CWndクラスのメンバ関数として <code>ScreenToClient</code> メソッド と <code>ClientToScreen</code> メソッド が提供されている。<br> <syntaxhighlight lang="c++"> POINT pt; GetCursorPos(&pt); ScreenToClient(&pt); // CWndのメンバ関数 </syntaxhighlight> <br> ==== GET_X_LPARAMマクロ / GET_Y_LPARAMマクロ ==== lParamから座標を抽出するには、<code>GET_X_LPARAM</code> マクロ と <code>GET_Y_LPARAM</code> マクロを使用する。<br> <br> これらのマクロは、<code>windowsx.h</code> ヘッダファイルで定義されている。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> #include <windowsx.h> LRESULT CMyView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_LBUTTONDOWN) { int xPos = GET_X_LPARAM(lParam); int yPos = GET_Y_LPARAM(lParam); CString str; str.Format(_T("クリック位置: x=%d, y=%d"), xPos, yPos); AfxMessageBox(str); } return CView::WindowProc(message, wParam, lParam); } </syntaxhighlight> <br> MFCのイベントハンドラでは、CPoint型のパラメータとして座標が提供されるため、これらのマクロは不要である。<br> <syntaxhighlight lang="c++"> void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { // pointは既にCPoint型で提供される CString str; str.Format(_T("クリック位置: x=%d, y=%d"), point.x, point.y); AfxMessageBox(str); CView::OnLButtonDown(nFlags, point); } </syntaxhighlight> <br><br> == マウスボタン状態の取得 == マウスボタンの状態を取得するには、複数の方法がある。<br> <br> <center> {| class="wikitable" |+ マウスボタン状態取得の方法 |- ! 方法 !! 説明 |- | nFlags (wParam) || マウスメッセージのパラメータから取得 |- | GetAsyncKeyState関数 || リアルタイムのボタン状態を取得 |} </center> <br> ==== nFlagsからのボタン状態取得 ==== マウスメッセージのwParamには、ボタンと修飾キーの状態が含まれる。<br> <br> ビットフラグを確認することにより、複数のボタンが同時に押下されているかを判定できる。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::OnMouseMove(UINT nFlags, CPoint point) { // 左ボタンが押下されている場合 if (nFlags & MK_LBUTTON) { // ドラッグ中の描画処理 DrawLine(point); } // 左ボタンと右ボタンが同時に押下されている場合 if ((nFlags & MK_LBUTTON) && (nFlags & MK_RBUTTON)) { // 特殊な操作 ZoomOperation(point); } // [Ctrl]キーを押下しながらドラッグしている場合 if ((nFlags & MK_LBUTTON) && (nFlags & MK_CONTROL)) { // コピー操作 CopyDrag(point); } CView::OnMouseMove(nFlags, point); } </syntaxhighlight> <br> nFlagsによるボタン状態の取得は、マウスメッセージハンドラ内で使用するのに適している。<br> <br> ==== GetAsyncKeyState関数 ==== <code>GetAsyncKeyState</code> 関数を使用すると、リアルタイムのマウスボタン状態を取得できる。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> SHORT GetAsyncKeyState(int vKey); </syntaxhighlight> <br> 下表に、マウスボタン用の仮想キーコードを示す。<br> <br> <center> {| class="wikitable" |+ マウスボタンの仮想キーコード |- ! 定数 !! 説明 |- | VK_LBUTTON || 左ボタン |- | VK_RBUTTON || 右ボタン |- | VK_MBUTTON || 中ボタン |} </center> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::OnTimer(UINT_PTR nIDEvent) { // タイマ内でマウスボタン状態を確認 if (GetAsyncKeyState(VK_LBUTTON) & 0x8000) { // 左ボタンが押下されている場合 m_isDragging = TRUE; } else { m_isDragging = FALSE; } // 中ボタンでスクロールモード if (GetAsyncKeyState(VK_MBUTTON) & 0x8000) { EnableScrollMode(); } CView::OnTimer(nIDEvent); } </syntaxhighlight> <br> GetAsyncKeyState関数は、マウスメッセージの外でボタン状態を確認する場合に便利である。<br> 例えば、タイマイベント内や、定期的なポーリング処理で使用する。<br> <br><br> == MFCでのマウスイベントハンドラ == MFCは、マウスメッセージを処理するための便利なメッセージハンドラを提供している。<br> <br> <center> {| class="wikitable" |+ 主要なマウスイベントハンドラ |- ! メソッド !! 説明 |- | OnLButtonDown<br>OnLButtonUp || WM_LBUTTONDOWN / WM_LBUTTONUPメッセージの処理 |- | OnRButtonDown<br>OnRButtonUp || WM_RBUTTONDOWN / WM_RBUTTONUPメッセージの処理 |- | OnMButtonDown<br>OnMButtonUp || WM_MBUTTONDOWN / WM_MBUTTONUPメッセージの処理 |- | OnMouseMove || WM_MOUSEMOVEメッセージの処理 |- | OnMouseWheel || WM_MOUSEWHEELメッセージの処理 |- | OnLButtonDblClk<br>OnRButtonDblClk || ダブルクリックメッセージの処理 |- | OnSetCursor || WM_SETCURSORメッセージの処理 |- | PreTranslateMessage || メッセージの前処理 |} </center> <br> ==== OnLButtonDown / OnLButtonUp ==== <code>OnLButtonDown</code> イベントハンドラ と <code>OnLButtonUp</code> イベントハンドラ は、左ボタンの押下と解放を処理するハンドラである。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) |- ! 項目 !! 説明 |- | nFlags || ボタンと修飾キーの状態<br>(MK_CONTROL、MK_SHIFT等) |- | point || マウスカーソルの位置 (クライアント座標) |} </center> <br> OnLButtonDownハンドラ と OnLButtonUpハンドラを使用することにより、クリック操作やドラッグ操作を実装できる。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { // ドラッグ開始 m_bDragging = TRUE; m_ptStart = point; // マウスキャプチャを開始 SetCapture(); CView::OnLButtonDown(nFlags, point); } void CMyView::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDragging) { // ドラッグ終了 m_bDragging = FALSE; // マウスキャプチャを解放 ReleaseCapture(); // ドラッグ完了処理 CompleteDrag(m_ptStart, point); } CView::OnLButtonUp(nFlags, point); } </syntaxhighlight> <br> 右ボタン (OnRButtonDown / OnRButtonUp) と 中ボタン (OnMButtonDown / OnMButtonUp) も同様のシグネチャを持つ。<br> <br> ==== OnMouseMove ==== <code>OnMouseMove</code> イベントハンドラは、マウス移動を処理するハンドラである。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> afx_msg void OnMouseMove(UINT nFlags, CPoint point); </syntaxhighlight> <br> <center> {| class="wikitable" |+ パラメータ |- ! 項目 !! 説明 |- | nFlags || ボタンと修飾キーの状態 |- | point || マウスカーソルの位置 (クライアント座標) |} </center> <br> OnMouseMoveハンドラは、ドラッグ操作や描画操作を実装する場合に使用する。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::OnMouseMove(UINT nFlags, CPoint point) { // ドラッグ中の場合 if (m_bDragging && (nFlags & MK_LBUTTON)) { // 線を描画 CClientDC dc(this); dc.MoveTo(m_ptPrev); dc.LineTo(point); m_ptPrev = point; } // カーソル位置を表示 CString str; str.Format(_T("X: %d, Y: %d"), point.x, point.y); GetParent()->SetWindowText(str); CView::OnMouseMove(nFlags, point); } </syntaxhighlight> <br> <u>※注意</u><br> <u>OnMouseMoveは高頻度で呼び出されるため、処理は軽量に保つ必要がある。</u><br> <u>重い処理を実装すると、マウス追従が遅延し、ユーザ体験が低下する。</u><br> <br> ==== OnMouseWheel ==== <code>OnMouseWheel</code> イベントハンドラは、マウスホイール回転を処理するハンドラである。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) |- ! 項目 !! 説明 |- | nFlags || 修飾キーの状態<br>(MK_CONTROL、MK_SHIFT等) |- | zDelta || ホイールの回転量<br>正の値: 手前方向 (上方向)、負の値: 奥方向 (下方向) |- | pt || マウスカーソルの位置 (スクリーン座標) |} </center> <br> zDeltaは、<u>WHEEL_DELTA (120)</u> の倍数で提供される。<br> 通常のスクロールでは、1ノッチ (1クリック) で120の値が渡される。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> BOOL CMyView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // スクリーン座標をクライアント座標に変換 ScreenToClient(&pt); // ホイールの回転量に応じてスクロール int scrollLines = zDelta / WHEEL_DELTA; if (zDelta > 0) { // 上にスクロール ScrollUp(scrollLines); } else { // 下にスクロール ScrollDown(abs(scrollLines)); } // [Ctrl]キーを押下しながらホイール回転でズーム if (nFlags & MK_CONTROL) { if (zDelta > 0) { ZoomIn(); } else { ZoomOut(); } } return CView::OnMouseWheel(nFlags, zDelta, pt); } </syntaxhighlight> <br> ==== OnSetCursor ==== <code>OnSetCursor</code> イベントハンドラは、マウスカーソルの形状を変更するハンドラである。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) |- ! 項目 !! 説明 |- | pWnd || カーソルを含むウィンドウへのポインタ |- | nHitTest || ヒットテストコード (HTCLIENT等) |- | message || マウスメッセージ |} </center> <br> OnSetCursorハンドラは、マウスカーソルの形状をカスタマイズする場合に使用する。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // クライアント領域内の場合 if (nHitTest == HTCLIENT) { // 編集モードの場合は十字カーソル if (m_bEditMode) { SetCursor(LoadCursor(NULL, IDC_CROSS)); return TRUE; } // リサイズモードの場合はサイズ変更カーソル if (m_bResizeMode) { SetCursor(LoadCursor(NULL, IDC_SIZEALL)); return TRUE; } } return CView::OnSetCursor(pWnd, nHitTest, message); } </syntaxhighlight> <br> OnSetCursorハンドラがTRUEを返す場合、カーソルの変更を処理済みとして扱う。<br> FALSEを返す場合、デフォルトのカーソル処理が実行される。<br> <br> ==== PreTranslateMessageメソッド ==== <code>PreTranslateMessage</code> メソッドは、メッセージがディスパッチされる前に呼び出されるメソッドである。<br> このメソッドをオーバーライドすることにより、メッセージの前処理やフィルタリングを実装できる。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> virtual BOOL PreTranslateMessage(MSG* pMsg); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) と 戻り値 |- ! 種別 !! 項目 !! 説明 |- | パラメータ || pMsg || メッセージ構造体へのポインタ |- | rowspan="2" | 戻り値 || TRUE || メッセージを処理済み (DispatchMessageに渡さない) |- | FALSE || メッセージを通常通り処理 (DispatchMessageに渡す) |} </center> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> BOOL CMyView::PreTranslateMessage(MSG* pMsg) { // 右クリックを無効化 if (pMsg->message == WM_RBUTTONDOWN) { return TRUE; // メッセージを消費 } // マウスホイールの処理をカスタマイズ if (pMsg->message == WM_MOUSEWHEEL) { // カスタム処理 CustomWheelHandler(pMsg); return TRUE; } return CView::PreTranslateMessage(pMsg); } </syntaxhighlight> <br> PreTranslateMessageメソッドは、マウス操作のデフォルト動作を変更する場合に有用である。<br> <br><br> == マウスカーソル == マウスカーソルの形状を制御することにより、ユーザに視覚的なフィードバックを提供できる。<br> <br> <center> {| class="wikitable" |+ カーソル制御の方法 |- ! 方法 !! 説明 |- | SetCursor関数 || カーソルを即座に変更 |- | LoadCursor関数 || システムカーソルまたはカスタムカーソルをロード |- | OnSetCursorハンドラ || WM_SETCURSORメッセージで動的にカーソルを変更 |} </center> <br> ==== システム定義カーソル ==== Windowsは、複数の標準カーソルを提供している。<br> <br> <center> {| class="wikitable" |+ 主要なシステムカーソル |- ! 定数 !! 説明 |- | IDC_ARROW || 標準の矢印カーソル |- | IDC_IBEAM || テキスト選択用のIビームカーソル |- | IDC_WAIT || 待機中を示す砂時計カーソル |- | IDC_CROSS || 十字カーソル |- | IDC_HAND || ハンドカーソル (リンクの上等) |- | IDC_SIZEALL || 4方向サイズ変更カーソル |- | IDC_SIZENESW || 右上/左下方向サイズ変更カーソル |- | IDC_SIZENS || 垂直方向サイズ変更カーソル |- | IDC_SIZENWSE || 左上/右下方向サイズ変更カーソル |- | IDC_SIZEWE || 水平方向サイズ変更カーソル |- | IDC_NO || 禁止カーソル |- | IDC_APPSTARTING || 作業中カーソル (矢印+砂時計) |} </center> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::ChangeCursor(int cursorType) { HCURSOR hCursor = NULL; switch (cursorType) { case 0: hCursor = LoadCursor(NULL, IDC_ARROW); break; case 1: hCursor = LoadCursor(NULL, IDC_CROSS); break; case 2: hCursor = LoadCursor(NULL, IDC_HAND); break; case 3: hCursor = LoadCursor(NULL, IDC_WAIT); break; } if (hCursor != NULL) { SetCursor(hCursor); } } </syntaxhighlight> <br> ==== カスタムカーソル ==== カスタムカーソルをリソースファイルから読み込む方法を以下に示す。<br> <br> <syntaxhighlight lang="c++"> // カスタムカーソルをロード (IDC_MYCURSORはリソースID) HCURSOR hCustomCursor = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_MYCURSOR)); if (hCustomCursor != NULL) { SetCursor(hCustomCursor); } </syntaxhighlight> <br> カーソルファイル (.cur) から直接ロードする方法を以下に示す。<br> <syntaxhighlight lang="c++"> HCURSOR hCursor = LoadCursorFromFile(_T("C:\\Cursors\\mycursor.cur")); if (hCursor != NULL) { SetCursor(hCursor); } </syntaxhighlight> <br> ==== WM_SETCURSORメッセージ ==== WM_SETCURSORメッセージは、マウスカーソルの形状を変更する必要がある時に送信される。<br> <br> OnSetCursorハンドラをオーバーライドすることにより、動的にカーソルを変更できる。<br> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if (nHitTest == HTCLIENT) { CPoint pt; GetCursorPos(&pt); ScreenToClient(&pt); // 特定の領域の上にカーソルがある場合 if (m_hotRect.PtInRect(pt)) { SetCursor(LoadCursor(NULL, IDC_HAND)); return TRUE; } } return CView::OnSetCursor(pWnd, nHitTest, message); } </syntaxhighlight> <br> ==== 待機カーソルの表示 ==== MFCは、待機カーソルを簡単に表示するためのメソッドを提供している。<br> <br> * BeginWaitCursor *: 待機カーソル (砂時計) を表示する。 * EndWaitCursor *: 待機カーソルを元に戻す。 <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void CMyView::LongOperation() { BeginWaitCursor(); // 待機カーソル表示 // 長時間かかる処理 for (int i = 0; i < 10000; i++) { ProcessData(i); } EndWaitCursor(); // 元のカーソルに戻す } </syntaxhighlight> <br> CWaitCursorクラスを使用すると、スコープベースで自動的にカーソルを管理できる。<br> <syntaxhighlight lang="c++"> void CMyView::LongOperation() { CWaitCursor wait; // コンストラクタで待機カーソル表示 // 長時間かかる処理 ProcessData(); // デストラクタで自動的に元のカーソルに戻る } </syntaxhighlight> <br><br> == マウスキャプチャ == マウスキャプチャは、特定のウィンドウが全てのマウス入力を受け取る機能である。<br> <br> キャプチャを開始すると、マウスカーソルがウィンドウの外に出ても、そのウィンドウがマウスメッセージを受信し続ける。<br> この機能は、ドラッグ操作の実装に不可欠である。<br> <br> <center> {| class="wikitable" |+ マウスキャプチャの関数 |- ! 関数 !! 説明 |- | SetCapture || マウスキャプチャを開始 |- | ReleaseCapture || マウスキャプチャを解放 |- | GetCapture || 現在キャプチャしているウィンドウを取得 |} </center> <br> ==== SetCapture / ReleaseCapture / GetCapture ==== 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> HWND SetCapture(HWND hWnd); BOOL ReleaseCapture(void); HWND GetCapture(void); </syntaxhighlight> <br> * SetCapture *: マウスキャプチャを開始する。 *: すべてのマウス入力が指定されたウィンドウに送信されるようになる。 * ReleaseCapture *: マウスキャプチャを解放する。 * GetCapture *: 現在マウスキャプチャを行っているウィンドウのハンドルを返す。 <br> MFCでは、CWndクラスのメンバ関数として提供されている。<br> <syntaxhighlight lang="c++"> CWnd* SetCapture(); static BOOL PASCAL ReleaseCapture(); static CWnd* PASCAL GetCapture(); </syntaxhighlight> <br> ==== ドラッグ操作の実装例 ==== マウスキャプチャを使用したドラッグ操作の実装例を以下に示す。<br> <br> <syntaxhighlight lang="c++"> class CMyView : public CView { protected: BOOL m_bDragging; // ドラッグ中かどうか CPoint m_ptStart; // ドラッグ開始位置 CPoint m_ptCurrent; // 現在の位置 public: CMyView() : m_bDragging(FALSE) {} afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() }; void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { // ドラッグ開始 m_bDragging = TRUE; m_ptStart = point; m_ptCurrent = point; // マウスキャプチャを開始 SetCapture(); CView::OnLButtonDown(nFlags, point); } void CMyView::OnMouseMove(UINT nFlags, CPoint point) { if (m_bDragging) { // ドラッグ中の処理 CClientDC dc(this); // 前回の矩形を消去 (XORモード) dc.SetROP2(R2_NOTXORPEN); dc.Rectangle(m_ptStart.x, m_ptStart.y, m_ptCurrent.x, m_ptCurrent.y); // 新しい矩形を描画 m_ptCurrent = point; dc.Rectangle(m_ptStart.x, m_ptStart.y, m_ptCurrent.x, m_ptCurrent.y); } CView::OnMouseMove(nFlags, point); } void CMyView::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bDragging) { // ドラッグ終了 m_bDragging = FALSE; // マウスキャプチャを解放 ReleaseCapture(); // 最終的な矩形を確定 CRect rect(m_ptStart, point); rect.NormalizeRect(); // 矩形を描画 DrawFinalRectangle(rect); } CView::OnLButtonUp(nFlags, point); } </syntaxhighlight> <br> <u>※注意</u><br> <u>マウスキャプチャを開始した場合、必ずReleaseCapture関数で解放する必要がある。</u><br> <u>解放しないと、他のウィンドウがマウス入力を受け取れなくなる。</u><br> <br> マウスキャプチャは、以下の用途で使用される。<br> * ドラッグアンドドロップ操作 * リサイズ操作 * 描画ツールでのペン操作 * スライダーやスクロールバーのドラッグ <br><br> == マウストラッキング == マウストラッキングは、マウスカーソルがウィンドウに入った時や出た時、ホバーした時を検出する機能である。<br> <br> <code>TrackMouseEvent</code> 関数を使用して、WM_MOUSELEAVE と WM_MOUSEHOVER メッセージを受信できる。<br> <br> ==== TrackMouseEvent関数 ==== TrackMouseEvent関数は、マウストラッキングを開始する関数である。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> BOOL TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack); </syntaxhighlight> <br> TRACKMOUSEEVENT構造体を以下に示す。<br> <syntaxhighlight lang="c++"> typedef struct tagTRACKMOUSEEVENT { DWORD cbSize; DWORD dwFlags; HWND hwndTrack; DWORD dwHoverTime; } TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT; </syntaxhighlight> <br> <center> {| class="wikitable" |+ TRACKMOUSEEVENT構造体のメンバ |- ! メンバ !! 説明 |- | cbSize || 構造体のサイズ |- | dwFlags || トラッキングフラグ (TME_LEAVE、TME_HOVER等) |- | hwndTrack || トラッキング対象のウィンドウハンドル |- | dwHoverTime || ホバーまでの時間 (ミリ秒) |} </center> <br> <center> {| class="wikitable" |+ dwFlagsの値 |- ! フラグ !! 説明 |- | TME_LEAVE || マウスがウィンドウを離れた時にWM_MOUSELEAVEを送信 |- | TME_HOVER || マウスがホバーした時にWM_MOUSEHOVERを送信 |- | TME_CANCEL || トラッキングをキャンセル |} </center> <br> ==== WM_MOUSELEAVE / WM_MOUSEHOVER ==== * WM_MOUSELEAVEメッセージ *: マウスカーソルがウィンドウのクライアント領域から出た時に送信される。 * WM_MOUSEHOVERメッセージ *: マウスカーソルが指定時間静止した時に送信される。 <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> class CMyView : public CView { protected: BOOL m_bTracking; // トラッキング中かどうか public: CMyView() : m_bTracking(FALSE) {} afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CMyView, CView) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) END_MESSAGE_MAP() void CMyView::OnMouseMove(UINT nFlags, CPoint point) { if (!m_bTracking) { // トラッキングを開始 TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE | TME_HOVER; tme.hwndTrack = m_hWnd; tme.dwHoverTime = 1000; // 1秒 if (TrackMouseEvent(&tme)) { m_bTracking = TRUE; } } CView::OnMouseMove(nFlags, point); } LRESULT CMyView::OnMouseLeave(WPARAM wParam, LPARAM lParam) { // マウスがウィンドウを離れた m_bTracking = FALSE; // ホバー効果を解除 ClearHoverEffect(); return 0; } LRESULT CMyView::OnMouseHover(WPARAM wParam, LPARAM lParam) { // マウスがホバーした // ツールチップやホバー効果を表示 ShowTooltip(); // 再度ホバーメッセージを受け取るには、TrackMouseEventを再度呼び出す m_bTracking = FALSE; return 0; } </syntaxhighlight> <br> マウストラッキングは、以下の用途で使用される。<br> * ホバー効果の実装 (ボタンの色変更等) * ツールチップの表示 * マウスがウィンドウを離れた時のクリーンアップ処理 * カスタムコントロールの視覚フィードバック <br><br> == マウス入力のシミュレーション == プログラムから仮想的にマウス入力を生成する技術を、マウス入力のシミュレーションという。<br> <br> Windowsでは、<code>SendInput</code> 関数 と <code>mouse_event</code> 関数の2つの方法がある。<br> <br> * SendInput関数 *: Windows 2000以降で推奨される方法である。 * mouse_event関数 *: レガシーな方法であり、互換性のために残されている。 <br> ==== SendInput関数 ==== SendInput関数は、キーボードやマウスの入力イベントを合成する関数である。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> UINT SendInput( UINT nInputs, LPINPUT pInputs, int cbSize ); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) |- ! 項目 !! 説明 |- | nInputs || 入力イベントの数 |- | pInputs || INPUT構造体の配列 |- | cbSize || INPUT構造体のサイズ |} </center> <br> INPUT構造体とMOUSEINPUT構造体を以下に示す。<br> <syntaxhighlight lang="c++"> typedef struct tagINPUT { DWORD type; // INPUT_MOUSE、INPUT_KEYBOARD等 union { MOUSEINPUT mi; KEYBDINPUT ki; HARDWAREINPUT hi; }; } INPUT, *PINPUT; typedef struct tagMOUSEINPUT { LONG dx; LONG dy; DWORD mouseData; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } MOUSEINPUT, *PMOUSEINPUT; </syntaxhighlight> <br> <center> {| class="wikitable" |+ MOUSEINPUTのメンバ |- ! メンバ !! 説明 |- | dx || X方向の移動量 (または絶対座標) |- | dy || Y方向の移動量 (または絶対座標) |- | mouseData || ホイール回転量やボタンデータ |- | dwFlags || イベントフラグ (MOUSEEVENTF_LEFTDOWN等) |- | time || タイムスタンプ (0で自動設定) |- | dwExtraInfo || 追加情報 |} </center> <br> <center> {| class="wikitable" |+ dwFlagsの主要な値 |- ! フラグ !! 説明 |- | MOUSEEVENTF_MOVE || マウス移動 |- | MOUSEEVENTF_LEFTDOWN || 左ボタン押下 |- | MOUSEEVENTF_LEFTUP || 左ボタン解放 |- | MOUSEEVENTF_RIGHTDOWN || 右ボタン押下 |- | MOUSEEVENTF_RIGHTUP || 右ボタン解放 |- | MOUSEEVENTF_MIDDLEDOWN || 中ボタン押下 |- | MOUSEEVENTF_MIDDLEUP || 中ボタン解放 |- | MOUSEEVENTF_WHEEL || 垂直ホイール回転 |- | MOUSEEVENTF_HWHEEL || 水平ホイール回転 |- | MOUSEEVENTF_ABSOLUTE || dx, dyを絶対座標として扱う |} </center> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void SendMouseClick(int x, int y) { INPUT inputs[3] = {}; // マウス移動 inputs[0].type = INPUT_MOUSE; inputs[0].mi.dx = x * (65535 / GetSystemMetrics(SM_CXSCREEN)); inputs[0].mi.dy = y * (65535 / GetSystemMetrics(SM_CYSCREEN)); inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; // 左ボタン押下 inputs[1].type = INPUT_MOUSE; inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN; // 左ボタン解放 inputs[2].type = INPUT_MOUSE; inputs[2].mi.dwFlags = MOUSEEVENTF_LEFTUP; // 入力イベントの送信 UINT uSent = SendInput(3, inputs, sizeof(INPUT)); if (uSent != 3) { AfxMessageBox(_T("SendInputに失敗しました")); } } </syntaxhighlight> <br> マウスホイール回転をシミュレートする例を以下に示す。<br> <syntaxhighlight lang="c++"> void SendMouseWheelRotation(int delta) { INPUT input = {}; input.type = INPUT_MOUSE; input.mi.mouseData = delta; // 通常はWHEEL_DELTA (120) の倍数 input.mi.dwFlags = MOUSEEVENTF_WHEEL; SendInput(1, &input, sizeof(INPUT)); } // 使用例 void CMyView::SimulateWheelUp() { SendMouseWheelRotation(WHEEL_DELTA); // 上方向に1ノッチ } </syntaxhighlight> <br> ==== mouse_event関数 ==== mouse_event関数は、レガシーなマウス入力シミュレーション関数である。<br> <br> 関数のプロトタイプを以下に示す。<br> <syntaxhighlight lang="c++"> VOID mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo ); </syntaxhighlight> <br> <center> {| class="wikitable" |+ 引数 (パラメータ) |- ! 項目 !! 説明 |- | dwFlags || イベントフラグ<br>(MOUSEEVENTF_LEFTDOWN等) |- | dx || X方向の移動量 (または絶対座標) |- | dy || Y方向の移動量 (または絶対座標) |- | dwData || ホイール回転量やボタンデータ |- | dwExtraInfo || 追加情報<br>(通常は0) |} </center> <br> 使用例を以下に示す。<br> <syntaxhighlight lang="c++"> void SendMouseClickLegacy(int x, int y) { // マウス移動 mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, x * (65535 / GetSystemMetrics(SM_CXSCREEN)), y * (65535 / GetSystemMetrics(SM_CYSCREEN)), 0, 0); // 左ボタン押下 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); // 左ボタン解放 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); } </syntaxhighlight> <br> <u>※注意</u><br> <u>mouse_event関数は、Windows 2000以降では非推奨とされている。</u><br> <u>新規開発では、SendInput関数の使用を推奨する。</u><br> <br> マウス入力のシミュレーションは、自動化ツール、テストツール、マクロツール、リモート操作ツールなどの実装に利用される。<br> ただし、セキュリティ上の理由から、使用には注意が必要である。<br> <br><br> == 関連リンク == * [https://learn.microsoft.com/en-us/windows/win32/inputdev/mouse-input Microsoft Docs - Mouse Input] * [https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput Microsoft Docs - SendInput function] * [https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-trackmouseevent Microsoft Docs - TrackMouseEvent function] * [https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcapture Microsoft Docs - SetCapture function] <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,MFC,C++,Mouse,マウス,Windows,Programming,Mouse Click,Mouse Move,Mouse Wheel,Drag,Capture,Cursor,マウスカーソル,ドラッグ |description={{PAGENAME}} - MFC/C++におけるマウス処理の包括的なガイド |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:MFC]]
MFCの基礎 - マウス
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse