今天自己写了《windows程序设计》184页的用键盘控制滚动条显示程序,对滚动条显示有点感悟,留个纪念!
代码如下:
#include <Windows.h> #include <math.h> #include "SYSMETS.h" LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow) { static TCHAR szAppName[]=TEXT("First Program"); MSG msg; HWND hwnd; WNDCLASS wndclass; wndclass.style=CS_HREDRAW|CS_VREDRAW; 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(hwnd,TEXT("Error exists!"),TEXT("Error!"),MB_ICONERROR); return 0; } hwnd=CreateWindow(szAppName,TEXT("Hello World!"),WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,iCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg,hwnd,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { static int cxChar,cyChar,cxCaps,cxClient,cyClient; int iVertPos,x,y,i,iPaintBeg,iPaintEnd; TCHAR szBuffer[20]; HDC hdc; PAINTSTRUCT ps; TEXTMETRIC tm; SCROLLINFO si; switch(message) { case WM_CREATE: hdc=GetDC(hwnd); GetTextMetrics(hdc,&tm); cxChar=tm.tmAveCharWidth; cyChar=tm.tmHeight+tm.tmExternalLeading; cxCaps=(tm.tmPitchAndFamily&1?3:2)*cxChar/2; ReleaseDC(hwnd,hdc); return 0; 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); return 0; case WM_VSCROLL: si.cbSize=sizeof(si); si.fMask=SIF_ALL; GetScrollInfo(hwnd,SB_VERT,&si); iVertPos=si.nPos; switch(LOWORD(wParam)) { case SB_TOP: si.nPos=si.nMin; break; case SB_BOTTOM: si.nPos=si.nMax; break; case SB_PAGEUP: si.nPos-=si.nPage; break; case SB_PAGEDOWN: si.nPos+=si.nPage; break; case SB_LINEUP: si.nPos-=1; break; case SB_LINEDOWN: si.nPos+=1; break; case SB_THUMBTRACK: si.nPos=si.nTrackPos; break; default: break; } si.cbSize=sizeof(si); 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_KEYDOWN: switch(wParam) { case VK_UP: SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0); break; case VK_DOWN: SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0); break; case VK_PRIOR: SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0); break; case VK_NEXT: SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0); break; default: break; } return 0; //关键代码 case WM_PAINT: si.cbSize=sizeof(si); si.fMask=SIF_ALL; GetScrollInfo(hwnd,SB_VERT,&si); iVertPos=si.nPos; hdc=BeginPaint(hwnd,&ps); iPaintBeg=max(0,si.nPos+ps.rcPaint.top/cyChar); iPaintEnd=min(si.nMax,si.nPos+ps.rcPaint.bottom/cyChar); for (i=iPaintBeg;i<=iPaintEnd;i++) { y=cyChar*(i-iVertPos); TextOut(hdc,0,y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel)); TextOut(hdc,22*cxCaps,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc)); SetTextAlign(hdc,TA_TOP|TA_RIGHT); TextOut(hdc,60*cxCaps,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].Index))); SetTextAlign(hdc,TA_LEFT|TA_TOP); } EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); }
1、iPaintBeg=max(0,si.nPos+ps.rcPaint.top/cyChar);
iPaintEnd=min(si.nMax,si.nPos+ps.rcPaint.bottom/cyChar);
这两句是干嘛用的?
2、为什么是for (i=iPaintBeg;i<=iPaintEnd;i++)这样循环?
3、y=cyChar*(i-iVertPos);
为什么是i-iVertPos?
今天调试了一下,颇有感悟!
调试时滚动条下拉了一行!
首先给出调试时一些参数,是我写的一张图:
得出了一些结论:
1、下拉滚动条时,只更新时新出现的客户区,这个矩形的具体参数存数在ps.rcPaint中。
更新起点iPaintBeg是需更新矩形的顶部所在的行数,iPaintEnd是底部所在的行数。即图中新出现一行的顶部和底部。
2、for循环就是输出这些新出现的文本
3、i-iVerPos就是以新客户区的顶部为起点更新客户区