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.
Det här avsnittet beskriver uppgifter som är associerade med musinmatning.
- spåra musmarkören
- rita linjer med musen
- Bearbeta ett dubbelklickmeddelande
- Välja en textrad
- Använda ett mushjul i ett dokument med inbäddade objekt
- Att hämta antalet rader för scrollhjulet
Spåra musmarkören
Program utför ofta uppgifter som innebär att spåra musmarkörens position. De flesta ritningsprogram spårar till exempel musmarkörens position under ritningsåtgärder, så att användaren kan rita i ett fönsters klientområde genom att dra musen. Ordbearbetningsprogram spårar också markören, vilket gör att användaren kan välja ett ord eller textblock genom att klicka och dra musen.
Att spåra markören innebär vanligtvis att bearbeta WM_LBUTTONDOWN, WM_MOUSEMOVEoch WM_LBUTTONUP meddelanden. Ett fönster avgör när markören ska börja spåras genom att markera markörens position i parametern lParam i WM_LBUTTONDOWN-meddelandet. Ett ordbehandlingsprogram skulle till exempel bara börja spåra markören om det WM_LBUTTONDOWN meddelandet inträffade när markören var på en textrad, men inte om den var förbi slutet av dokumentet.
Ett fönster spårar markörens position genom att bearbeta strömmen av WM_MOUSEMOVE meddelanden som publiceras i fönstret när musen flyttas. Bearbetning av WM_MOUSEMOVE-meddelandet innebär vanligtvis en repetitiv målning eller ritningsåtgärd i klientområdet. Ett ritningsprogram kan till exempel rita om en linje upprepade gånger när musen flyttas. Ett fönster använder WM_LBUTTONUP-meddelandet som en signal för att sluta spåra markören.
Dessutom kan ett program anropa funktionen TrackMouseEvent för att låta systemet skicka andra meddelanden som är användbara för att spåra markören. Systemet publicerar WM_MOUSEHOVER meddelande när markören hovrar över klientområdet under en viss tidsperiod. Den publicerar WM_MOUSELEAVE-meddelandet när markören lämnar klientområdet. Meddelandena WM_NCMOUSEHOVER och WM_NCMOUSELEAVE är motsvarande meddelanden för de icke-klientområdena.
Rita linjer med musen
Exemplet i det här avsnittet visar hur du spårar musmarkören. Den innehåller delar av en fönsterprocedur som gör att användaren kan rita linjer i ett fönsters klientområde genom att dra musen.
När fönsterproceduren tar emot ett WM_LBUTTONDOWN meddelande fångar den upp musen och sparar markörens koordinater med koordinaterna som startpunkt för raden. Den använder också funktionen ClipCursor för att begränsa markören till klientområdet under linjeritningsåtgärden.
Under det första WM_MOUSEMOVE meddelandet ritar fönsterproceduren en linje från startpunkten till markörens aktuella position. Under efterföljande WM_MOUSEMOVE meddelanden raderar fönsterproceduren föregående rad genom att rita över den med en inverterad pennfärg. Sedan ritas en ny rad från startpunkten till markörens nya position.
Meddelandet WM_LBUTTONUP signalerar slutet på ritningsåtgärden. Fönsterproceduren släpper musfångstet och frigör musen från klientområdet.
LRESULT APIENTRY MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc; // handle to device context
RECT rcClient; // client area rectangle
POINT ptClientUL; // client upper left corner
POINT ptClientLR; // client lower right corner
static POINTS ptsBegin; // beginning point
static POINTS ptsEnd; // new endpoint
static POINTS ptsPrevEnd; // previous endpoint
static BOOL fPrevLine = FALSE; // previous line flag
switch (uMsg)
{
case WM_LBUTTONDOWN:
// Capture mouse input.
SetCapture(hwndMain);
// Retrieve the screen coordinates of the client area,
// and convert them into client coordinates.
GetClientRect(hwndMain, &rcClient);
ptClientUL.x = rcClient.left;
ptClientUL.y = rcClient.top;
// Add one to the right and bottom sides, because the
// coordinates retrieved by GetClientRect do not
// include the far left and lowermost pixels.
ptClientLR.x = rcClient.right + 1;
ptClientLR.y = rcClient.bottom + 1;
ClientToScreen(hwndMain, &ptClientUL);
ClientToScreen(hwndMain, &ptClientLR);
// Copy the client coordinates of the client area
// to the rcClient structure. Confine the mouse cursor
// to the client area by passing the rcClient structure
// to the ClipCursor function.
SetRect(&rcClient, ptClientUL.x, ptClientUL.y,
ptClientLR.x, ptClientLR.y);
ClipCursor(&rcClient);
// Convert the cursor coordinates into a POINTS
// structure, which defines the beginning point of the
// line drawn during a WM_MOUSEMOVE message.
ptsBegin = MAKEPOINTS(lParam);
return 0;
case WM_MOUSEMOVE:
// When moving the mouse, the user must hold down
// the left mouse button to draw lines.
if (wParam & MK_LBUTTON)
{
// Retrieve a device context (DC) for the client area.
hdc = GetDC(hwndMain);
// The following function ensures that pixels of
// the previously drawn line are set to white and
// those of the new line are set to black.
SetROP2(hdc, R2_NOTXORPEN);
// If a line was drawn during an earlier WM_MOUSEMOVE
// message, draw over it. This erases the line by
// setting the color of its pixels to white.
if (fPrevLine)
{
MoveToEx(hdc, ptsBegin.x, ptsBegin.y,
(LPPOINT) NULL);
LineTo(hdc, ptsPrevEnd.x, ptsPrevEnd.y);
}
// Convert the current cursor coordinates to a
// POINTS structure, and then draw a new line.
ptsEnd = MAKEPOINTS(lParam);
MoveToEx(hdc, ptsBegin.x, ptsBegin.y, (LPPOINT) NULL);
LineTo(hdc, ptsEnd.x, ptsEnd.y);
// Set the previous line flag, save the ending
// point of the new line, and then release the DC.
fPrevLine = TRUE;
ptsPrevEnd = ptsEnd;
ReleaseDC(hwndMain, hdc);
}
break;
case WM_LBUTTONUP:
// The user has finished drawing the line. Reset the
// previous line flag, release the mouse cursor, and
// release the mouse capture.
fPrevLine = FALSE;
ClipCursor(NULL);
ReleaseCapture();
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Process other messages.
}
}
Bearbeta ett dubbelklicksmeddelande
Om du vill ta emot dubbelklicksmeddelanden måste ett fönster tillhöra en fönsterklass som har CS_DBLCLKS klassformat. Du anger det här formatet när du registrerar fönsterklassen, som du ser i följande exempel.
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWClass";
return RegisterClass(&wc);
}
Ett dubbelklicksmeddelande föregås alltid av ett nedtryckningsmeddelande. Av den anledningen använder program vanligtvis ett dubbelklicksmeddelande för att utöka en uppgift som den påbörjade under ett knapp-ned-meddelande.
Välja en textrad
Exemplet i det här avsnittet är hämtat från ett enkelt ordbearbetningsprogram. Den innehåller kod som gör det möjligt för användaren att ange positionen för caret genom att klicka var som helst på en textrad och välja (markera) en textrad genom att dubbelklicka var som helst på raden.
LRESULT APIENTRY MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc; // handle to device context
TEXTMETRIC tm; // font size data
int i, j; // loop counters
int cCR = 0; // count of carriage returns
char ch; // character from input buffer
static int nBegLine; // beginning of selected line
static int nCurrentLine = 0; // currently selected line
static int nLastLine = 0; // last text line
static int nCaretPosX = 0; // x-coordinate of caret
static int cch = 0; // number of characters entered
static int nCharWidth = 0; // exact width of a character
static char szHilite[128]; // text string to highlight
static DWORD dwCharX; // average width of characters
static DWORD dwLineHeight; // line height
static POINTS ptsCursor; // coordinates of mouse cursor
static COLORREF crPrevText; // previous text color
static COLORREF crPrevBk; // previous background color
static PTCHAR pchInputBuf; // pointer to input buffer
static BOOL fTextSelected = FALSE; // text-selection flag
size_t * pcch;
HRESULT hResult;
switch (uMsg)
{
case WM_CREATE:
// Get the metrics of the current font.
hdc = GetDC(hwndMain);
GetTextMetrics(hdc, &tm);
ReleaseDC(hwndMain, hdc);
// Save the average character width and height.
dwCharX = tm.tmAveCharWidth;
dwLineHeight = tm.tmHeight;
// Allocate a buffer to store keyboard input.
pchInputBuf = (LPSTR) GlobalAlloc(GPTR,
BUFSIZE * sizeof(TCHAR));
return 0;
case WM_CHAR:
switch (wParam)
{
case 0x08: // backspace
case 0x0A: // linefeed
case 0x1B: // escape
MessageBeep( (UINT) -1);
return 0;
case 0x09: // tab
// Convert tabs to four consecutive spaces.
for (i = 0; i < 4; i++)
SendMessage(hwndMain, WM_CHAR, 0x20, 0);
return 0;
case 0x0D: // carriage return
// Record the carriage return, and position the
// caret at the beginning of the new line.
pchInputBuf[cch++] = 0x0D;
nCaretPosX = 0;
nCurrentLine += 1;
break;
default: / displayable character
ch = (char) wParam;
HideCaret(hwndMain);
// Retrieve the character's width, and display the
// character.
hdc = GetDC(hwndMain);
GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,
&nCharWidth);
TextOut(hdc, nCaretPosX,
nCurrentLine * dwLineHeight, &ch, 1);
ReleaseDC(hwndMain, hdc);
// Store the character in the buffer.
pchInputBuf[cch++] = ch;
// Calculate the new horizontal position of the
// caret. If the new position exceeds the maximum,
// insert a carriage return and reposition the
// caret at the beginning of the next line.
nCaretPosX += nCharWidth;
if ((DWORD) nCaretPosX > dwMaxCharX)
{
nCaretPosX = 0;
pchInputBuf[cch++] = 0x0D;
++nCurrentLine;
}
ShowCaret(hwndMain);
break;
}
SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
nLastLine = max(nLastLine, nCurrentLine);
break;
// Process other messages.
case WM_LBUTTONDOWN:
// If a line of text is currently highlighted, redraw
// the text to remove the highlighting.
if (fTextSelected)
{
hdc = GetDC(hwndMain);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
hResult = StringCchLength(szHilite, 128/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 0, nCurrentLine * dwLineHeight,
szHilite, *pcch);
ReleaseDC(hwndMain, hdc);
ShowCaret(hwndMain);
fTextSelected = FALSE;
}
// Save the current mouse-cursor coordinates.
ptsCursor = MAKEPOINTS(lParam);
// Determine which line the cursor is on, and save
// the line number. Do not allow line numbers greater
// than the number of the last line of text. The
// line number is later multiplied by the average height
// of the current font. The result is used to set the
// y-coordinate of the caret.
nCurrentLine = min((int)(ptsCursor.y / dwLineHeight),
nLastLine);
// Parse the text input buffer to find the first
// character in the selected line of text. Each
// line ends with a carriage return, so it is possible
// to count the carriage returns to find the selected
// line.
cCR = 0;
nBegLine = 0;
if (nCurrentLine != 0)
{
for (i = 0; (i < cch) &&
(cCR < nCurrentLine); i++)
{
if (pchInputBuf[i] == 0x0D)
++cCR;
}
nBegLine = i;
}
// Starting at the beginning of the selected line,
// measure the width of each character, summing the
// width with each character measured. Stop when the
// sum is greater than the x-coordinate of the cursor.
// The sum is used to set the x-coordinate of the caret.
hdc = GetDC(hwndMain);
nCaretPosX = 0;
for (i = nBegLine;
(pchInputBuf[i] != 0x0D) && (i < cch); i++)
{
ch = pchInputBuf[i];
GetCharWidth32(hdc, (int) ch, (int) ch, &nCharWidth);
if ((nCaretPosX + nCharWidth) > ptsCursor.x) break;
else nCaretPosX += nCharWidth;
}
ReleaseDC(hwndMain, hdc);
// Set the caret to the user-selected position.
SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);
break;
case WM_LBUTTONDBLCLK:
// Copy the selected line of text to a buffer.
for (i = nBegLine, j = 0; (pchInputBuf[i] != 0x0D) &&
(i < cch); i++)
{
szHilite[j++] = pchInputBuf[i];
}
szHilite[j] = '\0';
// Hide the caret, invert the background and foreground
// colors, and then redraw the selected line.
HideCaret(hwndMain);
hdc = GetDC(hwndMain);
crPrevText = SetTextColor(hdc, RGB(255, 255, 255));
crPrevBk = SetBkColor(hdc, RGB(0, 0, 0));
hResult = StringCchLength(szHilite, 128/sizeof(TCHAR), pcch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite, *pcch);
SetTextColor(hdc, crPrevText);
SetBkColor(hdc, crPrevBk);
ReleaseDC(hwndMain, hdc);
fTextSelected = TRUE;
break;
// Process other messages.
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}
Använda ett mushjul i ett dokument med inbäddade objekt
Det här exemplet förutsätter ett Microsoft Word-dokument med olika inbäddade objekt:
- Ett Microsoft Excel-kalkylblad
- En inbäddad listrutekontroll som rullar som svar på hjulet
- En inbäddad textrutekontroll som inte reagerar på musens hjul
Meddelandet MSH_MOUSEWHEEL skickas alltid till huvudfönstret i Microsoft Word. Detta gäller även om det inbäddade kalkylbladet är aktivt. I följande tabell förklaras hur MSH_MOUSEWHEEL-meddelandet hanteras enligt fokus.
| Fokus ligger på | Hanteringen är följande |
|---|---|
| Word-dokument | Word rullar dokumentfönstret. |
| Inbäddat Excel-kalkylblad | Word publicerar meddelandet i Excel. Du måste bestämma om det inbäddade programmet ska svara på meddelandet eller inte. |
| Inbäddad kontroll | Det är upp till programmet att skicka meddelandet till en inbäddad kontroll som har fokus och kontrollera returkoden för att se om kontrollen hanterade den. Om kontrollen inte hanterade den ska programmet rulla dokumentfönstret. Om användaren till exempel klickade på en listruta och sedan rullade hjulet skulle kontrollen rulla som svar på en hjulrotation. Om användaren klickade på en textruta och sedan roterade hjulet skulle hela dokumentet rulla. |
I följande exempel visas hur ett program kan hantera de två hjulmeddelandena.
/************************************************
* this code deals with MSH_MOUSEWHEEL
*************************************************/
#include "zmouse.h"
//
// Mouse Wheel rotation stuff, only define if we are
// on a version of the OS that does not support
// WM_MOUSEWHEEL messages.
//
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL WM_MOUSELAST+1
// Message ID for IntelliMouse wheel
#endif
UINT uMSH_MOUSEWHEEL = 0; // Value returned from
// RegisterWindowMessage()
/**************************************************
INT WINAPI WinMain(
HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpCmdLine,
INT nCmdShow)
{
MSG msg;
BOOL bRet;
if (!InitInstance(hInst, nCmdShow))
return FALSE;
//
// The new IntelliMouse uses a Registered message to transmit
// wheel rotation info. So register for it!
uMSH_MOUSEWHEEL =
RegisterWindowMessage(MSH_MOUSEWHEEL);
if ( !uMSH_MOUSEWHEEL )
{
MessageBox(NULL,"
RegisterWindowMessag Failed!",
"Error",MB_OK);
return msg.wParam;
}
while (( bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (!TranslateAccelerator(ghwndApp,
ghaccelTable,
&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return msg.wParam;
}
/************************************************
* this code deals with WM_MOUSEWHEEL
*************************************************/
LONG APIENTRY MainWndProc(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
static int nZoom = 0;
switch (msg)
{
//
// Handle Mouse Wheel messages generated
// by the operating systems that have built-in
// support for the WM_MOUSEWHEEL message.
//
case WM_MOUSEWHEEL:
((short) HIWORD(wParam)< 0) ? nZoom-- : nZoom++;
//
// Do other wheel stuff...
//
break;
default:
//
// uMSH_MOUSEWHEEL is a message registered by
// the mswheel dll on versions of Windows that
// do not support the new message in the OS.
if( msg == uMSH_MOUSEWHEEL )
{
((int)wParam < 0) ? nZoom-- : nZoom++;
//
// Do other wheel stuff...
//
break;
}
return DefWindowProc(hwnd,
msg,
wParam,
lParam);
}
return 0L;
}
Hämtar antalet mushjulsrullningslinjer
Med följande kod kan ett program hämta antalet rullningslinjer med hjälp av funktionen SystemParametersInfo.
#ifndef SPI_GETWHEELSCROLLLINES
#define SPI_GETWHEELSCROLLLINES 104
#endif
#include "zmouse.h"
/*********************************************************
* FUNCTION: GetNumScrollLines
* Purpose : An OS independent method to retrieve the
* number of wheel scroll lines
* Params : none
* Returns : UINT: Number of scroll lines where WHEEL_PAGESCROLL
* indicates to scroll a page at a time.
*********************************************************/
UINT GetNumScrollLines(void)
{
HWND hdlMsWheel;
UINT ucNumLines=3; // 3 is the default
OSVERSIONINFO osversion;
UINT uiMsh_MsgScrollLines;
memset(&osversion, 0, sizeof(osversion));
osversion.dwOSVersionInfoSize =sizeof(osversion);
GetVersionEx(&osversion);
if ((osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ||
( (osversion.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
(osversion.dwMajorVersion < 4) ) )
{
hdlMsWheel = FindWindow(MSH_WHEELMODULE_CLASS,
MSH_WHEELMODULE_TITLE);
if (hdlMsWheel)
{
uiMsh_MsgScrollLines = RegisterWindowMessage
(MSH_SCROLL_LINES);
if (uiMsh_MsgScrollLines)
ucNumLines = (int)SendMessage(hdlMsWheel,
uiMsh_MsgScrollLines,
0,
0);
}
}
else if ( (osversion.dwPlatformId ==
VER_PLATFORM_WIN32_NT) &&
(osversion.dwMajorVersion >= 4) )
{
SystemParametersInfo(SPI_GETWHEELSCROLLLINES,
0,
&ucNumLines, 0);
}
return(ucNumLines);
}