Windows程序设计--设置滚动条详解二
来源:互联网 发布:网络流行欧美歌曲 编辑:程序博客网 时间:2024/05/18 00:45
用以下一个结构和三个函数就能设置滚动条了
1.滚动条信息结构
//SetScrollInfo函数设置这个结构的信息//GetScrollInfo函数返回这个结构的信息typedef struct tagSCROLLINFO { UINT cbSize; //存储这个结构的大小,以字节为单位 UINT fMask; //标志这个结构的哪些值被设置或被获取 int nMin; //滚动条的最小位置 int nMax; //滚动条的最大位置//一般这两个参数一起构成滚动条范围 UINT nPage; //页面大小 int nPos; //滚动条位置 int nTrackPos; //可以随着用户的拖动而显示当前滚动条位置} SCROLLINFO; typedef SCROLLINFO FAR* LPSCROLLINFO; /* fMask: SIF_ALL:结构中参数全部有效(都可以被用) SIF_DISABLENOSCROLL:这个值是只有当设置滚动条的参数使用。如果滚动条的新参数使滚动条不必要的,禁用滚动条,而不是删除它。 SIF_PAGE:nPage有效 SIF_POS:nPos有效 SIF_RANGE:nMin,nMax有效 SIF_TRACKPOS:nTrackPos有效*/
2.获取滚动条信息
BOOL GetScrollInfo( HWND hwnd, //窗口句柄 int fnBar, //指定返回哪个滚动条的参数,SB_CTL(控件),SB_HORZ(水平滚动条),SB_VERT(垂直滚动条) LPSCROLLINFO lpsi //滚动条信息结构);
3.设置滚动条信息
int SetScrollInfo( HWND hwnd, //窗口句柄 int fnBar, //指定哪个滚动条的参数 LPSCROLLINFO lpsi, //滚动条信息结构 BOOL fRedraw //是否重画滚动条,也就是即时显示滚动条 //TRUE表示重画,FALSE表示不重画);
4.滚动窗口
BOOL ScrollWindow( HWND hWnd, //窗口句柄 int XAmount, //指定水平滚动以设备为单位的数量。如果窗体被滚动模式为 //CS_OWNDC或CS_CLASSDC,此参数则使用逻辑单位而不使用设备单位。 //当向左滚动窗体内容时,参数值必须为负。 int YAmount, //指定垂直滚动以设备为单位的数量。 const RECT *lpRect,//指向所指定将被滚动的客户区域部分的RECT结构。若此参数为NULL,则整个客户区域均被滚动。 const RECT *lpClipRect//指向包含类似于剪辑滚动条RECT结构。只有剪辑矩形条内部的位受影响。 //由外向内的滚动矩形内部被着色,而由矩形内向外的滚动将不被着色。);
主要步骤:
1.向窗口添加滚动条风格
2.WM_CREATE消息中设置字体信息.
3.在WM_SZIE消息中获取客户区宽度和高度
4.在WM_SIZE消息中设置滚动条范围和位置
5.在WM_VSCROLL和WM_HSCROLL消息中滚动滑块的位置
6.在WM_PAINT消息中显示滚动滑块后的内容
详细代码如下:
#include <windows.h>LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//全局变量存储错误信息DWORD dwError = 0;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT("Scroll"); HWND hwnd=nullptr; MSG msg = {0}; WNDCLASS wndclass = {0}; //创建窗口类 wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(nullptr, IDI_APPLICATION); wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = nullptr; wndclass.lpszClassName = szAppName; //注册窗口类 if (!RegisterClass(&wndclass)) { MessageBox(nullptr, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } //创建窗口 hwnd = CreateWindow(szAppName, TEXT("ScrollDemo"), WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,//添加滚动条风格 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr); if (!hwnd) { dwError = GetLastError(); return 0; } //显示窗口 ShowWindow(hwnd, iCmdShow); //更新窗口 UpdateWindow(hwnd); //获取队列中的消息 while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}//窗口过程函数LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ //字体的宽度,高度,cxCaps是宽字符的宽度 static int cxChar = 0, cxCaps = 0, cyChar = 0; //滚动条的垂直位置和水平位置 static int iVertPos = 0, iHorzPos = 0; //获取当前客户区可容纳的行数和列数 static int cxColumn = 0, cyLine = 0; //客户区宽度和高度 static int cxClient = 0, cyClient = 0; //鼠标滑动信息 static int iDeltaPerLine = 0, iAccumDelta = 0; ULONG ulScrollLines = 0; int i = 0, temp = 0, ix = 0, iy = 0; //设备环境句柄 HDC hdc = nullptr; //绘图信息结构 PAINTSTRUCT ps = { 0 }; //字体信息结构 TEXTMETRIC tm = { 0 }; //滚动条信息结构 SCROLLINFO si = {0}; switch (message) { case WM_CREATE: hdc = GetDC(hwnd); //获取字体信息,一般系统默认 GetTextMetrics(hdc, &tm); //字符宽度 cxChar = tm.tmAveCharWidth; //判断是否是宽字符,宽字符就是1.5cxChar cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2; //字符高度 cyChar = tm.tmHeight + tm.tmExternalLeading; ReleaseDC(hwnd, hdc); case WM_SETTINGCHANGE: //SPI_GETWHEELSCROLLLINES:用于Windows NT 4.0及以后版本、 //Windows 98。当前轨迹球转动时,获取滚动的行数。参数pvParam //必须指向UINT类型变量以接收行数。缺省值是3。 if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0)) { dwError = GetLastError(); break; } // 增量数值用WHEEL_DELTA来标识,它等于120 if (ulScrollLines)//每滚动一行的增量是40 iDeltaPerLine = WHEEL_DELTA / ulScrollLines; else iDeltaPerLine = 0; return 0; case WM_SIZE: //获取客户区宽度和高度,每当你改变窗口大小的时候它 //都会发生改变。 cxClient = LOWORD(lParam); cyClient = HIWORD(lParam); //获取当前客户区可容纳的列数 cxColumn = cxClient / cxChar; //获取当前客户区可容纳的行数 cyLine = cyClient / cyChar; //设置垂直滚动条范围和初始位置 si.cbSize = sizeof(si);//要使用这个结构,必须要把它的大小传入进去 si.fMask = SIF_RANGE | SIF_PAGE|SIF_POS;//范围、页面大小和位置三个参数有效 si.nMin = 0;//设置范围的最小值 si.nMax = cyClient/cyChar+200;//设置范围的最大值后面的根据实际值来加 si.nPos = 0;//设置滚动条初始位置 si.nPage= cyClient / cyChar;//设置页面大小 //用SetScrollInfo函数设置垂直滚动条信息(结构中的值传入函数) SetScrollInfo(hwnd, SB_VERT, &si, TRUE); //设置水平滚动条范围和初始位置 si.cbSize = sizeof(si);//要使用这个结构,必须要把它的大小传入进去 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;//范围、页面大小和位置三个参数有效 si.nMin = 0;//设置范围的最小值 si.nMax = cxClient / cxChar+20;//设置范围的最大值 si.nPos = 0;//设置滚动条初始位置 si.nPage = cxClient / cxChar;//设置页面大小 //用SetScrollInfo函数设置水平滚动条信息(结构中的值传入函数) 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; //接收到用户拖动滑块消息 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_TOP: si.nPos = si.nMin; break; case SB_BOTTOM: si.nPos = si.nMax; 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), nullptr, nullptr); UpdateWindow(hwnd); } return 0; case WM_HSCROLL: //获取水平滚动条全部信息 si.cbSize = sizeof(si); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_HORZ, &si); //记录未改变时的滑块位置 iHorzPos=si.nPos; //接收到用户拖动滑块消息 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_THUMBTRACK: 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, nullptr, nullptr); UpdateWindow(hwnd); } return 0; //键盘消息 case WM_KEYDOWN: //如果有按下方向键 switch (LOWORD(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_LEFT: SendMessage(hwnd, WM_HSCROLL, SB_LINELEFT, 0); break; case VK_RIGHT: SendMessage(hwnd, WM_HSCROLL, SB_LINERIGHT, 0); break; //PageUp case VK_PRIOR: SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0); break; //PageDown case VK_NEXT: SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0); //Bottom case VK_END: SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0); break; case VK_HOME: SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0); break; default: break; } return 0; //鼠标滚轮消息 case WM_MOUSEWHEEL: //如果增量等于0就是没有滚动就退出 if (iDeltaPerLine == 0) break; iAccumDelta += (short)HIWORD(wParam); // 120 or -120 while (iAccumDelta >= iDeltaPerLine) { SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0); iAccumDelta -= iDeltaPerLine; } while (iAccumDelta <= -iDeltaPerLine) { SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0); iAccumDelta += iDeltaPerLine; } 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; for (int i = 0;i < 70;i++) { ix = cxChar*(1 - iHorzPos); iy = cyChar*(i - iVertPos); TextOut(hdc,ix,iy,L"1234567845623132",wcslen(L"1234567845623132") ); } EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam);}
要注意几点:
1.设置范围si.nMax的时候,它决定了你能滑动多少行。比如你要显示100行,但是客户区只能显示50行,那么你的si.nMax就要设置为cyClient/cyChar(客户区大小)+50(或大于50)才能显示完.
2.初始位置可以自己设置,一般系统默认初始化为0了。
3.si.cbSize一点要设置,不管是在设置或获取结构信息的时候,都要把结构体大小传入。
4.在WM_VSCROLL和WM_HSCROLL中,处理滑块移动前要把当前位置保存下来,处理完后把现在的位置保存起来,比较是否一样,不一样代表滑块移动了,就滚动窗口。
这些都是手动设置滚动条的范围,而不能根据输入多少文本,滚动条范围随之改变。
1 0
- Windows程序设计--设置滚动条详解二
- Windows程序设计--设置滚动条详解一
- Windows程序设计 滚动条
- windows程序设计 滚动条
- windows程序设计(滚动条)
- 读书笔记 - Windows程序设计(滚动条)
- 《Windows程序设计》读书笔记------------->>基本滚动条<<
- 《windows程序设计》(三)-------滚动条编程
- windows程序设计(5)使用滚动条
- windows程序设计读书笔记之滚动条
- windows程序设计 更好的滚动条
- windows程序设计-滚动条的实现
- MFC Windows程序设计学习笔记--滚动条
- 《Windows程序设计》读书笔记之二——输出文字与滚动条使用
- ListView等滚动条的设置详解
- 《Windows程序设计》读书笔记------------->>滚动条使用(翻译自MSDN)<<
- windows程序设计(13):给滚动条加上键盘响应
- 设置滚动条向下滚动
- ObjectOutputStream 追加写入读取错误
- Robi改造计划-开篇
- android Installation error: INSTALL_FAILED_DUPLICATE_PERMISSION 解决方案
- uLua中遇到的问题
- ubuntu中wine的安装位置
- Windows程序设计--设置滚动条详解二
- ucenter单点登录
- Mysql5.7在linux上安装步骤
- House Robber I & II | LeetCode
- zzulioj 1827: 石锅全拌 (线段树求区间和)
- Objective-C语言——实例方法与类方法之间互相调用
- jqurey.fullpage.js解读
- linux 下svn安装配置
- Python模块学习系列(4)----matplotlib