Condividi tramite


Spostamento del mouse

Quando il mouse si sposta, Windows pubblica un messaggio di WM_MOUSEMOVE . Per impostazione predefinita, WM_MOUSEMOVE passa alla finestra contenente il cursore. È possibile eseguire l'override di questo comportamento acquisiscendo il mouse, descritto nella sezione successiva.

Il messaggio WM_MOUSEMOVE contiene gli stessi parametri dei messaggi per i clic del mouse. I 16 bit più bassi di lParam contengono la coordinata x e i 16 bit successivi contengono la coordinata y. Usare le macro GET_X_LPARAM e GET_Y_LPARAM per decomprimere le coordinate da lParam. Il parametro wParam contiene un or bit per bit di flag, che indica lo stato degli altri pulsanti del mouse e i tasti MAIUSC e CTRL. Il codice seguente ottiene le coordinate del mouse da lParam.

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

Tenere presente che queste coordinate sono in pixel, non pixel indipendenti dal dispositivo (DIP). Più avanti in questo argomento verrà esaminato il codice che converte tra le due unità.

Una finestra può anche ricevere un messaggio WM_MOUSEMOVE se la posizione del cursore cambia rispetto alla finestra. Ad esempio, se il cursore viene posizionato su una finestra e l'utente nasconde la finestra, la finestra riceve WM_MOUSEMOVE messaggi anche se il mouse non è stato spostato. Una conseguenza di questo comportamento è che le coordinate del mouse potrebbero non cambiare tra i messaggi WM_MOUSEMOVE .

Acquisizione del movimento del mouse all'esterno della finestra

Per impostazione predefinita, una finestra interrompe la ricezione di messaggi WM_MOUSEMOVE se il mouse si sposta oltre il bordo dell'area client. Tuttavia, per alcune operazioni, potrebbe essere necessario tenere traccia della posizione del mouse oltre questo punto. Ad esempio, un programma di disegno potrebbe consentire all'utente di trascinare il rettangolo di selezione oltre il bordo della finestra, come illustrato nel diagramma seguente.

figura dell'acquisizione del mouse.

Per ricevere messaggi di spostamento del mouse oltre il bordo della finestra, chiamare la funzione SetCapture . Dopo aver chiamato questa funzione, la finestra continuerà a ricevere WM_MOUSEMOVE messaggi per quanto l'utente contenga almeno un pulsante del mouse verso il basso, anche se il mouse si sposta all'esterno della finestra. La finestra di acquisizione deve essere la finestra di primo piano e solo una finestra può essere la finestra di acquisizione alla volta. Per rilasciare l'acquisizione del mouse, chiamare la funzione ReleaseCapture .

In genere si usa SetCapture e ReleaseCapture nel modo seguente.

  1. Quando l'utente preme il pulsante sinistro del mouse, chiamare SetCapture per avviare l'acquisizione del mouse.
  2. Rispondere ai messaggi di spostamento del mouse.
  3. Quando l'utente rilascia il pulsante sinistro del mouse, chiamare ReleaseCapture.

Esempio: cerchi di disegno

Estendere il programma Circle dal modulo 3 consentendo all'utente di disegnare un cerchio con il mouse. Iniziare con il programma Direct2D Circle Sample . Verrà modificato il codice in questo esempio per aggiungere un disegno semplice. Aggiungere prima di tutto una nuova variabile membro alla MainWindow classe.

D2D1_POINT_2F ptMouse;

Questa variabile archivia la posizione verso il basso del mouse mentre l'utente trascina il mouse. MainWindow Nel costruttore inizializzare le variabili con puntini di sospensione e ptMouse.

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

Rimuovere il corpo del MainWindow::CalculateLayout metodo. Non è necessario per questo esempio.

void CalculateLayout() { }

Dichiarare quindi i gestori dei messaggi per i messaggi a sinistra verso il basso, il pulsante sinistro verso l'alto e i messaggi di spostamento del mouse.

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

Le coordinate del mouse vengono fornite in pixel fisici, ma Direct2D prevede pixel indipendenti dal dispositivo (DIP). Per gestire correttamente le impostazioni DPI elevate, è necessario convertire le coordinate pixel in INDIRIZZI DIP. Per altre informazioni su DPI, vedere DPI e Device-Independent Pixel. Il codice seguente mostra una classe helper che converte i pixel in INDIRIZZI 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;

Chiamare DPIScale::Initialize nel gestore WM_CREATE , dopo aver creato l'oggetto Factory Direct2D.

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

Per ottenere le coordinate del mouse nei messaggi del mouse, eseguire le operazioni seguenti:

  1. Usare le macro GET_X_LPARAM e GET_Y_LPARAM per ottenere le coordinate pixel. Queste macro sono definite in WindowsX.h, quindi ricordarsi di includere tale intestazione nel progetto.
  2. Chiamare DPIScale::PixelsToDips per convertire i pixel in INDIRIZZI DIP.

Aggiungere ora i gestori di messaggi alla routine della finestra.

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;

Infine, implementare i gestori di messaggi stessi.

Pulsante sinistro verso il basso

Per il messaggio a sinistra verso il basso, eseguire le operazioni seguenti:

  1. Chiamare SetCapture per iniziare a acquisire il mouse.
  2. Archiviare la posizione del mouse facendo clic nella variabile ptMouse . Questa posizione definisce l'angolo superiore sinistro del rettangolo di selezione per i puntini di sospensione.
  3. Reimpostare la struttura con i puntini di sospensione.
  4. Chiamare InvalidateRect. Questa funzione forza il repainting della finestra.
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);
}

Spostamento del mouse

Per il messaggio di spostamento del mouse, verificare se il pulsante del mouse sinistro è inattivo. In caso affermativo, ricalcolare i puntini di sospensione e ricompilare la finestra. In Direct2D un'ellisse è definita dal punto centrale e x- e y-radii. Si vuole disegnare un punto di sospensione che si adatta al rettangolo definito dal punto in basso del mouse (ptMouse) e la posizione del cursore corrente (x, y), quindi è necessario trovare la larghezza, l'altezza e la posizione dei puntini di sospensione.

Il codice seguente ricalcola i puntini di sospensione e quindi chiama InvalidateRect per ricreare la finestra.

Diagramma che mostra un'ellisse con raggi x e 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);
    }
}

Pulsante sinistro su

Per il messaggio a sinistra, chiamare ReleaseCapture per rilasciare l'acquisizione del mouse.

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

Prossima