zoukankan      html  css  js  c++  java
  • 学习windows编程 day3 之滚动条完善

    1.不再使用setscrollrange,setscrollpos,getscrollrange,getscrollpos这些函数,这只是有助于理解其中运行原理

    2.改用setscrollinfo,getscrollinfo函数和结构体scrollinfo去改变和获取滚动条信息,相对于上面会更加灵活,方便扩展

    3.scrollwindow:滚动窗口客户区的内容,只滚动当前显示的内容,要显示其他内容,需要重绘失效的窗口,但是相对于重绘整个窗口是一个很节省内存的方法

    #include <windows.h>
    #include "Sysmet.h"
    #include <strsafe.h>
    
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
        //声明全局数据:类名
        static TCHAR szClassName[] = TEXT("MyWindows");
        HWND hwnd;
        MSG msg;
    
        //注册窗口类
        WNDCLASS wndclass;
    
        wndclass.hInstance = hInstance;
        wndclass.lpszClassName = szClassName;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.lpfnWndProc = WndProc;
        wndclass.lpszMenuName = NULL;
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.style = CS_HREDRAW;
    
        if (!RegisterClass(&wndclass))
        {
            MessageBox(NULL, TEXT("this program must run in Windows NT!"), szClassName, MB_ICONERROR);
            return 0;
        }
    
        hwnd = CreateWindow(
            szClassName,
            TEXT("MyFirstPractice"),
            WS_OVERLAPPEDWINDOW|WS_VSCROLL,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            NULL,
            NULL,
            hInstance,
            NULL
            );
    
        ShowWindow(hwnd, nShowCmd);
        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)
    {
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;
        //获取字体大小,初始化数据
        static int cxChar, cyChar, cxCaps;
        //获取每次重绘窗口后的大小尺寸
        static int cxClient, cyClient;
        //获取总行数和当前行数
        static numCount, curCount;
    
        static int y;
        int FirstLine, LastLine;
    
        TEXTMETRIC tm;
        TCHAR szBuffer[100];
        size_t st;
        SCROLLINFO si;
    
        switch (message)
        {
        case WM_CREATE:
            hdc = GetDC(hwnd);
            //获取字体大小,初始化数据
            GetTextMetrics(hdc, &tm);
            cxChar = tm.tmAveCharWidth;
            cyChar = tm.tmHeight + tm.tmExternalLeading;
            cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2)*cxChar / 2;
    
            //初始化总行数和当前行数
            numCount = NUMLINES;
            curCount = 0;
    
            //初始化滚动条位置
            SetScrollRange(hwnd, SB_VERT, 0, numCount, FALSE);
            SetScrollPos(hwnd, SB_VERT, 0, TRUE);
    
            ReleaseDC(hwnd, &hdc);
    
            break;
        case WM_SIZE:
            //获取每次重绘后的屏幕大小
            cxClient = LOWORD(lParam);    //这是获取当前窗口的大小
            cyClient = HIWORD(lParam);
    
            //设置垂直滚动条的范围和页面大小
            si.cbSize = sizeof(si);    //为了更好的兼容版本
            si.fMask = SIF_RANGE | SIF_PAGE;
            si.nMin = 0;
            si.nMax = numCount - 1;
            si.nPage = cyClient / cyChar;    //页面的大小设置
    
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
            break;
        case WM_VSCROLL:
            //获得垂直滚动条的信息
            si.cbSize = sizeof(si);
            si.fMask = SIF_ALL;
            GetScrollInfo(hwnd, SB_VERT, &si);
    
            //保存当前滑块的位置
            curCount = 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_THUMBTRACK:
                si.nPos = si.nTrackPos;
                break;
                //在si.nTrackPos中存放着SB_THUMBTRACK和SB_THUMBPOSITION的位置信息
            case SB_THUMBPOSITION:
                si.nPos = si.nTrackPos;
                break;
            default:
                break;
            }
    
            //设置滚动滑块的新位置
            si.fMask = SIF_POS;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
    
            //再次获得滚动滑块的位置,由于窗口调整,他可能不是同一个值
            GetScrollInfo(hwnd, SB_VERT, &si);
            //curCount是前面未滚动的数据,si.nPos是刚刚滚动后的数据(除非是在顶部或者底部,不然由于窗口调整,两种一定不是同一个值)
            if (si.nPos != curCount)
            {
                ScrollWindow(hwnd, 0, cyChar*(curCount-si.nPos), NULL, NULL);
                /*
                    hwnd                     :窗口句柄
                    0                         :水平滚动的数量
                    cyChar*(curCount-si.nPos):垂直滚动的距离
                    NULL(lpRect)             :为NULL时,当前整个客户区将被滚动
                    NULL(lpClipRect)         :与上一个参数有关,当上一个设置区域后,该参数在其区域中裁剪区域进行滚动
                */
                UpdateWindow(hwnd);
                //不进入消息队列,直接发送WM_PAINT消息进行处理
            }
            break;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            
            //获取垂直滚动条的位置
            si.cbSize = sizeof(si);
            si.fMask = SIF_POS;
            GetScrollInfo(hwnd,SB_VERT, &si);
            curCount = si.nPos;
    
            //计算需要重绘的区域
            FirstLine = max(0, curCount + ps.rcPaint.top / cyChar);
            LastLine = min(numCount - 1, curCount + ps.rcPaint.bottom / cyChar);
            /*
                ps是结构体,ps.rcPaint是指需要重绘的部分窗口矩形,ps.rcPaint.top是该矩形的上部
            */
    
    
            for (int i = FirstLine; i < LastLine;i++)
            {
                y = cyChar*(i - curCount);    //相当于将这个重绘区域看着新窗口,重这个区域的顶部开始重新绘制
    
                StringCchLength(sysmetrics[i].szLabel, 100, &st);
                TextOut(hdc, 0, y, sysmetrics[i].szLabel, st);
    
                StringCchLength(sysmetrics[i].szDesc, 100, &st);
                TextOut(hdc, 40 * cxChar, y, sysmetrics[i].szDesc, st);
    
                SetTextAlign(hdc, TA_RIGHT | TA_TOP);
    
                StringCchPrintf(szBuffer, 100, L"%5d", GetSystemMetrics(sysmetrics[i].iIndex));
                StringCchLength(szBuffer, 100, &st);
                TextOut(hdc, 40 * cxChar + 40 * cxCaps, y, szBuffer, st);
    
                SetTextAlign(hdc, TA_LEFT);
            }
    
            EndPaint(hwnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
    
    
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
  • 相关阅读:
    WPF多路绑定
    ConfigurationManager
    开发小技巧1——Logger
    C#对json数据的解析
    Process类
    JS获取访客IP+判断归属地+自动跳转
    织梦默认编辑器换成kindEditor实操教程
    linux中添加环境变量(python为例)
    原生javascript实现省市区三级联动
    kali安装火狐浏览器
  • 原文地址:https://www.cnblogs.com/ssyfj/p/8505273.html
Copyright © 2011-2022 走看看