学习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);
}

原文地址:https://www.cnblogs.com/ssyfj/p/8505273.html

时间: 2024-10-09 02:34:40

学习windows编程 day3 之滚动条完善的相关文章

学习windows编程 day2 之滚动条使用

相关函数: setscrollrange,setscrollpos,getscrollrange,getscrollpos 使用滚动条时我们需要进行的操作: 1.初始化滚动条范围和位置 在窗口创建时WM_CREATE响应时可以完成 SetScrollRange(hwnd, SB_VERT, 0, NUMLINES,FALSE); SetScrollPos(hwnd, SB_VERT, 0, TRUE); 2.处理窗口过程的滚动条消息 在响应WM_VSCROLL时处理 switch(LOWORD(

有一定基础的 C++ 学习者该怎样学习 Windows 编程?

人的心理有个奇异的特性:一项知识一旦学会之后,学习过程中面临的困惑和不解非常快就会忘得干干净净,似乎一切都是自然而然,本来就该这种.因此,关于「怎样入门」这类问题,找顶尖高手来回答,未必能比一个刚入门不久的人来回答要好.就譬如最高票的那个回答,是一个非常精通 Windows 编程的高人回答的,但这种答案能给刚開始学习的人带来多少帮助,我这里想先打一个问号. 前段时间刚辅导了一个学生学会了 Win32 GUI 编程,刚好看到这个问题,顺手就邀请他回答了.并不是是给他布置总结作业,不过希望能从他这里

有一定基础的 C++ 学习者该如何学习 Windows 编程?

人的心理有个奇妙的特性:一项知识一旦学会之后,学习过程中面临的困惑和不解很快就会忘得干干净净,似乎一切都是自然而然,本来就该这样的.因此,关于「如何入门」这类问题,找顶尖高手来回答,未必能比一个刚入门不久的人来回答要好.就譬如最高票的那个回答,是一个非常精通 Windows 编程的高人回答的,但这样的答案能给初学者带来多少帮助,我这里想先打一个问号. 前段时间刚辅导了一个学生学会了 Win32 GUI 编程,刚好看到这个问题,顺手就邀请他回答了.并非是给他布置总结作业,仅仅是希望能从他这里得到第

如何学习Windows编程

如何学习Windows编程 来源 https://zhuanlan.zhihu.com/p/24773204 Godbird 北京爱奇艺科技有限公司 客户端工程师  编辑于 2017-01-08 有很多初入门的小朋友跟我说,他们想学“底层”的技术,因为觉得技术含量高,所以想学Windows C++开发,看着调用一个个的参数超级多,调用起来超级麻烦的Windows API,觉着很酷.于是我念头一转,就有了这篇文章,根据我多年来做Windows 客户端的经验,跟大家谈谈Windows C++,该从哪

学习windows编程 day1

#include <windows.h> #include <strsafe.h> /* 任务:去掉标题栏和边框 */ //#define LineHeight 15 这是自己猜测的行高,不要这样做 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstanc

学习windows编程 day4 之 自定义映射

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; int iMapMode; static int cxClient, cyClient; switch (message) { case WM_SIZE: cxClient = LOWORD(lParam); cyClient = HIWORD(lParam);

【Windows编程】系列第五篇:GDI图形绘制

上两篇我们学习了文本字符输出以及Unicode编写程序,知道如何用常见Win32输出文本字符串,这一篇我们来学习Windows编程中另一个非常重要的部分GDI图形绘图.Windows的GDI函数包含数百个API可供我们使用,本篇把最常用的GDI绘图做一个讲解.GDI可以绘制点.直线曲线.填充封闭区域.位图以及文本,其中文本部分已经在上一篇中将了,请参考[Windows编程]系列第三篇:文本字符输出. 跟前面的GDI对象一样,本篇的这些绘图函数也必须要设备上下文句柄(HDC)作为函数参数,从前文我

windows编程经典书籍

本人是刚刚开始学习windows编程的,感觉看雪学院的大牛很NB.想找一些书籍来看学习学习,可是不知道看哪些书好.驱动,对菜鸟们来说真是一个很深奥的话题,所以 ,我找来了这篇文章供大家分享,以后大家发现什么好书就在楼下跟贴吧! 作者:Harry Meng 来源:互联网.也许我的阅读面过于狭小,书架里基本上都是Jeffrey Richter,Charles Petzold,侯捷老师以及潘爱民老师的书,这些书一直陪伴着我,并给我的编程工作带来了很大的帮助,希望我的推荐对你也有帮助.现 在的计算机图书

【Windows编程】系列第九篇:剪贴板使用

 上一篇我们学习了常见的通用对话框,本篇来了解剪贴板的使用,它常用于复制粘贴功能. 剪贴板是Windows最早就加入的功能,由于该功能非常实用,我们几乎每天都会使用到.通过剪贴板,我们就可以将数据从一个应用程序传递到另一个应用程序,是一种简单的进程间通信. 许多文档处理软件都有复制.剪切.粘贴功能,这些都是用Windows剪贴板实现的,当然我们也可以在我们的程序中实现自己的剪贴板功能,本篇我们就来实现自己的剪贴板.使用剪贴板时,都是先把源数据先传到剪贴板上,再在需要的时候从剪贴板传输到目的处