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
原创粉丝点击