다음을 통해 공유


마우스 이동

마우스가 이동하면 Windows에서 WM_MOUSEMOVE 메시지를 게시합니다. 기본적으로 WM_MOUSEMOVE 커서가 포함된 창으로 이동합니다. 다음 섹션에서 설명하는 마우스를 캡처하는 이 동작을 재정의할 수 있습니다.

WM_MOUSEMOVE 메시지에는 마우스 클릭에 대한 메시지와 동일한 매개 변수가 포함됩니다. 가장 낮은 16비트 lParam x 좌표를 포함하고 다음 16비트에서는 y 좌표를 포함합니다. GET_X_LPARAMGET_Y_LPARAM 매크로를 사용하여 lParam좌표의 압축을 풉니다. wParam 매개 변수에는 다른 마우스 단추의 상태와 Shift 및 Ctrl 키를 나타내는 플래그의 비트 OR 포함되어 있습니다. 다음 코드는 lParam마우스 좌표를 가져옵니다.

int xPos = GET_X_LPARAM(lParam); 
int yPos = GET_Y_LPARAM(lParam);

이러한 좌표는 디바이스 독립적 픽셀(DIP)이 아닌 픽셀 단위입니다. 이 항목의 뒷부분에서는 두 단위 간에 변환되는 코드를 살펴보겠습니다.

창에 상대적으로 커서의 위치가 변경되면 창에서 WM_MOUSEMOVE 메시지를 받을 수도 있습니다. 예를 들어 커서가 창 위에 배치되고 사용자가 창을 숨기면 마우스가 움직이지 않더라도 창에 WM_MOUSEMOVE 메시지가 표시됩니다. 이 동작의 한 가지 결과는 마우스 좌표가 WM_MOUSEMOVE 메시지 간에 변경되지 않을 수 있다는 것입니다.

창 밖에서 마우스 이동 캡처

기본적으로 마우스가 클라이언트 영역의 가장자리를 지나면 창에서 WM_MOUSEMOVE 메시지 수신을 중지합니다. 그러나 일부 작업의 경우 이 시점 이후의 마우스 위치를 추적해야 할 수 있습니다. 예를 들어 그리기 프로그램을 사용하면 다음 다이어그램과 같이 선택 영역 사각형을 창 가장자리 너머로 끌 수 있습니다.

마우스 캡처의 그림을 .

창 가장자리를 지나 마우스 이동 메시지를 받으려면 SetCapture 함수를 호출합니다. 이 함수가 호출되면 마우스가 창 밖으로 이동하더라도 사용자가 하나 이상의 마우스 단추를 누른 경우 창에서 WM_MOUSEMOVE 메시지가 계속 수신됩니다. 캡처 창은 포그라운드 창이어야 하며 한 번에 하나의 창만 캡처 창이 될 수 있습니다. 마우스 캡처를 해제하려면 ReleaseCapture 함수를 호출합니다.

일반적으로 SetCapture 사용하고 다음과 같은 방법으로 ReleaseCapture.

  1. 사용자가 왼쪽 마우스 단추를 누르면 SetCapture 호출하여 마우스 캡처를 시작합니다.
  2. 마우스 이동 메시지에 응답합니다.
  3. 사용자가 마우스 왼쪽 단추를 놓으면 ReleaseCapture호출합니다.

예: 원 그리기

사용자가 마우스로 원을 그릴 수 있도록 하여 모듈 3 원 프로그램을 확장해 보겠습니다. 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 Pixels참조하세요. 다음 코드는 픽셀을 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의 마우스 좌표를 얻으려면 다음을 수행합니다.

  1. GET_X_LPARAMGET_Y_LPARAM 매크로를 사용하여 픽셀 좌표를 가져옵니다. 이러한 매크로는 WindowsX.h에 정의되어 있으므로 프로젝트에 해당 헤더를 포함해야 합니다.
  2. DPIScale::PixelsToDips 호출하여 픽셀을 DIP로 변환합니다.

이제 창 프로시저에 메시지 처리기를 추가합니다.

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;

마지막으로 메시지 처리기 자체를 구현합니다.

왼쪽 단추 아래쪽

왼쪽 단추 아래쪽 메시지의 경우 다음을 수행합니다.

  1. SetCapture 호출하여 마우스 캡처를 시작합니다.
  2. 마우스 클릭 위치를 ptMouse 변수에 저장합니다. 이 위치는 줄임표에 대한 경계 상자의 왼쪽 위 모서리를 정의합니다.
  3. 타원 구조를 다시 설정합니다.
  4. 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-radii로 정의됩니다. 마우스 아래쪽 점(ptMouse)과 현재 커서 위치(x, y)로 정의된 경계 상자에 맞는 타원을 그리려고 하므로 줄임표의 너비, 높이 및 위치를 찾으려면 약간의 산술 연산이 필요합니다.

다음 코드는 줄임표를 다시 계산한 다음 InvalidateRect 호출하여 창을 다시 칠합니다.

x 및 y 반경이 있는 타원을 보여 주는 다이어그램

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(); 
}

다음

  • 다른 마우스 작업