7,鼠标学习四-滚轮

滚轮的滑动是windows产生WM_MOUSEWHEEL消息,并发送给具有输入焦点的窗口,而不是鼠标指针下面的窗口。和通常一样,参数lParam包含鼠标的位置信息,但是这些坐标是相对屏幕左上角的坐标,而不是相对客户区的坐标。同样,参数wParam的低位字包含一系列标志(flag),用于指明鼠标按钮,shift键和Ctrl键的状态。


新的信息出现在参数wParam的高位字,这是一个“增量”(delta)的数值,当前它可能等于120或者-120,取决于滑轮向前移动(朝鼠标的前段),数值120或-120表示文档分别向上或向下滚动三行。


在此介绍几个相关函数:

BOOL WINAPI SystemParametersInfo(
  _In_    UINT  uiAction,
  _In_    UINT  uiParam,
  _Inout_ PVOID pvParam,
  _In_    UINT  fWinIni
);

uiAction:       顾名思义,指定的行为参数

uiParam:     set_时指定的值,无需要就指定为0

pvParam:    get_时获取的值,无需要就指定为0

fWinIni:        如有需要,三个值中选其一,SPIF_UPDATEINIFILE(更新win.ini),SPIF_SENDCHANGE(更行win.ini后并广播WM_SETTINGCHANGE),

SPIF_SENDWININICHANGE(同SPIF_SENDCHANGE效果),如不需要设定,则置为0


详见https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947%28v=vs.85%29.aspx


示例代码:

#define WINVER 0x0500
#define _WIN32_WINNT 0x0500

#include<windows.h>
#include "sysmets.h"

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
PSTR szCmdLine,int iCmdShow)
{
	static TCHAR szAppName[]=TEXT("sysmet4");
	HWND		 hwnd;
	MSG			 msg;
	WNDCLASS	 wndclass;

	wndclass.style=CS_VREDRAW |CS_HREDRAW;
	wndclass.lpfnWndProc=WndProc;
	wndclass.cbClsExtra=0;
	wndclass.cbWndExtra=0;
	wndclass.hInstance=hInstance;
	wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName=NULL;
	wndclass.lpszClassName=szAppName;

	if(!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("unhnow error occurs"),szAppName,
		MB_ICONERROR);
		return 0;
	}

	hwnd=CreateWindow(szAppName,TEXT("mousewheel of sysmets4"),
	WS_OVERLAPPEDWINDOW,
	CW_USEDEFAULT,CW_USEDEFAULT,
	CW_USEDEFAULT,CW_USEDEFAULT,
	NULL,NULL,hInstance,NULL);

	ShowWindow(hwnd,iCmdShow);
	UpdateWindow(hwnd);

	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static int	cxChar,cxCaps,cyChar,cxClient,cyClient,iMaxWidth;
	static int	iDeltaPerLine,iAccumDelta;            //for mouse wheel logic
	HDC			hdc;
	int			i,x,y,iVertPos,iHorzPos,iPaintBeg,iPaintEnd;
	PAINTSTRUCT ps;
	SCROLLINFO  si;
	TCHAR		szBuffer[10];
	TEXTMETRIC	tm;
	ULONG		ulScrollLines;			//for mouse wheel logic

	switch(message)
	{
	case WM_CREATE:
		hdc=GetDC(hwnd);

		GetTextMetrics(hdc,&tm);
		cxChar=tm.tmAveCharWidth;
		cxCaps=(tm.tmPitchAndFamily&1 ?3 :2)*cxChar/2;
		cyChar=tm.tmHeight+tm.tmExternalLeading;

		ReleaseDC(hwnd,hdc);

		iMaxWidth=40*cxChar+22*cxCaps;


	case WM_SETTINGCHANGE:
		SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,&ulScrollLines,0);

		

		//ulScrollLines usually equals 3 or 0(for no scrolling)
		//WHEEL_DELTA equals 120,so iDeltaPerLine will be 40

		if(ulScrollLines)
			iDeltaPerLine=WHEEL_DELTA/ulScrollLines;
		else
			iDeltaPerLine=0;

		return 0;</span>

	case WM_SIZE:
		cxClient=LOWORD(lParam);
		cyClient=HIWORD(lParam);

		si.cbSize=sizeof(si);
		si.fMask=SIF_RANGE | SIF_PAGE;
		si.nMin=0;
		si.nMax=NUMLINES-1;
		si.nPage=cyClient/cyChar;
		SetScrollInfo(hwnd,SB_VERT,&si,TRUE);

		si.cbSize=sizeof(si);
		si.fMask=SIF_RANGE |SIF_PAGE;
		si.nMin=0;
		si.nMax=2+iMaxWidth/cxChar;
		si.nPage=cxClient/cxChar;
		SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);

		return 0;

	case WM_VSCROLL:
		si.cbSize=sizeof(si);
		si.fMask=SIF_ALL;
		GetScrollInfo(hwnd,SB_VERT,&si);

		iVertPos=si.nPos;           //save the position for comparison later on

		switch(LOWORD(wParam))
		{
		case SB_TOP:
			si.nPos=si.nMin;
			break;

		case SB_BOTTOM:
			si.nPos=si.nMax;
			break;

		case SB_LINEUP:
			si.nPos-=1;
			break;

		case SB_LINEDOWN:
			si.nPos+=1;
			break;

		case SB_PAGEUP:
			si.nPos-=si.nPage;
			break;

		case SB_PAGEDOWN:
			si.nPos+=si.nPage;
			break;

		case SB_THUMBTRACK:
			si.nPos=si.nTrackPos;
			break;
			
		default:
			break;
		}

		si.fMask=SIF_POS;
		SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
		GetScrollInfo(hwnd,SB_VERT,&si);

		if(si.nPos!=iVertPos)
		{
			ScrollWindow(hwnd,0,cyChar*(iVertPos-si.nPos),
			NULL,NULL);
			UpdateWindow(hwnd);
		}
		return 0;

	case WM_HSCROLL:
		si.cbSize=sizeof(si);
		si.fMask=SIF_ALL;                     //指定获取或设定哪些信息
		GetScrollInfo(hwnd,SB_HORZ,&si);

		iHorzPos=si.nPos;           //save the position for comparison later on

		switch(LOWORD(wParam))
		{
		case SB_LINELEFT:
			si.nPos-=1;
			break;

		case SB_LINERIGHT:
			si.nPos+=1;
			break;

		case SB_PAGELEFT:
			si.nPos-=si.nPage;
			break;

		case SB_PAGERIGHT:
			si.nPos+=si.nPage;
			break;

		case SB_THUMBPOSITION:
			si.nPos=si.nTrackPos;
			break;
			
		default:
			break;
		}

		si.fMask=SIF_POS;
		SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);
		GetScrollInfo(hwnd,SB_HORZ,&si);

		if(si.nPos!=iHorzPos)
		{
			ScrollWindow(hwnd,cxChar*(iHorzPos-si.nPos),0,
			NULL,NULL);
			//UpdateWindow(hwnd);
		}
		return 0;

	case WM_KEYDOWN:
		switch(wParam)
		{
		case VK_HOME:
			SendMessage(hwnd,WM_VSCROLL,SB_TOP,0);
			break;

		case VK_END:
			SendMessage(hwnd,WM_VSCROLL,SB_BOTTOM,0);

		case VK_PRIOR:
			SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0);
			break;

		case VK_NEXT:
			SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0);
			break;

		case VK_UP:
			SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0);
			break;

		case VK_DOWN:
			SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0);
			break;

		case VK_LEFT:
			SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0);
			break;

		case VK_RIGHT:
			SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0);
			break;
		}
		return 0;

	case WM_MOUSEWHEEL:
		if(iDeltaPerLine==0)
		break;
		
		//鼠标滚一下,增量为120或-120

		iAccumDelta+=(short)HIWORD(wParam);         

		while(iAccumDelta>=iDeltaPerLine)
		{
			SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0);
			iAccumDelta-=iDeltaPerLine;
		}


		//每一行的增量为30或-30
		while(iAccumDelta<=-iDeltaPerLine)     
		{
			SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0);
			iAccumDelta+=iDeltaPerLine;
		}</span>

		return 0;

	case WM_PAINT:
		hdc=BeginPaint(hwnd,&ps);

		si.cbSize=sizeof(si);
		si.fMask=SIF_POS;
		GetScrollInfo(hwnd,SB_VERT,&si);
		iVertPos=si.nPos;

		GetScrollInfo(hwnd,SB_HORZ,&si);
		iHorzPos=si.nPos;

		iPaintBeg=max(0,iVertPos+ps.rcPaint.top/cyChar);
		iPaintEnd=min(NUMLINES-1,
		iVertPos+ps.rcPaint.bottom/cyChar);

		for(i=iPaintBeg;i<=iPaintEnd;i++)
		{
			x=cxChar*(1-iHorzPos);
			y=cyChar*(i-iVertPos);

			TextOut(hdc,x,y,sysmetrics[i].szLabel,
			lstrlen(sysmetrics[i].szLabel));

			TextOut(hdc,x+22*cxCaps,y,
			sysmetrics[i].szDesc,
			lstrlen(sysmetrics[i].szDesc));

			SetTextAlign(hdc,TA_RIGHT |TA_TOP);

			TextOut(hdc,x+22*cxCaps+40*cxChar,y,szBuffer,
			wsprintf(szBuffer,TEXT("%5d"),
			GetSystemMetrics(sysmetrics[i].iIndex)));

			SetTextAlign(hdc,TA_LEFT |TA_TOP);

		}

		EndPaint(hwnd,&ps);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}


程序在处理WM_SETTINGCHANGE消息时调用了参数为SPI_GETEWHEELSCROLLLINES的SystemParametersInfo函数。这个参数表示了每个增量数值能够滚动多少行,其中增量数值用定义在WINUSER.h的头文件中的WHEEL_DELTA来标识。WHEEL_DELTA等于120,且默认情况下SystemParametersInfo返回值为3,因此,没滚动一行的增量是40,也就是说滚轮每动一个单位,需要发送三次SB_LINEUP或者SB_LINEDOWN,程序中将这个单位增量保存在iDeltaPerLine中。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值