最近做WIN32 API开发时发现对ScrollWindow的一些工作原理并不是太清楚,于是做了相关研究,记载下来和大家共同学习。

首先在WM_CREATE中获取系统字符的宽度和高度

  1. case WM_CREATE:
  2. //获取系统字符的宽度和高度
  3. cxChar = LOWORD(GetDialogBaseUnits()) ;
  4. cyChar = HIWORD(GetDialogBaseUnits()) ;
  5. //显示字体大小
  6. sprintf(szBuffer, TEXT("字符高度:%d 字符宽度:%d"), cyChar, cxChar) ;
  7. MessageBox(hwnd, szBuffer, TEXT("字符大小"), MB_OK) ;
  8. return 0 ;

再在WM_SIZE中获取客户区大小

  1. case WM_SIZE:
  2. //获取客户区大小
  3. GetClientRect(hwnd, &rcClient) ;
  4. //显示客户区大小
  5. sprintf(szBuffer, TEXT("左上角:%d %d 右下角:%d %d"), rcClient.left, rcClient.top, rcClient.right, rcClient.bottom) ;
  6. MessageBox(hwnd, szBuffer, TEXT("客户区大小"), MB_OK) ;
  7. return 0 ;

为了增强滚动时的对比效果,在WM_PAINT中分别写左右两行文字

  1. case WM_PAINT:
  2. hdc = BeginPaint (hwnd, &ps) ;
  3. //获取重画区域大小
  4. sprintf(szBuffer, TEXT("%d %d %d %d"), ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom) ;
  5. MessageBox(hwnd, szBuffer, TEXT("重画区域"), MB_OK) ;
  6. TextOut(hdc, 0, (rcClient.bottom-rcClient.top)/2,
  7. TEXT("Text Out here left!"), lstrlen(TEXT("Text Out here left!"))) ;
  8. TextOut(hdc, (rcClient.right-rcClient.left)/2, (rcClient.bottom-rcClient.top)/2,
  9. TEXT("Text Out here right!"), lstrlen(TEXT("Text Out here right!"))) ;
  10. EndPaint (hwnd, &ps) ;
  11. return 0 ;

下面再加上滚动右边文字的代码

  1. case WM_KEYDOWN:
  2. CopyRect(&rect, &rcClient) ;
  3. rect.left = rcClient.right / 2 ;
  4. switch(wParam)
  5. {
  6. case VK_DOWN:
  7. ScrollWindow(hwnd, 0, cyChar, &rect, &rect) ;
  8. break ;
  9. case VK_UP:
  10. ScrollWindow(hwnd, 0, -cyChar, &rect, &rect) ;
  11. break ;
  12. }
  13. return 0 ;

运行依次进入WM_CREATE,WM_PAINT,WM_SIZE消息

WM_CREATE中显示

WM_PAINT中显示

WM_SIZE中显示

可知

字符大小为高度16px    宽度8px

客户区大小为宽1009px    高488px

左边显示区域范围为左0px    上0px    右504px    下488px

右边显示区域范围为左504px    上0px    右1009px    下488px

按小键盘上的上下滚动键分别得到重绘区域为

对比计算

可知当使用ScrollWindow时左边区域并没有重绘

当右边向上滚动时 重绘区域为向上滚动后没有被滚动区域覆盖的最小面一行字符区域

当右边向下滚动时 重绘区域为向下滚动后没有被滚动区域覆盖的最上面一行字符区域

故 我们再看看微软MSDN中对ScrollWindow的描述

“如果在被滚动的窗口中含有^符,ScrollWindow将自动隐藏起^符,以防它被擦掉;当滚动结束后再恢复^符。^符的位置相应的被调整过来。  

未被ScrollWindow覆盖的区域不再重画,但该区域会与窗口更新区域组合。应用程序最终收到WM_PAINT的消息,通知它结合区域必须被重画。为了在滚动操作的同时重画未覆盖区域,则应在调用ScrollWindow函数后马上调用UpdateWindow函数。  

如果参数lpRect为NULL,则窗口中的任何子窗口的位置由参数XAmount和Yamount的数值决定偏移;窗体无效(未着色)的区域也偏移。IpRect为NULL时ScrollWindow执行地更快。  

如果参数lpRect不为NULL,则窗口中的子窗口的位置不改变,窗口中无效(未着色)的区域也不偏移。为了防止lpRect不为NULL时更新的问题,需要在调用ScrollWindow前调用UpdateWindow函数重绘窗口。”

这里的未被scrollWindow覆盖的区域应该强调是scrollWindow使用的剪切区域中未被滚动操作覆盖的区域,这里是很多人难以理解的地方,务必注意。

那么如何高效的使用ScrollWindow这个API函数呢

这里笔者以每次滚动一行文字为例,提供两种方法

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

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

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

在调用按ScrollWindow后获得窗口DC,自己绘制未被滚动操作覆盖的一行,然后将整个滚动剪切区域设为有效,禁止其产生WM_PAINT消息,这样也可加快绘制速度。

原创,转载请注明来自http://blog.csdn.net/wenzhou1219

http://blog.csdn.net/wenzhou1219/article/details/7798967

深入探索ScrollWindow的更多相关文章

  1. 探索Win32系统之窗口类(转载)

    Window Classes in Win32 摘要 本文主要介绍win32系统里窗口类的运做和使用机制,探索一些细节问题,使win32窗口类的信息更加明朗化. 在本文中,"类", ...

  2. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  3. 【探索】利用 canvas 实现数据压缩

    前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...

  4. 探索C#之6.0语法糖剖析

    阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...

  5. Mysql事务探索及其在Django中的实践(二)

    继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...

  6. Linux学习之探索文件系统

    Linux,一起学习进步-    ls With it, we can see directory contents and determine a variety of important file ...

  7. 马里奥AI实现方式探索 ——神经网络+增强学习

    [TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...

  8. C++随笔:.NET CoreCLR之GC探索(4)

    今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...

  9. C++随笔:.NET CoreCLR之GC探索(2)

    首先谢谢 @dudu 和 @张善友 这2位大神能订阅我,本来在写这个系列以前,我一直对写一些核心而且底层的知识持怀疑态度,我为什么持怀疑态度呢?因为一般写高层语言的人99%都不会碰底层,其实说句实话, ...

随机推荐

  1. GANs(生成对抗网络)初步

    Image Completion with Deep Learning in TensorFlow 1. 基本思路 首先定义一个简单的.常见的概率分布,将其表示为 pz,不妨将其作为 [-1, 1] ...

  2. POJ 2728 - 最小比例生成树

    传送门 题目大意 有n个村庄,每个村庄都有一个(x, y)坐标和z海拔,定义两个村庄间的dist为坐标的距离,cost为海拔差的绝对值,求图的一颗生成树,使得\(\frac{\sum cost}{\s ...

  3. 【BZOJ 1032】 [JSOI2007]祖码Zuma

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1032 [题意] [题解] /* 设f[i][j]表示从第i个珠子开始的j个珠子被消除; ...

  4. java写文件时往末尾追加文件(而不是覆盖原文件),的两种方法总结

    代码如下: import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; public ...

  5. matlab 神经网络工具箱的实用

    0. 其他处理 计时: tic net = train(net, X, y); toc 1. 一个简单的 demo(单层感知器) P = [1, 1, 1, 1, 0, 0, 0, 0; 0, 0, ...

  6. sql数据库恢复神器--Log Explorer 4.2使用教程

    对于程序员来说,世界最悲催的事情是什么?——就是手贱,把数据库的数据给删掉了,更悲催的是木有任何数据库备份  感谢万能的度娘,感谢无私奉献的网友们,最感谢强大的LogExplorer工具 . 使用Lo ...

  7. 将字符串转换成xml并取得对应的值

    如数据库中有一个字段保存了xml格式的一串字符串: <?xml version="1.0" encoding="utf-16"?><Array ...

  8. vue: 关于多路由公用模板,导致组件内数组缓存问题

    当多个路由复用同一个模板,此时在这几个路由间切换,模板并不会重新挂载.针对这个情况,我们需要在当前逻辑内对路由做监听,在发生变化时更新对应属性,已满足需求. 但是,在实现的过程中会遇到如下情况: 如图 ...

  9. Linux命令list

    文件和目录 cd /home 进入 '/ home' 目录' cd .. 返回上一级目录 cd ../.. 返回上两级目录 cd 进入个人的主目录 cd ~user1 进入个人的主目录 cd - 返回 ...

  10. qt的应用层主要是大型3d,vr,管理软件和器械嵌入软件(有上千个下一代软件黑科技项目是qt的,美国宇航局,欧洲宇航局,超级战舰DDG1000)

    作者:Nebula.Trek链接:https://www.zhihu.com/question/24316868/answer/118944490来源:知乎著作权归作者所有.商业转载请联系作者获得授权 ...