《windows程序设计》学习_4:文本输出,加滚动条

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

typedef struct tagSCROLLINFO
        
{
        
    UINT cbSize ;// set to sizeof (SCROLLINFO)
        
    UINT fMask ;  // values to set or get,要设置或获取的值
        
    int  nMin ;      // minimum range value,范围最小值
        
    int  nMax ;   // maximum range value,范围最大值
        
    UINT nPage ;  // page size,页面大小
        
    int  nPos ;   // current position,当前位置
        
    int  nTrackPos ;// current tracking position,当前追踪位置
        
}
        
SCROLLINFO, * PSCROLLINFO ;

ScrollWindow:

 函数原型:BOOL ScrollWindow(HWND hWnd, int XAmount, int YAmount, CONST RECT *IpRect, CONST RECT *lpClipRect);

参数:

hWnd
[in]客户区域将被滚动的窗口的句柄。
XAmount
[in]指定水平滚动的距离,以设备单位计。如果窗口类风格为CS_OWNDC或CS_CLASSDC,则此参数则使用逻辑单位而非设备单位。当向左滚动窗体内容时,参数值必须为负。
YAmount
[in]指定垂直滚动的距离,以设备单位计。如果窗口类风格为CS_OWNDC或CS_CLASSDC,则此参数则使用逻辑单位而非设备单位。当向上滚动窗体内容时,参数值必须为负。
lpRect
[in]指向RECT结构的指针,该结构指定了将要滚动的客户区范围。若此参数为NULL,则整个客户区域将被滚动。
lpClipRect
[in]指向RECT结构的指针,该结构指定了要滚动的裁剪区域。只有这个矩形中的位才会被滚动。在矩形之外的位不会被影响,即使它们是在lpRect矩形之内。(见代码"测试一")假如lpClipRect为NULL,则不会在滚动矩形上进行裁剪。
返回值:
如果函数运行成功,返回值为非零;如果函数运行失败,返回值为零。若想获得更多的错误信息,请调用GetLastReeor函数。
注意:
如果在被滚动的窗口中含有插入符,ScrollWindow将自动隐藏插入符,以防它被擦掉;当滚动结束后再恢复插入符。插入符的位置相应的被调整过来。
未被ScrollWindow覆盖的区域不再重画,但该区域会与窗口更新区域组合。应用程序最终收到WM_PAINT的消息,通知它结合区域必须被重画。为了在滚动操作的同时重画未覆盖区域,则应在调用ScrollWindow函数后马上调用UpdateWindow函数。
如果参数lpRect为NULL,则窗口中的任何子窗口的位置由参数XAmount和Yamount的数值决定偏移;窗体无效(未着色)的区域也偏移。IpRect为NULL时ScrollWindow执行地更快。
如果参数lpRect不为NULL,则窗口中的子窗口的位置不改变,窗口中无效(未着色)的区域也不偏移。为了防止lpRect不为NULL时更新的问题,需要在调用ScrollWindow前调用UpdateWindow函数重绘窗口。
高效使用此函数的二法:

1.按照MSDN提供的方法来使用

调用完ScrollWindow后 ,立即调用UpdateWindow发送一个不进队的WM_PAINT消息。在WM_PAINT消息中可以按照滚动时的逻辑,整个区域都绘制但是利用重绘 区域自动将多余的绘制剪切掉,只绘制未被滚动操作覆盖的一行;但是更高明的做法无疑是只绘制未被滚动操作覆盖的一行,加快绘制速度。

2.在调用ScrollWindow的非WM_PAINT消息中绘制

在调用按ScrollWindow后获得窗口DC,自己绘制未被滚动操作覆盖的一行,然后将整个滚动剪切区域设为有效,禁止其产生WM_PAINT消息,这样也可加快绘制速度。
posted @ 2013-11-15 20:35  Hewie_Bai  阅读(552)  评论(0编辑  收藏  举报