打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

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

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

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

  1. //总行数  
  2. #define NUMLINES  ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))  
  3.   
  4. struct  
  5. {  
  6.     int Index ;  
  7.     TCHAR* szLabel;  
  8.     TCHAR* szDesc ;  
  9.   
  10. }  
  11. //结构体数组  
  12. sysmetrics [] =  
  13.           
  14. {  
  15.           
  16.     SM_CXSCREEN,            TEXT ("SM_CXSCREEN"),           TEXT ("Screen width in pixels"),          
  17.     SM_CYSCREEN,            TEXT ("SM_CYSCREEN"),           TEXT ("Screen height in pixels"),         
  18.     SM_CXVSCROLL,           TEXT ("SM_CXVSCROLL"),          TEXT ("Vertical scroll width"),          
  19.     SM_CYHSCROLL,           TEXT ("SM_CYHSCROLL"),          TEXT ("Horizontal scroll height"),          
  20.     SM_CYCAPTION,           TEXT ("SM_CYCAPTION"),          TEXT ("Caption bar height"),          
  21.     SM_CXBORDER,            TEXT ("SM_CXBORDER"),           TEXT ("Window border width"),          
  22.     SM_CYBORDER,            TEXT ("SM_CYBORDER"),           TEXT ("Window border height"),          
  23.     SM_CXFIXEDFRAME,        TEXT ("SM_CXFIXEDFRAME"),       TEXT ("Dialog window frame width"),          
  24.     SM_CYFIXEDFRAME,        TEXT ("SM_CYFIXEDFRAME"),       TEXT ("Dialog window frame height"),          
  25.     SM_CYVTHUMB,            TEXT ("SM_CYVTHUMB"),           TEXT ("Vertical scroll thumb height"),          
  26.     SM_CXHTHUMB,            TEXT ("SM_CXHTHUMB"),           TEXT ("Horizontal scroll thumb width"),          
  27.     SM_CXICON,              TEXT ("SM_CXICON"),             TEXT ("Icon width"),          
  28.     SM_CYICON,              TEXT ("SM_CYICON"),             TEXT ("Icon height"),          
  29.     SM_CXCURSOR,            TEXT ("SM_CXCURSOR"),           TEXT ("Cursor width"),          
  30.     SM_CYCURSOR,            TEXT ("SM_CYCURSOR"),           TEXT ("Cursor height"),          
  31.     SM_CYMENU,              TEXT ("SM_CYMENU"),             TEXT ("Menu bar height"),          
  32.     SM_CXFULLSCREEN,        TEXT ("SM_CXFULLSCREEN"),       TEXT ("Full screen client area width"),          
  33.     SM_CYFULLSCREEN,        TEXT ("SM_CYFULLSCREEN"),       TEXT ("Full screen client area height"),          
  34.     SM_CYKANJIWINDOW,       TEXT ("SM_CYKANJIWINDOW"),      TEXT ("Kanji window height"),          
  35.     SM_MOUSEPRESENT,        TEXT ("SM_MOUSEPRESENT"),       TEXT ("Mouse present flag"),          
  36.     SM_CYVSCROLL,           TEXT ("SM_CYVSCROLL"),          TEXT ("Vertical scroll arrow height"),          
  37.     SM_CXHSCROLL,           TEXT ("SM_CXHSCROLL"),          TEXT ("Horizontal scroll arrow width"),          
  38.     SM_DEBUG,               TEXT ("SM_DEBUG"),              TEXT ("Debug version flag"),          
  39.     SM_SWAPBUTTON,          TEXT ("SM_SWAPBUTTON"),         TEXT ("Mouse buttons swapped flag"),          
  40.     SM_CXMIN,               TEXT ("SM_CXMIN"),              TEXT ("Minimum window width"),          
  41.     SM_CYMIN,               TEXT ("SM_CYMIN"),              TEXT ("Minimum window height"),          
  42.     SM_CXSIZE,              TEXT ("SM_CXSIZE"),             TEXT ("Min/Max/Close button width"),          
  43.     SM_CYSIZE,              TEXT ("SM_CYSIZE"),             TEXT ("Min/Max/Close button height"),          
  44.     SM_CXSIZEFRAME,         TEXT ("SM_CXSIZEFRAME"),        TEXT ("Window sizing frame width"),          
  45.     SM_CYSIZEFRAME,         TEXT ("SM_CYSIZEFRAME"),        TEXT ("Window sizing frame height"),          
  46.     SM_CXMINTRACK,          TEXT ("SM_CXMINTRACK"),         TEXT ("Minimum window tracking width"),          
  47.     SM_CYMINTRACK,          TEXT ("SM_CYMINTRACK"),         TEXT ("Minimum window tracking height"),          
  48.     SM_CXDOUBLECLK,         TEXT ("SM_CXDOUBLECLK"),        TEXT ("Double click x tolerance"),          
  49.     SM_CYDOUBLECLK,         TEXT ("SM_CYDOUBLECLK"),        TEXT ("Double click y tolerance"),          
  50.     SM_CXICONSPACING,       TEXT ("SM_CXICONSPACING"),      TEXT ("Horizontal icon spacing"),          
  51.     SM_CYICONSPACING,       TEXT ("SM_CYICONSPACING"),      TEXT ("Vertical icon spacing"),          
  52.     SM_MENUDROPALIGNMENT,   TEXT ("SM_MENUDROPALIGNMENT"),  TEXT ("Left or right menu drop"),          
  53.     SM_PENWINDOWS,          TEXT ("SM_PENWINDOWS"),         TEXT ("Pen extensions installed"),          
  54.     SM_DBCSENABLED,         TEXT ("SM_DBCSENABLED"),        TEXT ("Double-Byte Char Set enabled"),          
  55.     SM_CMOUSEBUTTONS,       TEXT ("SM_CMOUSEBUTTONS"),      TEXT ("Number of mouse buttons"),         
  56.     SM_SECURE,              TEXT ("SM_SECURE"),             TEXT ("Security present flag"),          
  57.     SM_CXEDGE,              TEXT ("SM_CXEDGE"),             TEXT ("3-D border width"),          
  58.     SM_CYEDGE,              TEXT ("SM_CYEDGE"),             TEXT ("3-D border height"),          
  59.     SM_CXMINSPACING,        TEXT ("SM_CXMINSPACING"),       TEXT ("Minimized window spacing width"),          
  60.     SM_CYMINSPACING,        TEXT ("SM_CYMINSPACING"),       TEXT ("Minimized window spacing height"),          
  61.     SM_CXSMICON,            TEXT ("SM_CXSMICON"),           TEXT ("Small icon width"),         
  62.     SM_CYSMICON,            TEXT ("SM_CYSMICON"),           TEXT ("Small icon height"),          
  63.     SM_CYSMCAPTION,         TEXT ("SM_CYSMCAPTION"),        TEXT ("Small caption height"),          
  64.     SM_CXSMSIZE,            TEXT ("SM_CXSMSIZE"),           TEXT ("Small caption button width"),          
  65.     SM_CYSMSIZE,            TEXT ("SM_CYSMSIZE"),           TEXT ("Small caption button height"),          
  66.     SM_CXMENUSIZE,          TEXT ("SM_CXMENUSIZE"),         TEXT ("Menu bar button width"),          
  67.     SM_CYMENUSIZE,          TEXT ("SM_CYMENUSIZE"),         TEXT ("Menu bar button height"),          
  68.     SM_ARRANGE,             TEXT ("SM_ARRANGE"),            TEXT ("How minimized windows arranged"),          
  69.     SM_CXMINIMIZED,         TEXT ("SM_CXMINIMIZED"),        TEXT ("Minimized window width"),          
  70.     SM_CYMINIMIZED,         TEXT ("SM_CYMINIMIZED"),        TEXT ("Minimized window height"),          
  71.     SM_CXMAXTRACK,          TEXT ("SM_CXMAXTRACK"),         TEXT ("Maximum draggable width"),          
  72.     SM_CYMAXTRACK,          TEXT ("SM_CYMAXTRACK"),         TEXT ("Maximum draggable height"),          
  73.     SM_CXMAXIMIZED,         TEXT ("SM_CXMAXIMIZED"),        TEXT ("Width of maximized window"),          
  74.     SM_CYMAXIMIZED,         TEXT ("SM_CYMAXIMIZED"),        TEXT ("Height of maximized window"),          
  75.     SM_NETWORK,             TEXT ("SM_NETWORK"),            TEXT ("Network present flag"),          
  76.     SM_CLEANBOOT,           TEXT ("SM_CLEANBOOT"),          TEXT ("How system was booted"),          
  77.     SM_CXDRAG,              TEXT ("SM_CXDRAG"),             TEXT ("Avoid drag x tolerance"),          
  78.     SM_CYDRAG,              TEXT ("SM_CYDRAG"),             TEXT ("Avoid drag y tolerance"),          
  79.     SM_SHOWSOUNDS,          TEXT ("SM_SHOWSOUNDS"),         TEXT ("Present sounds visually"),          
  80.     SM_CXMENUCHECK,         TEXT ("SM_CXMENUCHECK"),        TEXT ("Menu check-mark width"),          
  81.     SM_CYMENUCHECK,         TEXT ("SM_CYMENUCHECK"),        TEXT ("Menu check-mark height"),          
  82.     SM_SLOWMACHINE,         TEXT ("SM_SLOWMACHINE"),        TEXT ("Slow processor flag"),          
  83.     SM_MIDEASTENABLED,      TEXT ("SM_MIDEASTENABLED"),     TEXT ("Hebrew and Arabic enabled flag"),          
  84.     SM_MOUSEWHEELPRESENT,   TEXT ("SM_MOUSEWHEELPRESENT"),  TEXT ("Mouse wheel present flag"),          
  85.     SM_XVIRTUALSCREEN,      TEXT ("SM_XVIRTUALSCREEN"),     TEXT ("Virtual screen x origin"),          
  86.     SM_YVIRTUALSCREEN,      TEXT ("SM_YVIRTUALSCREEN"),     TEXT ("Virtual screen y origin"),          
  87.     SM_CXVIRTUALSCREEN,     TEXT ("SM_CXVIRTUALSCREEN"),    TEXT ("Virtual screen width"),          
  88.     SM_CYVIRTUALSCREEN,     TEXT ("SM_CYVIRTUALSCREEN"),    TEXT ("Virtual screen height"),          
  89.     SM_CMONITORS,           TEXT ("SM_CMONITORS"),          TEXT ("Number of monitors"),          
  90.     SM_SAMEDISPLAYFORMAT,   TEXT ("SM_SAMEDISPLAYFORMAT"),  TEXT ("Same color format flag")  
  91.           
  92. } ;  


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

我们先看程序:

 
  1. #include <windows.h>  
  2. #include "sysmets.h"  
  3.   
  4. LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);  
  5.   
  6. int WINAPI WinMain(HINSTANCE hInstance,     //当前实例句柄  
  7.                    HINSTANCE hPrevInstance, //先前实例句柄  
  8.                    LPSTR lpCmdLine,         //命令行  
  9.                    int iCmdShow)            //显示状态  
  10. {  
  11.     static TCHAR szAppName[] = TEXT("显示系统内容");  
  12.     //窗口句柄  
  13.     HWND hwnd;  
  14.     //消息  
  15.     MSG msg;  
  16.     //窗口类  
  17.     WNDCLASS wndclass;  
  18.     //窗口风格:当移动窗口或者改变大小时重绘窗口  
  19.     wndclass.style         =  CS_HREDRAW | CS_VREDRAW;  
  20.     //指明回调函数  
  21.     wndclass.lpfnWndProc   = WndProc;  
  22.     //额外的比特用来确认下一个窗口类的位置,暂时不用  
  23.     wndclass.cbClsExtra    = 0;  
  24.     //额外的比特用来确认下一个窗口实例的位置,暂时不用  
  25.     wndclass.cbWndExtra    = 0;  
  26.     //实例句柄  
  27.     wndclass.hInstance     = hInstance;  
  28.     //装载图标  
  29.     wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);  
  30.     //装载光标  
  31.     wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);  
  32.     //背景为白色  
  33.     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);  
  34.     //菜单:暂时没有  
  35.     wndclass.lpszMenuName  = NULL;  
  36.     //窗口类名  
  37.     wndclass.lpszClassName = szAppName;  
  38.   
  39.     //注册窗口  
  40.     if(!RegisterClass(&wndclass))  
  41.     {  
  42.         return -1;  
  43.     }  
  44.   
  45.     //创建窗口  
  46.     hwnd = CreateWindow(szAppName,              //窗口类的名称,必须是已经注册的  
  47.                         TEXT("系统内容"),       //窗口标题  
  48.                         WS_OVERLAPPEDWINDOW | WS_VSCROLL,   //窗口风格,加入垂直滚动条  
  49.                         CW_USEDEFAULT,          //X坐标  
  50.                         CW_USEDEFAULT,          //Y坐标  
  51.                         CW_USEDEFAULT,          //宽度  
  52.                         CW_USEDEFAULT,          //高度  
  53.                         NULL,                   //父窗口句柄  
  54.                         NULL,                   //菜单窗口句柄  
  55.                         hInstance,              //高级版本的windos忽略  
  56.                         NULL);                    
  57.   
  58.     //显示窗口  
  59.     //ShowWindow(hwnd,SW_SHOWNA);  
  60.     ShowWindow (hwnd, iCmdShow);  
  61.   
  62.     //更新窗口  
  63.     UpdateWindow(hwnd);  
  64.   
  65.     //消息循环  
  66.     while(GetMessage(&msg,NULL,0,0))  
  67.     {  
  68.           
  69.         TranslateMessage(&msg);  
  70.         //将消息给窗口  
  71.         DispatchMessage(&msg);  
  72.   
  73.     }  
  74.   
  75.     return msg.wParam;  
  76.   
  77. }  
  78.   
  79. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  80. {  
  81.     //字符的宽度,大写字母宽度,字符高度  
  82.     static int    cxChar, cxCaps, cyChar ;  
  83.     //窗口大小  
  84.     static int cxClient, cyClient ;  
  85.     //滚动条位置  
  86.     static int iVscrollPos;   
  87.     HDC hdc;  
  88.     //该变量用于索引sysmets.h中定义的结构体数组sysmetrics[]的每个元素  
  89.     int i;  
  90.     //输出文本的垂直位置  
  91.     int y;  
  92.     //绘图结构  
  93.     PAINTSTRUCT ps;  
  94.     //字符串  
  95.     TCHAR szBuffer [10];  
  96.     //字体信息结构  
  97.     TEXTMETRIC  tm;  
  98.     switch(message)  
  99.     {  
  100.     case WM_CREATE:  
  101.         hdc = GetDC(hwnd);  
  102.         //取得内定系统字体的文字大小,存在放在tm里  
  103.         GetTextMetrics (hdc, &tm);  
  104.         //平均字符宽  
  105.         cxChar = tm.tmAveCharWidth ;  
  106.         //大写字母的平平均宽度  
  107.         cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;  
  108.         //字符总高度:高度+行间距  
  109.         cyChar = tm.tmHeight + tm.tmExternalLeading ;  
  110.   
  111.         ReleaseDC(hwnd,hdc);  
  112.   
  113.         //设置滚动条范围:参数为:窗口句柄,滚动条类型,最小位置,最大位置,是否重绘  
  114.         SetScrollRange (hwnd, SB_VERT, 0, NUMLINES - 1, FALSE);  
  115.         //滚动条的方块的位置,参数为:窗口句柄,滚动条类型,新的位置  
  116.         SetScrollPos   (hwnd, SB_VERT, iVscrollPos, TRUE);   
  117.           
  118.         return 0;  
  119.     case WM_SIZE:         
  120.         cxClient = LOWORD (lParam) ;          
  121.         cyClient = HIWORD (lParam) ;         
  122.         return 0;   
  123.     case WM_PAINT:  
  124.         hdc = BeginPaint (hwnd, &ps) ;  
  125.         for(i = 0;i < NUMLINES;i++ )  
  126.         {  
  127.               
  128.             //行宽度*变动的行数  
  129.             y =  cyChar * (i - iVscrollPos) ;  
  130.             //输出字符串到指定的区域(使用当前的字体,背景颜色,颜色)  
  131.             //参数为:设备内容句柄,x坐标,y坐标,带输出的字符串(与是否/0结尾无关),字符的个数  
  132.             //lstrlen计算字符串长度              
  133.             TextOut(hdc,0,          y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));  
  134.             //从22个大写字母以后的位置输出,因为第一列最多只有20个大写字母  
  135.             TextOut(hdc,22*cxCaps,  y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));  
  136.             //最后一列是右对齐的  
  137.             SetTextAlign(hdc,TA_RIGHT | TA_TOP);  
  138.             //40*cxChar是第二列及第三列的列宽  
  139.             //wsprintf用来给指定的buffer中格式化并存储字符串(0结尾),返回值为字符串的数目  
  140.             //GetSystemMetrics用来获取系统参数,返回值为系统参数  
  141.             TextOut(hdc,22*cxCaps+40*cxChar,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics (sysmetrics[i].Index)));  
  142.             //再把对齐方式改回去,否则下一次循环时也是右对齐  
  143.             SetTextAlign(hdc,TA_LEFT | TA_TOP);  
  144.         }  
  145.         EndPaint (hwnd, &ps) ;  
  146.         return 0;  
  147.           
  148.     //滚动条消息  
  149.     case WM_VSCROLL:  
  150.               
  151.         //通过滚动条消息的wParam表明滚动条的操作  
  152.         switch(LOWORD (wParam))  
  153.         {  
  154.         //点一下上箭头:向下翻一行  
  155.         case SB_LINEUP:  
  156.             iVscrollPos -=1;  
  157.             break;  
  158.         //点一下下箭头:向上翻一行  
  159.         case SB_LINEDOWN:  
  160.             iVscrollPos +=1;  
  161.             break;  
  162.         //点一下方块上面:向上翻一页,每一页是:(客户区/一行高度)这么多行  
  163.         case SB_PAGEUP:  
  164.             iVscrollPos -= cyClient / cyChar ;  
  165.             break;  
  166.         //点一下方块下面:向下翻一页  
  167.         case SB_PAGEDOWN:  
  168.             iVscrollPos += cyClient / cyChar ;  
  169.             break;  
  170.         //拖动滚动条:wParam的高字节表明了滚动条的位置  
  171.         case SB_THUMBPOSITION:  
  172.             iVscrollPos = HIWORD (wParam) ;  
  173.             break;  
  174.         default:  
  175.             break;  
  176.         }  
  177.           
  178.         //这一句是为了  
  179.         iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ;  
  180.   
  181.          //如果滚动条位置改变  
  182.          if (iVscrollPos != GetScrollPos (hwnd, SB_VERT))  
  183.          {  
  184.             //设置滚动条小方块的位置  
  185.             SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;  
  186.             //设为无效区,激励WM_PAINT消息  
  187.             InvalidateRect (hwnd, NULL, TRUE) ;  
  188.          }  
  189.   
  190.         return 0;  
  191.           
  192.   
  193.     case  WM_DESTROY:  
  194.         PostQuitMessage(0);  
  195.         return 0;  
  196.     }  
  197.     return DefWindowProc (hwnd, message, wParam, lParam) ;  
  198.   
  199. }  

程序的思路是这样的:在创建窗口时,就要告诉系统你要加一个滚动条(垂直的),在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消息下实现)。

我们在看看程序:

 
  1. #include <windows.h>  
  2. #include "sysmets.h"  
  3.   
  4. LRESULT CALLBACK WndProc (HWND,UINT,WPARAM,LPARAM);  
  5.   
  6. int WINAPI WinMain(HINSTANCE hInstance,     //当前实例句柄  
  7.                    HINSTANCE hPrevInstance, //先前实例句柄  
  8.                    LPSTR lpCmdLine,         //命令行  
  9.                    int iCmdShow)            //显示状态  
  10. {  
  11.     static TCHAR szAppName[] = TEXT("显示系统内容");  
  12.     //窗口句柄  
  13.     HWND hwnd;  
  14.     //消息  
  15.     MSG msg;  
  16.     //窗口类  
  17.     WNDCLASS wndclass;  
  18.     //窗口风格:当移动窗口或者改变大小时重绘窗口  
  19.     wndclass.style         =  CS_HREDRAW | CS_VREDRAW;  
  20.     //指明回调函数  
  21.     wndclass.lpfnWndProc   = WndProc;  
  22.     //额外的比特用来确认下一个窗口类的位置,暂时不用  
  23.     wndclass.cbClsExtra    = 0;  
  24.     //额外的比特用来确认下一个窗口实例的位置,暂时不用  
  25.     wndclass.cbWndExtra    = 0;  
  26.     //实例句柄  
  27.     wndclass.hInstance     = hInstance;  
  28.     //装载图标  
  29.     wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);  
  30.     //装载光标  
  31.     wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW);  
  32.     //背景为白色  
  33.     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);  
  34.     //菜单:暂时没有  
  35.     wndclass.lpszMenuName  = NULL;  
  36.     //窗口类名  
  37.     wndclass.lpszClassName = szAppName;  
  38.   
  39.     //注册窗口  
  40.     if(!RegisterClass(&wndclass))  
  41.     {  
  42.         return -1;  
  43.     }  
  44.   
  45.     //创建窗口  
  46.     hwnd = CreateWindow(szAppName,              //窗口类的名称,必须是已经注册的  
  47.                         TEXT("系统内容"),       //窗口标题  
  48.                         WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,  //窗口风格,加入滚动条  
  49.                         CW_USEDEFAULT,          //X坐标  
  50.                         CW_USEDEFAULT,          //Y坐标  
  51.                         CW_USEDEFAULT,          //宽度  
  52.                         CW_USEDEFAULT,          //高度  
  53.                         NULL,                   //父窗口句柄  
  54.                         NULL,                   //菜单窗口句柄  
  55.                         hInstance,              //高级版本的windos忽略  
  56.                         NULL);                    
  57.   
  58.     //显示窗口  
  59.     //ShowWindow(hwnd,SW_SHOWNA);  
  60.     ShowWindow (hwnd, iCmdShow);  
  61.   
  62.     //更新窗口  
  63.     UpdateWindow(hwnd);  
  64.   
  65.     //消息循环  
  66.     while(GetMessage(&msg,NULL,0,0))  
  67.     {  
  68.           
  69.         TranslateMessage(&msg);  
  70.         //将消息给窗口  
  71.         DispatchMessage(&msg);  
  72.   
  73.     }  
  74.   
  75.     return msg.wParam;  
  76.   
  77. }  
  78.   
  79. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  80. {  
  81.     //字符的宽度,大写字母宽度,字符高度  
  82.     static int    cxChar, cxCaps, cyChar ;  
  83.     //窗口大小  
  84.     static int cxClient, cyClient ;  
  85.     //最大宽度  
  86.     static int iMaxWidth;  
  87.     //滚动条位置  
  88.     static int iVertPos,iHorzPos,iPaintBeg,iPaintEnd;  
  89.     HDC hdc;  
  90.     //该变量用于索引sysmets.h中定义的结构体数组sysmetrics[]的每个元素  
  91.     int i;  
  92.     //输出文本的位置  
  93.     int x,y;  
  94.     //绘图结构  
  95.     PAINTSTRUCT ps;  
  96.     //这个结构包含了滚动条的信息  
  97.     //通过SetScrollInfo函数设置信息,通过 GetScrollInfo 函数获取信息  
  98.     SCROLLINFO si;  
  99.     //字符串  
  100.     TCHAR szBuffer [10];  
  101.     //字体信息结构  
  102.     TEXTMETRIC  tm;  
  103.     switch(message)  
  104.     {  
  105.     case WM_CREATE:  
  106.         hdc = GetDC(hwnd);  
  107.         //取得内定系统字体的文字大小,存在放在tm里  
  108.         GetTextMetrics (hdc, &tm);  
  109.         //平均字符宽  
  110.         cxChar = tm.tmAveCharWidth ;  
  111.         //大写字母的平均宽度  
  112.         cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;  
  113.         //字符总高度:高度+行间距  
  114.         cyChar = tm.tmHeight + tm.tmExternalLeading ;  
  115.   
  116.         ReleaseDC(hwnd,hdc);  
  117.         //最大跨度 = 40个字符+22个大写字母  
  118.         iMaxWidth = 40*cxChar+22*cxCaps;  
  119.         return 0;  
  120.     case WM_SIZE:  
  121.         cxClient = LOWORD (lParam) ;          
  122.         cyClient = HIWORD (lParam) ;     
  123.         //设置垂直滚动条信息  
  124.         //结构体的大小  
  125.         si.cbSize  = sizeof(si);  
  126.         //指明将要设置和获取的参数:这里是最大最小值组成的范围和页面的大小  
  127.         si.fMask = SIF_RANGE | SIF_PAGE ;  
  128.         //滚动条位置的最小值  
  129.         si.nMin = 0;  
  130.         //滚动条位置的最大值  
  131.         si.nMax = NUMLINES - 1 ;  
  132.         //页面大小  
  133.         si.nPage = cyClient / cyChar ;  
  134.         //设置滚动条的参数  
  135.         SetScrollInfo(hwnd, SB_VERT,&si,TRUE);  
  136.   
  137.         //设置水平滚动条信息  
  138.         si.cbSize  = sizeof(si);  
  139.         si.fMask = SIF_RANGE | SIF_PAGE ;  
  140.         si.nMin = 0;  
  141.         si.nMax = 2+ iMaxWidth/cxChar ;  
  142.         si.nPage = cxClient / cxChar ;  
  143.         SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ;  
  144.   
  145.         return 0;   
  146.           
  147.     case WM_PAINT:  
  148.         hdc = BeginPaint (hwnd, &ps) ;  
  149.   
  150.         si.cbSize = sizeof(si);  
  151.         si.fMask = SIF_POS;  
  152.         GetScrollInfo(hwnd,SB_VERT,&si);  
  153.         iVertPos = si.nPos;  
  154.         GetScrollInfo(hwnd,SB_HORZ,&si);  
  155.         iHorzPos = si.nPos;  
  156.         //max(0,当前位置+需要绘图的矩形区的最高点/字符的高度)  
  157.         //iPaintBeg = max(0,iVertPos+ps.rcPaint.top/cyChar);  
  158.         iPaintBeg = max(0,iVertPos);  
  159.         //绘图结束的地方 = 当前位置+绘制去取的高度  
  160.         iPaintEnd = min(NUMLINES -1,iVertPos+ps.rcPaint.bottom/cyChar);  
  161.   
  162.         for(i = iPaintBeg; i <= iPaintEnd;i++)  
  163.         {  
  164.             //绘图的x起始位置:1是自己设置的,设置越大离左边越宽  
  165.             x = cxChar * (1 - iHorzPos) ;  
  166.             //绘图的y起始位置。  
  167.             y = cyChar * (i - iVertPos) ;  
  168.             TextOut(hdc,x, y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));    
  169.             //从22个大写字母以后的位置输出,因为第一列最多只有20个大写字母    
  170.             TextOut(hdc,x+22*cxCaps,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));    
  171.             SetTextAlign(hdc,TA_RIGHT | TA_TOP);  
  172.             TextOut(hdc,x+22*cxCaps+40*cxChar,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics (sysmetrics[i].Index)));   
  173.             SetTextAlign(hdc,TA_LEFT | TA_TOP);    
  174.         }  
  175.         EndPaint (hwnd, &ps) ;  
  176.         return 0;  
  177.           
  178.     //垂直滚动条消息  
  179.     case WM_VSCROLL:  
  180.         //获取垂直滚动条信息  
  181.   
  182.         si.cbSize = sizeof(si);  
  183.         //所有参数  
  184.         si.fMask = SIF_ALL;  
  185.         GetScrollInfo(hwnd,SB_VERT,&si);  
  186.         //垂直位置  
  187.         iVertPos = si.nPos ;  
  188.         //通过滚动条消息的wParam表明滚动条的操作  
  189.         switch(LOWORD (wParam))  
  190.         {  
  191.         case SB_TOP:  
  192.             si.nPos = si.nMin;  
  193.             break;  
  194.         case SB_BOTTOM:  
  195.             si.nPos = si.nMax;  
  196.             break;  
  197.         case SB_LINEUP:  
  198.             si.nPos -= 1;  
  199.             break;  
  200.         case SB_LINEDOWN:  
  201.             si.nPos +=1;  
  202.         case SB_PAGEUP:  
  203.             si.nPage -= si.nPage;  
  204.             break;  
  205.         case SB_PAGEDOWN:  
  206.             si.nPos +=si.nPage;  
  207.             break;  
  208.         case SB_THUMBTRACK:  
  209.             si.nPos = si.nTrackPos;  
  210.             break;  
  211.         default:  
  212.             break;  
  213.         }  
  214.           
  215.   
  216.         si.fMask = SIF_POS;  
  217.         SetScrollInfo(hwnd,SB_VERT,&si,TRUE);  
  218.         GetScrollInfo(hwnd,SB_VERT,&si);  
  219.         if(si.nPos != iVertPos)  
  220.         {  
  221.             //滚动指定窗口的内容  
  222.             ScrollWindow(hwnd,0,cyChar*(iVertPos-si.nPos),NULL,NULL);  
  223.             UpdateWindow(hwnd);  
  224.         }  
  225.         return 0;  
  226.     //水平滚动条消息  
  227.     case WM_HSCROLL:  
  228.         si.cbSize = sizeof(si);  
  229.         si.fMask = SIF_ALL;  
  230.         GetScrollInfo(hwnd,SB_HORZ,&si);  
  231.         iHorzPos = si.nPos;  
  232.         switch(LOWORD(wParam))  
  233.         {  
  234.         case SB_LINELEFT:  
  235.             si.nPos -= 1;  
  236.             break;  
  237.         case SB_LINERIGHT:  
  238.             si.nPos +=1;  
  239.             break;  
  240.         case SB_PAGELEFT:  
  241.             si.nPos -= si.nPage;  
  242.             break;  
  243.         case SB_PAGERIGHT:  
  244.             si.nPos += si.nPage;  
  245.             break;  
  246.         case SB_THUMBPOSITION:  
  247.             si.nPos = si.nTrackPos;  
  248.             break;  
  249.         default:  
  250.             break;  
  251.               
  252.         }  
  253.         si.fMask = SIF_POS;  
  254.         SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);  
  255.         GetScrollInfo(hwnd,SB_HORZ,&si);  
  256.         if(si.nPos != iHorzPos)  
  257.         {  
  258.             ScrollWindow(hwnd,cxChar*(iHorzPos-si.nPos),0,NULL,NULL);  
  259.             //UpdateWindow (hwnd) ;  
  260.   
  261.         }  
  262.         return 0;  
  263.     case  WM_DESTROY:  
  264.         PostQuitMessage(0);  
  265.         return 0;  
  266.     }  
  267.     return DefWindowProc (hwnd, message, wParam, lParam) ;  
  268.   
  269. }  


 

程序中有几点需要注意:

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是为了不是太“顶格”,你也可以把它设置大一点,结果就很明显了。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Windows程序设计——窗口键盘消息滚动事件
Windows API学习之滚动条系列函数
什么?C语言也可以抢红包,速度来围观。
在Dialog中创建View【文集】
编写一个程序,在屏幕上出现一个圆心沿正弦曲线轨迹移动的实心圆,且每隔四分之一周期,圆的填充色和圆的周边颜色都发生变化,同时圆的半径在四分之一周期之内由正弦曲线幅值的0.2倍至0.6倍线性增长。
谁有C语言编写的病毒源代码?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服