マウスの動き
マウスが移動すると、Windows は WM_MOUSEMOVE メッセージを投稿します。 既定では、WM_MOUSEMOVE カーソルを含むウィンドウに移動します。 この動作は、次のセクションで説明するマウス キャプチャ することでオーバーライドできます。
WM_MOUSEMOVE メッセージには、マウス クリックのメッセージと同じパラメーターが含まれています。 lParam の下位 16 ビットには x 座標が含まれており、次の 16 ビットには y 座標が含まれます。 GET_X_LPARAM マクロと GET_Y_LPARAM マクロを使用して、lParamから座標をアンパックします。 wParam パラメーターには、フラグのビットごとの または が含まれています。これは、他のマウス ボタンの状態に Shift キーと Ctrl キーを加えた状態を示します。 次のコードは、lParam からマウス座標取得します。
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
これらの座標はピクセル単位であり、デバイスに依存しないピクセル (DIP) ではないことに注意してください。 このトピックの後半では、2 つのユニット間で変換するコードについて説明します。
また、ウィンドウに対してカーソルの位置が変わると、ウィンドウは WM_MOUSEMOVE メッセージを受け取ることもできます。 たとえば、カーソルがウィンドウの上に配置されていて、ユーザーがウィンドウを非表示にした場合、マウスが移動しなかった場合でも、ウィンドウは WM_MOUSEMOVE メッセージを受け取ります。 この動作の 1 つの結果は、WM_MOUSEMOVE メッセージ間でマウス座標が変わらない可能性があるということです。
ウィンドウの外側でマウスの動きをキャプチャする
既定では、マウスがクライアント領域の端を越えて移動すると、ウィンドウは WM_MOUSEMOVE メッセージの受信を停止します。 ただし、一部の操作では、このポイントを超えてマウスの位置を追跡することが必要な場合があります。 たとえば、描画プログラムを使用すると、次の図に示すように、選択した四角形をウィンドウの端の向こうにドラッグできます。
マウス キャプチャの図を
ウィンドウの端を越えてマウス移動メッセージを受信するには、SetCapture 関数を呼び出します。 この関数が呼び出されると、ユーザーが少なくとも 1 つのマウス ボタンを押しながらウィンドウの外に移動した場合でも、ウィンドウは引き続き WM_MOUSEMOVE メッセージを受信します。 キャプチャ ウィンドウはフォアグラウンド ウィンドウである必要があり、一度にキャプチャ ウィンドウにできるのは 1 つのウィンドウのみです。 マウス キャプチャを解放するには、ReleaseCapture 関数を呼び出します。
通常は、次の方法 SetCapture と ReleaseCapture使用します。
- ユーザーがマウスの左ボタンを押すと、SetCapture呼び出して、マウスのキャプチャを開始します。
- マウス移動メッセージに応答します。
- ユーザーがマウスの左ボタンを離したら、ReleaseCapture呼び出します。
例: 円の描画
ユーザーがマウスで円を描画できるようにすることで、モジュール 3 から Circle プログラムを拡張してみましょう。
Direct2D Circle サンプル プログラムから開始します。 このサンプルのコードを変更して、単純な描画を追加します。 まず、MainWindow
クラスに新しいメンバー変数を追加します。
D2D1_POINT_2F ptMouse;
この変数は、ユーザーがマウスをドラッグしている間のマウスの下向きの位置を格納します。
MainWindow
コンストラクターで、省略記号の を初期化し、ptMouse 変数を します。
MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL),
ellipse(D2D1::Ellipse(D2D1::Point2F(), 0, 0)),
ptMouse(D2D1::Point2F())
{
}
MainWindow::CalculateLayout
メソッドの本体を削除します。この例では必要ありません。
void CalculateLayout() { }
次に、左ボタンダウン、左ボタンアップ、マウス移動メッセージのメッセージ ハンドラーを宣言します。
void OnLButtonDown(int pixelX, int pixelY, DWORD flags);
void OnLButtonUp();
void OnMouseMove(int pixelX, int pixelY, DWORD flags);
マウス座標は物理ピクセル単位で指定されますが、Direct2D ではデバイスに依存しないピクセル (DIP) が必要です。 高 DPI 設定を正しく処理するには、ピクセル座標を DIP に変換する必要があります。 DPI の詳細については、「DPI と Device-Independent ピクセルの 」を参照してください。 次のコードは、ピクセルを DIP に変換するヘルパー クラスを示しています。
class DPIScale
{
static float scale;
public:
static void Initialize(HWND hwnd)
{
float dpi = GetDpiForWindow(hwnd);
scale = dpi/96.0f;
}
template <typename T>
static D2D1_POINT_2F PixelsToDips(T x, T y)
{
return D2D1::Point2F(static_cast<float>(x) / scale, static_cast<float>(y) / scale);
}
};
float DPIScale::scale = 1.0f;
Direct2D ファクトリ オブジェクト 作成した後、WM_CREATE ハンドラーで DPIScale::Initialize を呼び出します。
case WM_CREATE:
if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
{
return -1; // Fail CreateWindowEx.
}
DPIScale::Initialize(hwnd);
return 0;
マウス メッセージから DIP のマウス座標を取得するには、次の操作を行います。
- ピクセル座標を取得するには、GET_X_LPARAM マクロと GET_Y_LPARAM マクロを使用します。 これらのマクロは WindowsX.h で定義されているため、必ずプロジェクトにそのヘッダーを含めます。
- ピクセルを DIP に変換するには、
DPIScale::PixelsToDips
を呼び出します。
次に、メッセージ ハンドラーをウィンドウ プロシージャに追加します。
case WM_LBUTTONDOWN:
OnLButtonDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
return 0;
case WM_LBUTTONUP:
OnLButtonUp();
return 0;
case WM_MOUSEMOVE:
OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
return 0;
最後に、メッセージ ハンドラー自体を実装します。
左ボタンの下
左ボタンの下向きメッセージの場合は、次の操作を行います。
- SetCapture呼び出して、マウスのキャプチャを開始します。
- マウス クリックの位置を ptMouse 変数に格納します。 この位置は、楕円の境界ボックスの左上隅を定義します。
- 楕円構造をリセットします。
- InvalidateRect呼び出します。 この関数は、ウィンドウを強制的に再描画します。
void MainWindow::OnLButtonDown(int pixelX, int pixelY, DWORD flags)
{
SetCapture(m_hwnd);
ellipse.point = ptMouse = DPIScale::PixelsToDips(pixelX, pixelY);
ellipse.radiusX = ellipse.radiusY = 1.0f;
InvalidateRect(m_hwnd, NULL, FALSE);
}
マウスの移動
マウス移動メッセージの場合は、マウスの左ボタンが下にあるかどうかを確認します。 その場合は、楕円を再計算し、ウィンドウを再描画します。 Direct2D では、楕円は中心点と x および y 半径によって定義されます。 省略記号の幅、高さ、位置を検索するには、マウスの下向きポイント (ptMouse) と現在のカーソル位置 (x、y) に適合する楕円を描画します。
次のコードは省略記号を再計算し、InvalidateRect呼び出してウィンドウを再描画します。
void MainWindow::OnMouseMove(int pixelX, int pixelY, DWORD flags)
{
if (flags & MK_LBUTTON)
{
const D2D1_POINT_2F dips = DPIScale::PixelsToDips(pixelX, pixelY);
const float width = (dips.x - ptMouse.x) / 2;
const float height = (dips.y - ptMouse.y) / 2;
const float x1 = ptMouse.x + width;
const float y1 = ptMouse.y + height;
ellipse = D2D1::Ellipse(D2D1::Point2F(x1, y1), width, height);
InvalidateRect(m_hwnd, NULL, FALSE);
}
}
左ボタンを上へ
左ボタンアップ メッセージの場合は、ReleaseCapture呼び出してマウス キャプチャを解放するだけです。
void MainWindow::OnLButtonUp()
{
ReleaseCapture();
}
次に
- その他のマウス操作 を する