Freigeben über


Mausbewegung

Wenn die Maus bewegt wird, sendet Windows eine WM_MOUSEMOVE Nachricht. Standardmäßig wechselt WM_MOUSEMOVE zum Fenster, das den Cursor enthält. Sie können dieses Verhalten außer Kraft setzen, indem Sie erfassen maus, die im nächsten Abschnitt beschrieben wird.

Die WM_MOUSEMOVE Nachricht enthält dieselben Parameter wie die Nachrichten für Mausklicks. Die niedrigsten 16 Bits von lParam enthalten die x-Koordinate, und die nächsten 16 Bit enthalten die Y-Koordinate. Verwenden Sie die GET_X_LPARAM und GET_Y_LPARAM Makros, um die Koordinaten aus lParam-zu entpacken. Der wParam--Parameter enthält einen bitweisen ODER von Flags, der den Status der anderen Maustasten sowie die UMSCHALT- und STRG-TASTE angibt. Der folgende Code ruft die Mauskoordinaten von lParamab.

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

Denken Sie daran, dass sich diese Koordinaten in Pixeln befinden, nicht geräteunabhängige Pixel (DIPs). Später in diesem Thema befassen wir uns mit Code, der zwischen den beiden Einheiten konvertiert wird.

Ein Fenster kann auch eine WM_MOUSEMOVE Nachricht empfangen, wenn sich die Position des Cursors relativ zum Fenster ändert. Wenn der Cursor beispielsweise über einem Fenster positioniert ist und der Benutzer das Fenster ausblendet, empfängt das Fenster WM_MOUSEMOVE Nachrichten, auch wenn die Maus nicht verschoben wurde. Eine Folge dieses Verhaltens ist, dass sich die Mauskoordinaten möglicherweise nicht zwischen WM_MOUSEMOVE Nachrichten ändern.

Erfassen von Mausbewegungen außerhalb des Fensters

Standardmäßig empfängt ein Fenster nicht mehr WM_MOUSEMOVE Nachrichten, wenn sich die Maus über den Rand des Clientbereichs bewegt. Bei einigen Vorgängen müssen Sie die Mausposition jedoch möglicherweise über diesen Punkt hinaus nachverfolgen. Ein Zeichenprogramm kann es dem Benutzer beispielsweise ermöglichen, das Auswahlrechteck über den Rand des Fensters hinaus zu ziehen, wie im folgenden Diagramm dargestellt.

eine Abbildung der Mausaufnahme.

Rufen Sie die SetCapture-Funktion auf, um Mausverschiebungsnachrichten über den Rand des Fensters zu empfangen. Nachdem diese Funktion aufgerufen wurde, empfängt das Fenster weiterhin WM_MOUSEMOVE Nachrichten, solange der Benutzer mindestens eine Maustaste gedrückt hält, auch wenn die Maus außerhalb des Fensters bewegt wird. Das Aufnahmefenster muss das Vordergrundfenster sein, und nur ein Fenster kann das Aufnahmefenster gleichzeitig sein. Rufen Sie zum Loslassen der Mausaufnahme die ReleaseCapture--Funktion auf.

In der Regel verwenden Sie SetCapture- und ReleaseCapture- wie folgt.

  1. Wenn der Benutzer die linke Maustaste drückt, rufen Sie SetCapture- auf, um mit der Aufnahme der Maus zu beginnen.
  2. Reagieren Sie auf Nachrichten, die mit der Maus verschoben werden.
  3. Wenn der Benutzer die linke Maustaste loslässt, rufen Sie ReleaseCapture-auf.

Beispiel: Zeichnen von Kreisen

Lassen Sie uns das Circle-Programm von Modul 3 erweitern, indem der Benutzer einen Kreis mit der Maus zeichnen kann. Beginnen Sie mit dem Direct2D Circle Sample Programm. Wir ändern den Code in diesem Beispiel, um einfache Zeichnung hinzuzufügen. Fügen Sie zunächst der klasse MainWindow eine neue Membervariable hinzu.

D2D1_POINT_2F ptMouse;

Diese Variable speichert die Maus-Nach-unten-Position, während der Benutzer die Maus zieht. Initialisieren Sie im MainWindow-Konstruktor die auslassungspunkte und ptMouse- Variablen.

    MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL),
        ellipse(D2D1::Ellipse(D2D1::Point2F(), 0, 0)),
        ptMouse(D2D1::Point2F())
    {
    }

Entfernen Sie den Textkörper der MainWindow::CalculateLayout-Methode; Es ist für dieses Beispiel nicht erforderlich.

void CalculateLayout() { }

Deklarieren Sie als Nächstes Nachrichtenhandler für die Linke-Taste nach unten, nach links nach oben und nach oben, und bewegen Sie nachrichten mit der Maus.

void OnLButtonDown(int pixelX, int pixelY, DWORD flags);
void OnLButtonUp();
void OnMouseMove(int pixelX, int pixelY, DWORD flags);

Mauskoordinaten werden in physischen Pixeln angegeben, aber Direct2D erwartet geräteunabhängige Pixel (DIPs). Um einstellungen mit hohem DPI-Wert korrekt zu verarbeiten, müssen Sie die Pixelkoordinaten in DIPs übersetzen. Weitere Informationen zu DPI finden Sie unter DPI und Device-Independent Pixel. Der folgende Code zeigt eine Hilfsklasse, die Pixel in DIPs konvertiert.

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;

Rufen Sie DPIScale::Initialize in Ihrem WM_CREATE-Handler auf, nachdem Sie das Direct2D-Factoryobjekt erstellt haben.

case WM_CREATE:
    if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
    {
        return -1;  // Fail CreateWindowEx.
    }
    DPIScale::Initialize(hwnd);
    return 0;

Gehen Sie wie folgt vor, um die Mauskoordinaten in DIPs aus den Mausnachrichten abzurufen:

  1. Verwenden Sie die GET_X_LPARAM und GET_Y_LPARAM Makros, um die Pixelkoordinaten abzurufen. Diese Makros werden in WindowsX.h definiert. Denken Sie also daran, diesen Header in Ihr Projekt einzuschließen.
  2. Rufen Sie DPIScale::PixelsToDips auf, um Pixel in DIPs zu konvertieren.

Fügen Sie nun der Fensterprozedur die Nachrichtenhandler hinzu.

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;

Implementieren Sie schließlich die Nachrichtenhandler selbst.

Linke Schaltfläche nach unten

Gehen Sie für die Meldung mit der linken Schaltfläche nach unten wie folgt vor:

  1. Rufen Sie SetCapture- auf, um mit der Aufnahme der Maus zu beginnen.
  2. Speichern Sie die Position des Mausklicks in der ptMouse Variablen. Diese Position definiert die obere linke Ecke des umgebenden Felds für die Auslassungspunkte.
  3. Setzen Sie die Ellipsestruktur zurück.
  4. Rufen Sie InvalidateRect-auf. Diese Funktion erzwingt, dass das Fenster aktualisiert wird.
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);
}

Mausbewegung

Überprüfen Sie bei der Mausbewegung, ob die linke Maustaste gedrückt ist. Wenn dies der Grund ist, berechnen Sie die Auslassungspunkte neu, und aktualisieren Sie das Fenster erneut. In Direct2D wird eine Ellipse durch den Mittelpunkt und x- und y-Radien definiert. Wir möchten eine Ellipse zeichnen, die dem umgebenden Feld entspricht, das durch den Mausdownpunkt definiert ist (ptMouse) und die aktuelle Cursorposition (x, y), sodass ein wenig Arithmetik erforderlich ist, um die Breite, Höhe und Position der Auslassungspunkte zu finden.

Der folgende Code berechnet die Auslassungspunkte neu und ruft dann InvalidateRect- auf, um das Fenster neu zu überschreiben.

Diagramm, das eine Ellipse mit x- und y-Radius anzeigt.

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

Linke Schaltfläche nach oben

Rufen Sie einfach ReleaseCapture- auf, um die Mausaufnahme loszulassen, um die Linke-Taste-Up-Nachricht freizugeben.

void MainWindow::OnLButtonUp()
{
    ReleaseCapture(); 
}

Nächster