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 = ;
wndclass.cbWndExtra = ;
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 ;
} 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, , ))
{
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[];
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 & ? : )*cxChar / ; //初始化总行数和当前行数
numCount = NUMLINES;
curCount = ; //初始化滚动条位置
SetScrollRange(hwnd, SB_VERT, , numCount, FALSE);
SetScrollPos(hwnd, SB_VERT, , 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 = ;
si.nMax = numCount - ;
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 -= ;
break;
case SB_LINEDOWN:
si.nPos += ;
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, , 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(, curCount + ps.rcPaint.top / cyChar);
LastLine = min(numCount - , 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, , &st);
TextOut(hdc, , y, sysmetrics[i].szLabel, st); StringCchLength(sysmetrics[i].szDesc, , &st);
TextOut(hdc, * cxChar, y, sysmetrics[i].szDesc, st); SetTextAlign(hdc, TA_RIGHT | TA_TOP); StringCchPrintf(szBuffer, , L"%5d", GetSystemMetrics(sysmetrics[i].iIndex));
StringCchLength(szBuffer, , &st);
TextOut(hdc, * cxChar + * cxCaps, y, szBuffer, st); SetTextAlign(hdc, TA_LEFT);
} EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage();
return ;
} return DefWindowProc(hwnd, message, wParam, lParam);
}

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

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

    相关函数: setscrollrange,setscrollpos,getscrollrange,getscrollpos 使用滚动条时我们需要进行的操作: 1.初始化滚动条范围和位置 在窗口创建时W ...

  2. 学习windows编程 day3 之窗口绘画二:边框绘制函数

    #include <windows.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM l ...

  3. 学习windows编程 day3 之窗口绘画一:点线绘制

    #include <windows.h> #include <math.h> LRESULT CALLBACK WndProc(HWND hwnd, UINT message, ...

  4. 学习windows编程 day3 之 设置当前的背景颜色

    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRU ...

  5. 学习windows编程 day3 之 自定义画笔的两种方法

    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRU ...

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

    人的心理有个奇异的特性:一项知识一旦学会之后,学习过程中面临的困惑和不解非常快就会忘得干干净净,似乎一切都是自然而然,本来就该这种.因此,关于「怎样入门」这类问题,找顶尖高手来回答,未必能比一个刚入门 ...

  7. 我为什么学习Windows编程

    前一段时间在看TCP/IP,在图书馆里面找了不少的书,其中有几本书还是不错的.比如: <Windows网络与通信程序设计(第二版)> 王艳平著 <WinSock网络编程经络> ...

  8. 学习windows编程 day1

    #include <windows.h> #include <strsafe.h> /* 任务:去掉标题栏和边框 */ //#define LineHeight 15 这是自己 ...

  9. 学习windows编程 day6 之处理鼠标移动

    #define POINT_MAX 1000 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPara ...

随机推荐

  1. A Survey of Machine Learning Techniques Applied to Software Defined Networking (SDN): Research Issues and Challenges

    将机器学习用到SDN中的综述:研究的问题和挑战 从流量分类.路由优化.服务质量(Qos)/体验质量(QoE)预测.资源管理和安全性的角度,回顾了机器学习算法如何应用于SDN领域. 相关知识 在SDN中 ...

  2. 2017[BUAA软工]第0次个人作业

    第一部分:结缘计算机 1.你为什么选择计算机专业?你认为你的条件如何?和这些博主比呢? ●其实填写志愿之前并不知道要学什么专业,当初选择计算机是因为计算机就业前景好.方向多.计算机应用的领域无处不在, ...

  3. 转帖 Oracle 主键的处理方法 http://www.cnblogs.com/Richardzhu/p/3470929.html

    Oracle之主键的创建.添加.删除操作   一.创建表的同时创建主键约束 1.1.无命名 SQL> create table jack (id int primary key not null ...

  4. 解决vmware与主机无法连通的问题

    我们选择NAT方式,来实现Ubuntu的静态IP地址配置. 打开VMware,在顶部依次选择:编辑 > 虚拟网路编辑器,打开虚拟网路编辑器:去掉VMnet0和VMnet1,只保留VMnet8.然 ...

  5. 关于EXCEL if、countif 在查找数据的用法

    最近被其他部门的同事教导使用excel.突然觉得以前用代码切来切去的东西,和频繁比对的数据原来是用excel就能那么方便的算出,瞬间感觉打开了新世界的大门. 先说if和countif结合使用,来判断一 ...

  6. SVG to Image in js

    SVG to Image in js SVG to Image https://image.online-convert.com/convert-to-svg https://stackoverflo ...

  7. 自学Linux Shell3.5-目录处理命令mkdir rmdir

    点击返回 自学Linux命令行与Shell脚本之路 3.5-目录处理命令mkdir rmdir 1. mkdir命令 创建一个或多个新的目录. mkdir 命令创建由 Directory 参数指定的一 ...

  8. 51Nod 1048 1383 整数分解为2的幂

    任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量! 比如N = 7时,共有6种划分方法.   7=1+1+1+1+1+1+1   =1+1+1+1+1+2   =1+1+1+2+2   ...

  9. sprintf-%s的用法

    @2018-9-19 sprintf-%s的用法 #include <stdio.h> #include <string.h> char string[] = "I ...

  10. 洛谷 P4100 [HEOI2013]钙铁锌硒维生素 解题报告

    P4100 [HEOI2013]钙铁锌硒维生素 题目描述 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加 宇宙比赛的饮食. 众所周知,前往宇宙的某个星球,通常要花费好长好长的时间, ...