Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
När musen flyttas publicerar Windows ett WM_MOUSEMOVE meddelande. Som standard går WM_MOUSEMOVE till det fönster som innehåller markören. Du kan åsidosätta det här beteendet genom att fånga musen, vilket beskrivs i nästa avsnitt.
Meddelandet WM_MOUSEMOVE innehåller samma parametrar som meddelandena för musklickningar. De lägsta 16 bitarna av lParam innehålla x-koordinaten och de kommande 16 bitarna innehåller y-koordinaten. Använd makrona GET_X_LPARAM och GET_Y_LPARAM för att packa upp koordinaterna från lParam-. Parametern wParam innehåller en bitvis ELLER flaggor som anger tillståndet för de andra musknapparna plus SKIFT- och CTRL-tangenterna. Följande kod hämtar muskoordinaterna från lParam.
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
Kom ihåg att dessa koordinater finns i bildpunkter, inte enhetsoberoende bildpunkter (DIP:er). Senare i det här avsnittet tittar vi på kod som konverterar mellan de två enheterna.
Ett fönster kan också ta emot ett WM_MOUSEMOVE meddelande om markörens position ändras i förhållande till fönstret. Om markören till exempel är placerad över ett fönster och användaren döljer fönstret, får fönstret WM_MOUSEMOVE meddelanden även om musen inte flyttades. En konsekvens av det här beteendet är att muskoordinaterna kanske inte ändras mellan WM_MOUSEMOVE meddelanden.
Fånga musrörelser utanför fönstret
Som standard slutar ett fönster att ta emot WM_MOUSEMOVE meddelanden om musen flyttas förbi kanten av klientområdet. Men för vissa åtgärder kan du behöva spåra muspositionen bortom den här punkten. Ett ritningsprogram kan till exempel göra det möjligt för användaren att dra markeringsrektangeln utanför fönstrets kant, enligt följande diagram.
Om du vill ta emot musflyttade meddelanden förbi fönstrets kant anropar du funktionen SetCapture. När den här funktionen har anropats fortsätter fönstret att ta emot WM_MOUSEMOVE meddelanden så länge användaren har minst en musknapp nedtryckt, även om musen flyttas utanför fönstret. Avbildningsfönstret måste vara förgrundsfönstret och endast ett fönster kan vara avbildningsfönstret i taget. Om du vill släppa musfångst anropar du funktionen ReleaseCapture.
Du använder vanligtvis SetCapture och ReleaseCapture på följande sätt.
- När användaren trycker på den vänstra musknappen anropar du SetCapture för att börja fånga musen.
- Svara på musflyttningsmeddelanden.
- När användaren släpper den vänstra musknappen anropar du ReleaseCapture.
Exempel: ritningscirklar
Nu ska vi utöka Circle-programmet från modul 3 genom att göra det möjligt för användaren att rita en cirkel med musen. Börja med Direct2D Circle Sample-programmet. Vi kommer att ändra koden i det här exemplet för att lägga till en enkel ritning. Lägg först till en ny medlemsvariabel i klassen MainWindow.
D2D1_POINT_2F ptMouse;
Den här variabeln lagrar nedrullningsbar position medan användaren drar musen. Initiera ellipsen och ptMouse variabler i MainWindow konstruktorn.
MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL),
ellipse(D2D1::Ellipse(D2D1::Point2F(), 0, 0)),
ptMouse(D2D1::Point2F())
{
}
Ta bort brödtexten för metoden MainWindow::CalculateLayout; det krävs inte för det här exemplet.
void CalculateLayout() { }
Deklarera sedan meddelandehanterare för den vänstra knappen nedåt, vänster knapp uppåt och musflytta meddelanden.
void OnLButtonDown(int pixelX, int pixelY, DWORD flags);
void OnLButtonUp();
void OnMouseMove(int pixelX, int pixelY, DWORD flags);
Muskoordinater anges i fysiska bildpunkter, men Direct2D förväntar sig enhetsoberoende bildpunkter (DIP:er). Om du vill hantera inställningarna för hög DPI på rätt sätt måste du översätta pixelkoordinaterna till DIP:er. Mer information om DPI finns i DPI och Device-Independent Pixels. Följande kod visar en hjälpklass som konverterar bildpunkter till DIP:er.
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;
Anropa DPIScale::Initiera i WM_CREATE-hanteraren när du har skapat Direct2D-fabriksobjektet.
case WM_CREATE:
if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
{
return -1; // Fail CreateWindowEx.
}
DPIScale::Initialize(hwnd);
return 0;
Gör följande för att hämta muskoordinaterna i DIP:er från musmeddelandena:
- Använd makrona GET_X_LPARAM och GET_Y_LPARAM för att hämta pixelkoordinaterna. Dessa makron definieras i WindowsX.h, så kom ihåg att inkludera rubriken i projektet.
- Anropa
DPIScale::PixelsToDipsför att konvertera pixlar till DIP:er.
Lägg nu till meddelandehanterarna i fönsterproceduren.
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;
Implementera slutligen själva meddelandehanterarna.
Vänster knapp nedåt
Gör följande för det nedrullningsfria meddelandet till vänster:
- Anropa SetCapture för att börja fånga musen.
- Lagra positionen för musklickningen i variabeln ptMouse. Den här positionen definierar det övre vänstra hörnet i avgränsningsrutan för ellipsen.
- Återställ ellipsstrukturen.
- Anropa InvalidateRect. Den här funktionen tvingar fönstret att målas om.
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);
}
Musflytt
För musflyttningsmeddelandet kontrollerar du om den vänstra musknappen är nere. Om så är fallet beräknar du om ellipsen och ommålar om fönstret. I Direct2D definieras en ellips av mittpunkten och x- och y-radii. Vi vill rita en ellips som passar avgränsningsrutan som definieras av mus-nedpunkten (ptMouse) och den aktuella markörens position (x, y), så lite aritmetik krävs för att hitta ellipsens bredd, höjd och position.
Följande kod beräknar om ellipsen och anropar sedan InvalidateRect för att måla om fönstret.
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);
}
}
Vänster knapp uppåt
För det vänstra knapp-upp-meddelandet anropar du bara ReleaseCapture för att släppa musfångsten.
void MainWindow::OnLButtonUp()
{
ReleaseCapture();
}