《Windows程序设计》读书笔记------------->>滚动条使用(翻译自MSDN)<<

来源:互联网 发布:商业办公软件 编辑:程序博客网 时间:2024/05/17 04:58

使用滚动条

本节包含的示例代码将引导您完成以下内容:
创建滚动条
滚动文字
滚动图片
为一个滚动条创建键盘接口

创建滚动条
无论创建一个重叠,弹出,或是子窗口时,您都可以在CreateWindowEx函数(第三个参数)中注明WS_HSCROLL, WS_VSCROLL(或者两者一起)来创建一个水平或竖直滚动条(或两者都有)。下面这个例子创建了一个包含了水平和竖直滚动条的窗口。

hwnd = CreateWindowEx( 
    
0L,                          // 无拓展样式
    "MyAppClass",                // 窗口类别名
    "Scroll Bar Application",    // 窗口标题
    WS_OVERLAPPEDWINDOW |        // 窗口样式
        WS_HSCROLL | 
        WS_VSCROLL, 
    CW_USEDEFAULT,             
// 默认的水平位置
    CW_USEDEFAULT,             // 默认的竖直位置
    CW_USEDEFAULT,             // 默认宽度
    CW_USEDEFAULT,             // 默认高度
    (HWND) NULL,         // 没有父窗口
    (HMENU) NULL,        // 窗口菜单
    hinst,               // 窗口所有者为一个实例(猜的)
    (LPVOID) NULL        // 不需要指针(猜的)
); 

 

为了处理滚动条消息,必须在主窗口程序中加入正确的代码。

当使用CreateWindowEx函数创建一个窗口的时候,你可以通过指定滚动条样式来创建一个滚动条。而创建水平还是竖直滚动条由窗口样式是由指定的是SBS_HORZ还是SBS_VERT决定(这里不知道他为什么要写成不同,事实证明用哪种定义方式看起来是完全相同的)。滚动条大小和相对于它的副窗口的位置关系也可以指定。下面这个例子创建了一个在左上方的水平滚动条。

hwndScroll = CreateWindowEx( 
    
0L,                          // 没有拓展样式(猜的)
    "SCROLLBAR",                 // 滚动条控制类
    (LPSTR) NULL,                // 窗口标题
    WS_CHILD | SBS_HORZ,         // 滚动条样式 
    0,                           // 水平位置 
    0,                           // 竖直文字 
    200,                         // 滚动条长度 
    CW_USEDEFAULT,               // 默认高度 
    hwnd,                   // 主窗口句柄 
    (HMENU) NULL,           // 滚动条没有菜单
    hinst,                  // 拥有此窗口的是一个实例
    (LPVOID) NULL           // 不需要指针
); 

 

滚动文字
这一节介绍了如何改变窗口主程序使用户可以滚动文字。在“滚动文字示例程序”将通过处理WM_HSCROLL和WM_VSCROLL消息来显示超出范围的文字,以实现滚动水平和竖直的文字。

滚动文字与WM_CREATE消息
滚动模块一般在处理WM_CREATE消息时进行参数设定。滚动条可以非常方便的根据由设备句柄提供的字体的大小信息来进行设定,您可以使用GetTextMetrics函数和具体的设备句柄来取得需要的字体信息。

正如示例程序中所示范的,一个垂直滚动条与文字的高度加行间距的和有关。一个水平滚动条与文字的平均宽度有关。因此,水平滚动条的位置不应该完全对应于实际字符,除非显示的字体的宽度是固定的。

滚动文字与WM_SIZE消息
当处理WM_SIZE消息时,可以很方便地调整滚动条的范围和位置,这么做可以根据用户区域改变显示出的文本行数。SetScrollInfo函数可以设定这些东东(包括最小范围和最大范围,页面大小还有滚动条的位置等)。

滚动文字与WM_HSCROLL和WM_VSCROLL消息
无论是点击还是释放滚动条,都会受到一个WM_HSCROLL或者WM_VSCROLL消息。WM_HSCROLL和WM_VSCROLL返回值的低字组包含了一个消息代码以表示对滚动条进行了何种动作。

当窗口被滚动的时候,窗口的一部分会被标示为无效区域(更新区域),如果要更新这个区域可以调用UpdateWindow函数直接产生一个WM_PAINT消息。

滚动文字与WM_PAINT消息
当处理WM_PAINT消息的时候,你应该在绘制那些要在窗口上显示的文字。下面的例子使用了当前滚动位置和无效区域大小确定显示文字的范围。

下面这个示例程序示范了如何调整文字来响应水平和垂直滚动条:

HDC hdc; 
PAINTSTRUCT ps; 
TEXTMETRIC tm; 
SCROLLINFO si; 
 
// 这些变量保存了现实文字需要的信息
static int xClient;     // 客户区域宽度
static int yClient;     // 客户区域高度
static int xClientMax;  // 客户区域最大宽度
 
static int xChar;       // 水平滚动单位
static int yChar;       // 竖直滚动单位
static int xUpper;      // 大写字母平均宽度
 
static int xPos;        // 水平滚动条当前位置
static int yPos;        // 竖直滚动条当前位置
 
int i;                  // 循环计数器
int x, y;               // 水平和竖直的坐标
 
int FirstLine;          // 显示区域的第一行
int LastLine;           // 显示区域的最后一行
HRESULT hr;
size_t 
* abcLength;        // abc[] 的长度
 
// 创建一个数组储存需要显示的文字
#define LINES 28 
static TCHAR *abc[] = 
       TEXT(
"anteater"),  TEXT("bear"),      TEXT("cougar"), 
       TEXT(
"dingo"),     TEXT("elephant"),  TEXT("frog"), 
       TEXT(
"gazelle"),   TEXT("hyena"),     TEXT("iguana"), 
       TEXT(
"jackal"),    TEXT("kangaroo"),  TEXT("llama"), 
       TEXT(
"moose"),     TEXT("newt"),      TEXT("octopus"), 
       TEXT(
"penguin"),   TEXT("quail"),     TEXT("rat"), 
       TEXT(
"squid"),     TEXT("tortoise"),  TEXT("urus"), 
       TEXT(
"vole"),      TEXT("walrus"),    TEXT("xylophone"), 
       TEXT(
"yak"),       TEXT("zebra"),
       TEXT(
"This line contains words, but no character. Go figure."),
       TEXT(
"")
     }

 
switch (uMsg) 

    
case WM_CREATE : 
        
// 取得设备类型的句柄
        hdc = GetDC (hwnd); 
 
        
// 取得文字大小信息
        GetTextMetrics (hdc, &tm); 
        xChar 
= tm.tmAveCharWidth; 
        xUpper 
= (tm.tmPitchAndFamily & 1 ? 3 : 2* xChar/2
        yChar 
= tm.tmHeight + tm.tmExternalLeading; 
 
        
// 释放设备类型句柄
        ReleaseDC (hwnd, hdc); 
 
        
// 设置显示的文字的最大宽度
        
// (其中包括个小写字母和2个大写字母)
        xClientMax = 48 * xChar + 12 * xUpper; 
 
        
return 0
 
    
case WM_SIZE: 
 
        
// 取得显示区域的大小
        yClient = HIWORD (lParam); 
        xClient 
= LOWORD (lParam); 
 
        
// 设定竖直滚动条范围和页面大小
        si.cbSize = sizeof(si); 
        si.fMask  
= SIF_RANGE | SIF_PAGE; 
        si.nMin   
= 0
        si.nMax   
= LINES - 1
        si.nPage  
= yClient / yChar; 
        SetScrollInfo(hwnd, SB_VERT, 
&si, TRUE); 
 
        
// 设置水平滚动条的范围和页面大小
        si.cbSize = sizeof(si); 
        si.fMask  
= SIF_RANGE | SIF_PAGE; 
        si.nMin   
= 0
        si.nMax   
= 2 + xClientMax / xChar; 
        si.nPage  
= xClient / xChar; 
        SetScrollInfo(hwnd, SB_HORZ, 
&si, TRUE); 
 
        
return 0
    
case WM_HSCROLL:
         
// 取得水平滚动条的信息
         si.cbSize = sizeof (si);
         si.fMask  
= SIF_ALL;
         
// 保存以便于等会进行比较
         GetScrollInfo (hwnd, SB_HORZ, &si);
         xPos 
= 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;
         }

         
// 设定并储存位置,如果超出范围Window会自动处理的
         si.fMask = SIF_POS;
         SetScrollInfo (hwnd, SB_HORZ, 
&si, TRUE);
         GetScrollInfo (hwnd, SB_HORZ, 
&si);
         
         
// 如果位置变了就滚动屏幕
         if (si.nPos != xPos)
         
{
          ScrollWindow(hwnd, xChar 
* (xPos - si.nPos), 0, NULL, NULL);
         }

         
return 0;
         
    
case WM_VSCROLL:
         
// 取得竖直滚动条的信息
         si.cbSize = sizeof (si);
         si.fMask  
= SIF_ALL;
         GetScrollInfo (hwnd, SB_VERT, 
&si);
         
// 保存以便于等会进行比较
         yPos = si.nPos;
         
switch (LOWORD (wParam))
         
{
         
// 当用户按了HOME按钮
         case SB_TOP:
              si.nPos 
= si.nMin;
              
break;
              
         
// 当用户按了 END 按钮
         case SB_BOTTOM:
              si.nPos 
= si.nMax;
              
break;
              
         
// 用户点击了上箭头
         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;
              
         
default:
              
break
         }

         
// 设定并储存位置,如果超出范围Window会自动处理的
         si.fMask = SIF_POS;
         SetScrollInfo (hwnd, SB_VERT, 
&si, TRUE);
         GetScrollInfo (hwnd, SB_VERT, 
&si);
         
// 如果位置变了就滚动并更新屏幕
         if (si.nPos != yPos)
         
{                    
          ScrollWindow(hwnd, 
0, yChar * (yPos - si.nPos), NULL, NULL);
          UpdateWindow (hwnd);
         }

         
return 0;
         
    
case WM_PAINT :
         
// 为绘制窗口做准备
         hdc = BeginPaint (hwnd, &ps);
         
// 取得竖直滚动条的位置
         si.cbSize = sizeof (si);
         si.fMask  
= SIF_POS;
         GetScrollInfo (hwnd, SB_VERT, 
&si);
         yPos 
= si.nPos;
         
// 取得水平滚动条的位置
         GetScrollInfo (hwnd, SB_HORZ, &si);
         xPos 
= si.nPos;
         
// 计算绘制的范围
         FirstLine = max (0, yPos + ps.rcPaint.top / yChar);
         LastLine 
= min (LINES - 1, yPos + ps.rcPaint.bottom / yChar);
         
         
for (i = FirstLine; i <= LastLine; i++)
         
{
              x 
= xChar * (1 - xPos);
              y 
= yChar * (i - yPos);
              
              
// Note that "55" in the following depends on the 
              
// maximum size of an abc[] item.
              
//
              hr = StringCchLength(abc[i], 55, abcLength);
              
if ((FAILED(hr))|(abcLength == NULL))
              
{
              
//
              
// TODO: 加入出错代码
              
//
              }

              
         }

         
// 绘图完毕
         EndPaint (hwnd, &ps);
         
return 0;
         
    
case WM_DESTROY :
         PostQuitMessage (
0);
         
return 0;
    }

    
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}

 

 

滚动图片
(无关就不翻译了)

为一个滚动条创建键盘接口
(还没有学到,也不翻译了)