學習windows編程 day3 之滾動條完善
阿新 • • 發佈:2018-03-04
dpa nbsp 相對 classname ech extra set 窗口 tro
1.不再使用setscrollrange,setscrollpos,getscrollrange,getscrollpos這些函數,這只是有助於理解其中運行原理
2.改用setscrollinfo,getscrollinfo函數和結構體scrollinfo去改變和獲取滾動條信息,相對於上面會更加靈活,方便擴展
3.scrollwindow:滾動窗口客戶區的內容,只滾動當前顯示的內容,要顯示其他內容,需要重繪失效的窗口,但是相對於重繪整個窗口是一個很節省內存的方法
#include <windows.h> #include "Sysmet.h" #include <strsafe.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { //聲明全局數據:類名 static TCHAR szClassName[] = TEXT("MyWindows"); HWND hwnd; MSG msg; //註冊窗口類 WNDCLASS wndclass; wndclass.hInstance = hInstance; wndclass.lpszClassName = szClassName; wndclass.cbClsExtra= 0; wndclass.cbWndExtra = 0; wndclass.lpfnWndProc = WndProc; wndclass.lpszMenuName = NULL; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.style = CS_HREDRAW;if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("this program must run in Windows NT!"), szClassName, MB_ICONERROR); return 0; } hwnd = CreateWindow( szClassName, TEXT("MyFirstPractice"), WS_OVERLAPPEDWINDOW|WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd, nShowCmd); 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) { HDC hdc; PAINTSTRUCT ps; RECT rect; //獲取字體大小,初始化數據 static int cxChar, cyChar, cxCaps; //獲取每次重繪窗口後的大小尺寸 static int cxClient, cyClient; //獲取總行數和當前行數 static numCount, curCount; static int y; int FirstLine, LastLine; TEXTMETRIC tm; TCHAR szBuffer[100]; size_t st; 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; //初始化總行數和當前行數 numCount = NUMLINES; curCount = 0; //初始化滾動條位置 SetScrollRange(hwnd, SB_VERT, 0, numCount, FALSE); SetScrollPos(hwnd, SB_VERT, 0, TRUE); ReleaseDC(hwnd, &hdc); break; case WM_SIZE: //獲取每次重繪後的屏幕大小 cxClient = LOWORD(lParam); //這是獲取當前窗口的大小 cyClient = HIWORD(lParam); //設置垂直滾動條的範圍和頁面大小 si.cbSize = sizeof(si); //為了更好的兼容版本 si.fMask = SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = numCount - 1; si.nPage = cyClient / cyChar; //頁面的大小設置 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); break; case WM_VSCROLL: //獲得垂直滾動條的信息 si.cbSize = sizeof(si); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_VERT, &si); //保存當前滑塊的位置 curCount = si.nPos; switch (LOWORD(wParam)) { 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; //在si.nTrackPos中存放著SB_THUMBTRACK和SB_THUMBPOSITION的位置信息 case SB_THUMBPOSITION: si.nPos = si.nTrackPos; break; default: break; } //設置滾動滑塊的新位置 si.fMask = SIF_POS; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); //再次獲得滾動滑塊的位置,由於窗口調整,他可能不是同一個值 GetScrollInfo(hwnd, SB_VERT, &si); //curCount是前面未滾動的數據,si.nPos是剛剛滾動後的數據(除非是在頂部或者底部,不然由於窗口調整,兩種一定不是同一個值) if (si.nPos != curCount) { ScrollWindow(hwnd, 0, cyChar*(curCount-si.nPos), NULL, NULL); /* hwnd :窗口句柄 0 :水平滾動的數量 cyChar*(curCount-si.nPos):垂直滾動的距離 NULL(lpRect) :為NULL時,當前整個客戶區將被滾動 NULL(lpClipRect) :與上一個參數有關,當上一個設置區域後,該參數在其區域中裁剪區域進行滾動 */ UpdateWindow(hwnd); //不進入消息隊列,直接發送WM_PAINT消息進行處理 } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); //獲取垂直滾動條的位置 si.cbSize = sizeof(si); si.fMask = SIF_POS; GetScrollInfo(hwnd,SB_VERT, &si); curCount = si.nPos; //計算需要重繪的區域 FirstLine = max(0, curCount + ps.rcPaint.top / cyChar); LastLine = min(numCount - 1, curCount + ps.rcPaint.bottom / cyChar); /* ps是結構體,ps.rcPaint是指需要重繪的部分窗口矩形,ps.rcPaint.top是該矩形的上部 */ for (int i = FirstLine; i < LastLine;i++) { y = cyChar*(i - curCount); //相當於將這個重繪區域看著新窗口,重這個區域的頂部開始重新繪制 StringCchLength(sysmetrics[i].szLabel, 100, &st); TextOut(hdc, 0, y, sysmetrics[i].szLabel, st); StringCchLength(sysmetrics[i].szDesc, 100, &st); TextOut(hdc, 40 * cxChar, y, sysmetrics[i].szDesc, st); SetTextAlign(hdc, TA_RIGHT | TA_TOP); StringCchPrintf(szBuffer, 100, L"%5d", GetSystemMetrics(sysmetrics[i].iIndex)); StringCchLength(szBuffer, 100, &st); TextOut(hdc, 40 * cxChar + 40 * cxCaps, y, szBuffer, st); SetTextAlign(hdc, TA_LEFT); } EndPaint(hwnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
學習windows編程 day3 之滾動條完善