滚动条的使用2

来源:互联网 发布:ps软件序列号是什么 编辑:程序博客网 时间:2024/05/21 19:23

前面简单介绍了滚动条的使用,以及滚动条相关的函数。下面将基于一下内容继续完善滚动条的使用:

        1:GetScrollInfo、SetScrollInfo函数的使用

       2:解决绘制效率问题、以及最后最后一条数据不能在客户区底部显示的问题


1、GetScrollInfo、SetScrollInfo函数的使用

        这两个函数可以完全取代前面所使用的那一系列函数:GetScrollRange、GetScrollPos、SetScrollRange、SetScrollPos。因为GetScrollInfo、SetScrollInfo所使用的参数为SCROLLINFO结构体,该结构体包含了滚动条相关的信息,如下:
typedef struct tagSCROLLINFO {     UINT cbSize;     UINT fMask;     int  nMin;     int  nMax;     UINT nPage;     int  nPos;     int  nTrackPos; }   SCROLLINFO, *LPSCROLLINFO; typedef SCROLLINFO CONST *LPCSCROLLINFO;
现在对这些参数重新说明:
cbSize:结构体大小
fMask:掩码,指定要操作(设置或则获取)哪些滚动条的参数
                        SIF_ALL                                包含 SIF_PAGE, SIF_POS, SIF_RANGE, SIF_TRACKPOS
                        SIF_DISABLENOSCROLL       时滚动条无效
                        SIF_PAGE                            操作也参数
                        SIF_POS                             操作位置
                        SIF_RANGE                         操作范围
                        SIF_TRACKPOS                   获取拖动的位置
nMin:滚动条滚动范围的最小值
nMax:滚动条滚动范围的最大值
nPage:页面大小,即一页所占的内容大小(范围),这个值可以动态变化来改变滑块的大小
nPos:滚动条的位置
nTrackPos:滚动条在拖动过程中的位置
注意:
        正因为有了这个结构体,我们操作滚动条才变得更加方便,MSDN中建议我们在新的应用程序中使用GetScrollInfo、SetScrollInfo来操作滚动条。
        另外,系统会根据滚动条的范围和页(page)大小来计算滚动的真正范围,这就解决了最后一条数据不能现在客户区底部的问题

2、源代码如下

#define  _CRT_SECURE_NO_WARNINGS#define _CRT_NON_CONFORMING_SWPRINTFS#define MAX_NUM_ROW 100//显示文字的最大行数#include <windows.h>#include <tchar.h>LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR lpCmdLine, int nShowCmd){TCHAR *pszClassName = _T("MyClass");WNDCLASS  wndClass;wndClass.cbClsExtra = 0;wndClass.cbWndExtra = 0;wndClass.style = CS_HREDRAW | CS_VREDRAW;wndClass.lpfnWndProc = WndProc;wndClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndClass.hInstance = hInstance;wndClass.lpszClassName = pszClassName;wndClass.lpszMenuName = NULL;BOOL bRet;bRet = RegisterClass(&wndClass);if (!bRet){MessageBox(NULL, _T("注册窗口类失败"), NULL, MB_OK);return FALSE;}HWND hWnd;hWnd = CreateWindow(pszClassName,_T("MyApplication"),WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,//添加垂直滚动条和水平滚动条CW_USEDEFAULT,CW_USEDEFAULT,600,480,NULL,NULL,hInstance,NULL);if (!hWnd){MessageBox(NULL, _T("创建窗口失败!"), NULL, MB_OK);return FALSE;}ShowWindow(hWnd, nShowCmd);UpdateWindow(hWnd);MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}//窗口过程LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){static int cxClient, cyClient, cxChar, cyChar, cxCaps;HDC hdc;PAINTSTRUCT ps;TEXTMETRIC tm;SCROLLINFO scrollInfo;int iVertPos, iHorzPos;int iBegin, iEnd;switch (uMsg){case WM_CREATE:hdc = GetDC(hWnd);GetTextMetrics(hdc, &tm);cxChar = tm.tmAveCharWidth;cyChar = tm.tmHeight + tm.tmExternalLeading;cxCaps = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH ? 3 : 2) * cxChar / 2;ReleaseDC(hWnd, hdc);return 0;case WM_SIZE://第一条WM_SIZE消息是在WinMain函数调用CraeteWindow后,在ShowWindow时产生的,//所以这里获取客户区的大小进行初始化是可以的cxClient = LOWORD(lParam);cyClient = HIWORD(lParam);scrollInfo.cbSize = sizeof(SCROLLINFO);scrollInfo.fMask = SIF_PAGE | SIF_RANGE;//设置垂直滚动条scrollInfo.nMin = 0;scrollInfo.nMax = MAX_NUM_ROW -1;scrollInfo.nPage = cyClient / cyChar;//更新SetScrollInfo(hWnd, SB_VERT, &scrollInfo, TRUE);//设置水平滚动条scrollInfo.nMin = 0;scrollInfo.nMax = 100;scrollInfo.nPage = cxClient / cxChar;SetScrollInfo(hWnd, SB_HORZ, &scrollInfo, TRUE);return 0;case WM_VSCROLL:scrollInfo.cbSize = sizeof(SCROLLINFO);scrollInfo.fMask = SIF_ALL;GetScrollInfo(hWnd, SB_VERT, &scrollInfo);iVertPos = scrollInfo.nPos;switch (LOWORD(wParam)){case SB_LINEUP:scrollInfo.nPos -= 1;break;case SB_LINEDOWN:scrollInfo.nPos += 1;break;case SB_PAGEUP:scrollInfo.nPos -= scrollInfo.nPage;break;case SB_PAGEDOWN:scrollInfo.nPos += scrollInfo.nPage;break;case SB_THUMBTRACK:scrollInfo.nPos = scrollInfo.nTrackPos;break;}scrollInfo.fMask = SIF_POS;SetScrollInfo(hWnd, SB_VERT, &scrollInfo, TRUE);GetScrollInfo(hWnd, SB_VERT, &scrollInfo);if (iVertPos != scrollInfo.nPos){//滚动客户区的内容,这里参数设置代表了整个客户区,滚动后,没有覆盖的区域将参与重绘ScrollWindow(hWnd,  0,  (iVertPos - scrollInfo.nPos) * cyChar, //这里为内容的滚动方向,向上则加上负值 NULL,  NULL);UpdateWindow(hWnd);//立即更新无效的区域,此处为未被覆盖的局域}return 0;case WM_HSCROLL:scrollInfo.cbSize = sizeof(SCROLLINFO);scrollInfo.fMask = SIF_ALL;GetScrollInfo(hWnd, SB_HORZ, &scrollInfo);iHorzPos = scrollInfo.nPos;switch (LOWORD(wParam)){case SB_LINELEFT:scrollInfo.nPos -= 1;break;case SB_LINERIGHT:scrollInfo.nPos += 1;break;case SB_PAGELEFT:scrollInfo.nPos -= scrollInfo.nPage;break;case SB_PAGERIGHT:scrollInfo.nPos += scrollInfo.nPage;break;case SB_THUMBTRACK:scrollInfo.nPos = scrollInfo.nTrackPos;break;}scrollInfo.fMask = SIF_POS;SetScrollInfo(hWnd, SB_HORZ, &scrollInfo, TRUE);GetScrollInfo(hWnd, SB_HORZ, &scrollInfo);if (scrollInfo.nPos != iHorzPos){ScrollWindow(hWnd, cxChar * (iHorzPos - scrollInfo.nPos),0, NULL, NULL);}return 0;case WM_PAINT:hdc = BeginPaint(hWnd, &ps);scrollInfo.cbSize = sizeof(SCROLLINFO);scrollInfo.fMask = SIF_POS;GetScrollInfo(hWnd, SB_VERT, &scrollInfo);iVertPos = scrollInfo.nPos;//当前垂直滚动条的位置GetScrollInfo(hWnd, SB_HORZ, &scrollInfo);iHorzPos = scrollInfo.nPos;//当前水平滚动条的位置//确保滚动条滑块位置在 0--MAX_NUM_ROW之间iBegin = max(0, iVertPos + ps.rcPaint.top / cyChar);//无效区域对应的开始行,这句话是多余的,//因为开始设置的iVertPos大于0,而无效区域的矩形的坐标一般也是个正直//(InValidate可以设置坐标为负的矩形,但windows会做处理。对于不同的映射模式也一样吗?)iEnd = min(MAX_NUM_ROW - 1, iVertPos + ps.rcPaint.bottom / cyChar);//无效区域对应的结束行for (int row = iBegin; row <= iEnd; ++row){TCHAR buffer[100] = {0};TextOut(hdc,-iHorzPos * cxChar,(row - iVertPos) * cyChar,buffer,_stprintf(buffer, _T("第%3d行"), row + 1));}EndPaint(hWnd, &ps);return 0;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc(hWnd, uMsg, wParam, lParam);}

3、运行结果如下图



显然,解决了最后一行不能显示在客户区底部的问题。此外这里绘制是根据客户区无效的区域来确定对应内容的显示。当行号设置得更大时,绘制的效率也是一样的。

4、ScrollWindow的使用

BOOL ScrollWindow(  HWND hWnd,              // handle to window  int XAmount,            // horizontal scrolling  int YAmount,            // vertical scrolling  CONST RECT *lpRect,     // client area  CONST RECT *lpClipRect  // clipping rectangle);
见下图:


左边为滚动前的内容,右边为滚动后的内容。
其中红色区域为滚动区域,将内容向上滚动一行后,右边蓝色矩形区域为未被滚动区域覆盖的,那么这部分会被重绘。而红色区域不参与重绘,只是滚动之后的结果,内容不变,只是位置发生了改变而已!
0 0
原创粉丝点击