windows程序设计(5)使用滚动条

来源:互联网 发布:c语言printf和scanf 编辑:程序博客网 时间:2024/06/05 22:39

本文的程序来自《windows程序设计(第五版)》

设计滚动条的初衷,是因为客户区需要显示的东西太多了,在这个头文件中,我们包含了一大堆的系统的信息:

//总行数#define NUMLINES  ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))struct{int Index ;TCHAR* szLabel;TCHAR* szDesc ;}//结构体数组sysmetrics [] =        {        SM_CXSCREEN,TEXT ("SM_CXSCREEN"),TEXT ("Screen width in pixels"),        SM_CYSCREEN,TEXT ("SM_CYSCREEN"),TEXT ("Screen height in pixels"),           SM_CXVSCROLL,TEXT ("SM_CXVSCROLL"),TEXT ("Vertical scroll width"),            SM_CYHSCROLL,TEXT ("SM_CYHSCROLL"),TEXT ("Horizontal scroll height"),            SM_CYCAPTION,TEXT ("SM_CYCAPTION"),TEXT ("Caption bar height"),            SM_CXBORDER,TEXT ("SM_CXBORDER"),TEXT ("Window border width"),            SM_CYBORDER,TEXT ("SM_CYBORDER"),TEXT ("Window border height"),            SM_CXFIXEDFRAME,TEXT ("SM_CXFIXEDFRAME"),TEXT ("Dialog window frame width"),            SM_CYFIXEDFRAME,TEXT ("SM_CYFIXEDFRAME"),TEXT ("Dialog window frame height"),            SM_CYVTHUMB,TEXT ("SM_CYVTHUMB"),TEXT ("Vertical scroll thumb height"),            SM_CXHTHUMB,TEXT ("SM_CXHTHUMB"),TEXT ("Horizontal scroll thumb width"),            SM_CXICON,TEXT ("SM_CXICON"),TEXT ("Icon width"),            SM_CYICON,TEXT ("SM_CYICON"),TEXT ("Icon height"),            SM_CXCURSOR,TEXT ("SM_CXCURSOR"),TEXT ("Cursor width"),            SM_CYCURSOR,TEXT ("SM_CYCURSOR"),TEXT ("Cursor height"),            SM_CYMENU,TEXT ("SM_CYMENU"),TEXT ("Menu bar height"),            SM_CXFULLSCREEN,TEXT ("SM_CXFULLSCREEN"),TEXT ("Full screen client area width"),            SM_CYFULLSCREEN,TEXT ("SM_CYFULLSCREEN"),TEXT ("Full screen client area height"),            SM_CYKANJIWINDOW,TEXT ("SM_CYKANJIWINDOW"),TEXT ("Kanji window height"),            SM_MOUSEPRESENT,TEXT ("SM_MOUSEPRESENT"),TEXT ("Mouse present flag"),            SM_CYVSCROLL,TEXT ("SM_CYVSCROLL"),TEXT ("Vertical scroll arrow height"),            SM_CXHSCROLL,TEXT ("SM_CXHSCROLL"),TEXT ("Horizontal scroll arrow width"),            SM_DEBUG,TEXT ("SM_DEBUG"),TEXT ("Debug version flag"),            SM_SWAPBUTTON,TEXT ("SM_SWAPBUTTON"),TEXT ("Mouse buttons swapped flag"),            SM_CXMIN,TEXT ("SM_CXMIN"),TEXT ("Minimum window width"),            SM_CYMIN,TEXT ("SM_CYMIN"),TEXT ("Minimum window height"),            SM_CXSIZE,TEXT ("SM_CXSIZE"),TEXT ("Min/Max/Close button width"),            SM_CYSIZE,TEXT ("SM_CYSIZE"),TEXT ("Min/Max/Close button height"),            SM_CXSIZEFRAME,TEXT ("SM_CXSIZEFRAME"),TEXT ("Window sizing frame width"),            SM_CYSIZEFRAME,TEXT ("SM_CYSIZEFRAME"),TEXT ("Window sizing frame height"),            SM_CXMINTRACK,TEXT ("SM_CXMINTRACK"),TEXT ("Minimum window tracking width"),            SM_CYMINTRACK,TEXT ("SM_CYMINTRACK"),TEXT ("Minimum window tracking height"),            SM_CXDOUBLECLK,TEXT ("SM_CXDOUBLECLK"),TEXT ("Double click x tolerance"),            SM_CYDOUBLECLK,TEXT ("SM_CYDOUBLECLK"),TEXT ("Double click y tolerance"),            SM_CXICONSPACING,TEXT ("SM_CXICONSPACING"),TEXT ("Horizontal icon spacing"),            SM_CYICONSPACING,TEXT ("SM_CYICONSPACING"),TEXT ("Vertical icon spacing"),            SM_MENUDROPALIGNMENT,TEXT ("SM_MENUDROPALIGNMENT"),TEXT ("Left or right menu drop"),            SM_PENWINDOWS,TEXT ("SM_PENWINDOWS"),TEXT ("Pen extensions installed"),            SM_DBCSENABLED,TEXT ("SM_DBCSENABLED"),TEXT ("Double-Byte Char Set enabled"),            SM_CMOUSEBUTTONS,TEXT ("SM_CMOUSEBUTTONS"),TEXT ("Number of mouse buttons"),           SM_SECURE,TEXT ("SM_SECURE"),TEXT ("Security present flag"),            SM_CXEDGE,TEXT ("SM_CXEDGE"),TEXT ("3-D border width"),            SM_CYEDGE,TEXT ("SM_CYEDGE"),TEXT ("3-D border height"),            SM_CXMINSPACING,TEXT ("SM_CXMINSPACING"),TEXT ("Minimized window spacing width"),            SM_CYMINSPACING,TEXT ("SM_CYMINSPACING"),TEXT ("Minimized window spacing height"),            SM_CXSMICON,TEXT ("SM_CXSMICON"),TEXT ("Small icon width"),           SM_CYSMICON,TEXT ("SM_CYSMICON"),TEXT ("Small icon height"),            SM_CYSMCAPTION,TEXT ("SM_CYSMCAPTION"),TEXT ("Small caption height"),            SM_CXSMSIZE,TEXT ("SM_CXSMSIZE"),TEXT ("Small caption button width"),            SM_CYSMSIZE,TEXT ("SM_CYSMSIZE"),TEXT ("Small caption button height"),            SM_CXMENUSIZE,TEXT ("SM_CXMENUSIZE"),TEXT ("Menu bar button width"),            SM_CYMENUSIZE,TEXT ("SM_CYMENUSIZE"),TEXT ("Menu bar button height"),            SM_ARRANGE,TEXT ("SM_ARRANGE"),TEXT ("How minimized windows arranged"),            SM_CXMINIMIZED,TEXT ("SM_CXMINIMIZED"),TEXT ("Minimized window width"),            SM_CYMINIMIZED,TEXT ("SM_CYMINIMIZED"),TEXT ("Minimized window height"),            SM_CXMAXTRACK,TEXT ("SM_CXMAXTRACK"),TEXT ("Maximum draggable width"),            SM_CYMAXTRACK,TEXT ("SM_CYMAXTRACK"),TEXT ("Maximum draggable height"),            SM_CXMAXIMIZED,TEXT ("SM_CXMAXIMIZED"),TEXT ("Width of maximized window"),            SM_CYMAXIMIZED,TEXT ("SM_CYMAXIMIZED"),TEXT ("Height of maximized window"),            SM_NETWORK,TEXT ("SM_NETWORK"),TEXT ("Network present flag"),            SM_CLEANBOOT,TEXT ("SM_CLEANBOOT"),TEXT ("How system was booted"),            SM_CXDRAG,TEXT ("SM_CXDRAG"),TEXT ("Avoid drag x tolerance"),            SM_CYDRAG,TEXT ("SM_CYDRAG"),TEXT ("Avoid drag y tolerance"),            SM_SHOWSOUNDS,TEXT ("SM_SHOWSOUNDS"),TEXT ("Present sounds visually"),            SM_CXMENUCHECK,TEXT ("SM_CXMENUCHECK"),TEXT ("Menu check-mark width"),            SM_CYMENUCHECK,TEXT ("SM_CYMENUCHECK"),TEXT ("Menu check-mark height"),            SM_SLOWMACHINE,TEXT ("SM_SLOWMACHINE"),TEXT ("Slow processor flag"),            SM_MIDEASTENABLED,TEXT ("SM_MIDEASTENABLED"),TEXT ("Hebrew and Arabic enabled flag"),            SM_MOUSEWHEELPRESENT,TEXT ("SM_MOUSEWHEELPRESENT"),TEXT ("Mouse wheel present flag"),            SM_XVIRTUALSCREEN,TEXT ("SM_XVIRTUALSCREEN"),TEXT ("Virtual screen x origin"),            SM_YVIRTUALSCREEN,TEXT ("SM_YVIRTUALSCREEN"),TEXT ("Virtual screen y origin"),            SM_CXVIRTUALSCREEN,     TEXT ("SM_CXVIRTUALSCREEN"),TEXT ("Virtual screen width"),            SM_CYVIRTUALSCREEN,TEXT ("SM_CYVIRTUALSCREEN"),TEXT ("Virtual screen height"),            SM_CMONITORS,TEXT ("SM_CMONITORS"),TEXT ("Number of monitors"),            SM_SAMEDISPLAYFORMAT,TEXT ("SM_SAMEDISPLAYFORMAT"),TEXT ("Same color format flag")        } ;


第一行定义的,是数组有多少个元素。之后我们定义了结构体数组。元素个数很多,一行显示不下,那么如何添加滚动条呢?

我们先看程序:

#include <windows.h>#include "sysmets.h"LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);int WINAPI WinMain(HINSTANCE hInstance,//当前实例句柄   HINSTANCE hPrevInstance, //先前实例句柄   LPSTR lpCmdLine,//命令行   int iCmdShow)//显示状态{static TCHAR szAppName[] = TEXT("显示系统内容");//窗口句柄HWND hwnd;//消息MSG msg;//窗口类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)){return -1;}//创建窗口hwnd = CreateWindow(szAppName,//窗口类的名称,必须是已经注册的TEXT("系统内容"),//窗口标题WS_OVERLAPPEDWINDOW | WS_VSCROLL,//窗口风格,加入垂直滚动条CW_USEDEFAULT,//X坐标CW_USEDEFAULT,//Y坐标CW_USEDEFAULT,//宽度CW_USEDEFAULT,//高度NULL,//父窗口句柄NULL,//菜单窗口句柄hInstance,//高级版本的windos忽略NULL);//显示窗口//ShowWindow(hwnd,SW_SHOWNA);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 ;//窗口大小static int cxClient, cyClient ;//滚动条位置static int iVscrollPos; HDC hdc;//该变量用于索引sysmets.h中定义的结构体数组sysmetrics[]的每个元素int i;//输出文本的垂直位置int y;//绘图结构PAINTSTRUCT ps;//字符串TCHAR szBuffer [10];//字体信息结构TEXTMETRIC  tm;switch(message){case WM_CREATE:hdc = GetDC(hwnd);//取得内定系统字体的文字大小,存在放在tm里GetTextMetrics (hdc, &tm);//平均字符宽cxChar = tm.tmAveCharWidth ;//大写字母的平平均宽度cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;//字符总高度:高度+行间距cyChar = tm.tmHeight + tm.tmExternalLeading ;ReleaseDC(hwnd,hdc);//设置滚动条范围:参数为:窗口句柄,滚动条类型,最小位置,最大位置,是否重绘SetScrollRange (hwnd, SB_VERT, 0, NUMLINES - 1, FALSE);//滚动条的方块的位置,参数为:窗口句柄,滚动条类型,新的位置SetScrollPos   (hwnd, SB_VERT, iVscrollPos, TRUE); return 0;case WM_SIZE:       cxClient = LOWORD (lParam) ;        cyClient = HIWORD (lParam) ;       return 0; case WM_PAINT:hdc = BeginPaint (hwnd, &ps) ;for(i = 0;i < NUMLINES;i++ ){//行宽度*变动的行数y =  cyChar * (i - iVscrollPos) ;//输出字符串到指定的区域(使用当前的字体,背景颜色,颜色)//参数为:设备内容句柄,x坐标,y坐标,带输出的字符串(与是否/0结尾无关),字符的个数//lstrlen计算字符串长度TextOut(hdc,0,y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));//从22个大写字母以后的位置输出,因为第一列最多只有20个大写字母TextOut(hdc,22*cxCaps,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));//最后一列是右对齐的SetTextAlign(hdc,TA_RIGHT | TA_TOP);//40*cxChar是第二列及第三列的列宽//wsprintf用来给指定的buffer中格式化并存储字符串(0结尾),返回值为字符串的数目//GetSystemMetrics用来获取系统参数,返回值为系统参数TextOut(hdc,22*cxCaps+40*cxChar,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics (sysmetrics[i].Index)));//再把对齐方式改回去,否则下一次循环时也是右对齐SetTextAlign(hdc,TA_LEFT | TA_TOP);}EndPaint (hwnd, &ps) ;return 0;//滚动条消息case WM_VSCROLL://通过滚动条消息的wParam表明滚动条的操作switch(LOWORD (wParam)){//点一下上箭头:向下翻一行case SB_LINEUP:iVscrollPos -=1;break;//点一下下箭头:向上翻一行case SB_LINEDOWN:iVscrollPos +=1;break;//点一下方块上面:向上翻一页,每一页是:(客户区/一行高度)这么多行case SB_PAGEUP:iVscrollPos -= cyClient / cyChar ;break;//点一下方块下面:向下翻一页case SB_PAGEDOWN:iVscrollPos += cyClient / cyChar ;break;//拖动滚动条:wParam的高字节表明了滚动条的位置case SB_THUMBPOSITION:iVscrollPos = HIWORD (wParam) ;break;default:break;}//这一句是为了iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ; //如果滚动条位置改变 if (iVscrollPos != GetScrollPos (hwnd, SB_VERT)) {//设置滚动条小方块的位置SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;//设为无效区,激励WM_PAINT消息InvalidateRect (hwnd, NULL, TRUE) ; }return 0;case  WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc (hwnd, message, wParam, lParam) ;}

程序的思路是这样的:在创建窗口时,就要告诉系统你要加一个滚动条(垂直的),在WM_CREATE消息中,就要对滚动条进行一些基本的设置。WM_VSCROLL对滚动条做出相应,可以分为3部分:第一部分接收滚动条的消息;第二部分是让滚动条的那个小方块滚动到特定的位置,第三部分是页面的文字出现“滚动”的效果。

先看第一部分:滚动条的作用是什么:当点击一下向上或者向下的按钮时,会滚动一行文字;当点击滚动的小方块的上面或者下面时,会滚动一页文字;而拖着滚动条走,能滚动到指定的地方。到底是这几种操作的哪一种,是通过WM_VSCROLL消息的wParam的低字节传过来的。在程序中,使用iVscrollPos这个全局变量来记录滚动的位置,每一次对滚动条都会改变位置。

iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ;是为了不让滚动条的位置超出一定为范围,大家可以把它屏蔽之后,将滚动条向上或者向下滚,就可以理解结果了。
而通过SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;就将滚动条的方块放到了可定位位置。而第三部分让页面滚动,则是WM_PAINT的作用了:其实当你看到第二行显示在原来第一行为位置上时,其实并不是系统没有输出第一行,而是第一行输出的位置已经到了客户区的上面,所以你看不到!第二行紧跟在第一行下面,刚好就放到了开始的位置。

这个滚动条有一个明显的缺点,就是他并不是我们希望看到的那样:滚动条的长度反应的当前页面占显示的内容总的内容的百分比,具体的说,就是:

页面方块的大小/滚动的长度=页面大小/整个范围=显示文件的数量/整个文件的数量

别看这只是一点小小的改动,但是他的实现方法却与上面的差别很大。总体上来说,他需要使用SCROLLINFO结构来记录滚动条的信息,然后使用GetScrollInfo获取信息,通过SetScrollInfo设置信息。在对滚动条的响应消息中,通过ScrollWindow来实现内容的滚动(而不像前面那个程序,在WM_PAINT消息下实现)。

我们在看看程序:

#include <windows.h>#include "sysmets.h"LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);int WINAPI WinMain(HINSTANCE hInstance,//当前实例句柄   HINSTANCE hPrevInstance, //先前实例句柄   LPSTR lpCmdLine,//命令行   int iCmdShow)//显示状态{static TCHAR szAppName[] = TEXT("显示系统内容");//窗口句柄HWND hwnd;//消息MSG msg;//窗口类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)){return -1;}//创建窗口hwnd = CreateWindow(szAppName,//窗口类的名称,必须是已经注册的TEXT("系统内容"),//窗口标题WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,//窗口风格,加入滚动条CW_USEDEFAULT,//X坐标CW_USEDEFAULT,//Y坐标CW_USEDEFAULT,//宽度CW_USEDEFAULT,//高度NULL,//父窗口句柄NULL,//菜单窗口句柄hInstance,//高级版本的windos忽略NULL);//显示窗口//ShowWindow(hwnd,SW_SHOWNA);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 ;//窗口大小static int cxClient, cyClient ;//最大宽度static int iMaxWidth;//滚动条位置static int iVertPos,iHorzPos,iPaintBeg,iPaintEnd;HDC hdc;//该变量用于索引sysmets.h中定义的结构体数组sysmetrics[]的每个元素int i;//输出文本的位置int x,y;//绘图结构PAINTSTRUCT ps;//这个结构包含了滚动条的信息//通过SetScrollInfo函数设置信息,通过 GetScrollInfo 函数获取信息SCROLLINFO si;//字符串TCHAR szBuffer [10];//字体信息结构TEXTMETRIC  tm;switch(message){case WM_CREATE:hdc = GetDC(hwnd);//取得内定系统字体的文字大小,存在放在tm里GetTextMetrics (hdc, &tm);//平均字符宽cxChar = tm.tmAveCharWidth ;//大写字母的平均宽度cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;//字符总高度:高度+行间距cyChar = tm.tmHeight + tm.tmExternalLeading ;ReleaseDC(hwnd,hdc);//最大跨度 = 40个字符+22个大写字母iMaxWidth = 40*cxChar+22*cxCaps;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);//设置水平滚动条信息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_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;//max(0,当前位置+需要绘图的矩形区的最高点/字符的高度)//iPaintBeg = max(0,iVertPos+ps.rcPaint.top/cyChar);iPaintBeg = max(0,iVertPos);//绘图结束的地方 = 当前位置+绘制去取的高度iPaintEnd = min(NUMLINES -1,iVertPos+ps.rcPaint.bottom/cyChar);for(i = iPaintBeg; i <= iPaintEnd;i++){//绘图的x起始位置:1是自己设置的,设置越大离左边越宽x = cxChar * (1 - iHorzPos) ;//绘图的y起始位置。y = cyChar * (i - iVertPos) ;TextOut(hdc,x, y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));  //从22个大写字母以后的位置输出,因为第一列最多只有20个大写字母  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].Index))); SetTextAlign(hdc,TA_LEFT | TA_TOP);  }EndPaint (hwnd, &ps) ;return 0;//垂直滚动条消息case WM_VSCROLL://获取垂直滚动条信息si.cbSize = sizeof(si);//所有参数si.fMask = SIF_ALL;GetScrollInfo(hwnd,SB_VERT,&si);//垂直位置iVertPos = si.nPos ;//通过滚动条消息的wParam表明滚动条的操作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;case SB_PAGEUP:si.nPage -= 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;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_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProc (hwnd, message, wParam, lParam) ;}


 

程序中有几点需要注意:

1.程序中设置了垂直滚动条和水平滚动条。在WM_SIZE消息中,随着窗口的变化,滚动条的那个小方块的大小也在变化。

2.在每次使用GetScrollInfo或者SetScrollInfo之前,都必须有si.cbSize  = sizeof(si);这是因为兼容的缘故。而且还得指明操作的是SCROLLINFO中的哪些内容,这通过fMask来控制。

3.程序中有几行代码很费解:

iPaintBeg = max(0,iVertPos+ps.rcPaint.top/cyChar);实际上,由于ps.rcPaint.top=0,这行代码也可以写为:iPaintBeg = max(0,iVertPos);

iPaintEnd = min(NUMLINES -1,iVertPos+ps.rcPaint.bottom/cyChar);画图的结束位置=滚动条当前的位置+绘制的行数,而行数=客户区宽度/每一行的宽度;

x = cxChar * (1 - iHorzPos) ;绘图的x坐标,那个1是为了不是太“顶格”,你也可以把它设置大一点,结果就很明显了。

 

 

原创粉丝点击