实时波形显示---带来的VC++中窗口重绘精析(WM_PAINT)

WHAT:
实时波形显示---带来的VC中窗口重绘精析(WM_PAINT)

WHY:
开发了一个小测试程序, 程序的目的是用来实时采集通道信号, 显示采集数据, 实时波形显示, 存储数据.  问题是出现在波形显示阶段. 波形是显示在CPlotClass控件类(可下载)中, 通过重绘OnPaint()绘制波形以及坐标. 为了节省资源不使用自带的定时器. 但窗口初始化完成后不能立即显示波形及坐标, 而且在OnInitDialog(), OnPaint()以及其它事件中添加Invalidate()或发送重绘消息终不起作用. 故另辟蹊径, 写此文分享.

HOW:
我们的目标是调用CPlotClass控件类的重绘函数OnPaint(). 而OnPaint()又是窗口消息WM_PAINT的处理函数, 故我们必须搞清楚WM_PAINT重绘是怎样实现的. 窗口消息WM_PAINT的发送者可以是system或application.
1. 归纳得出3种重绘消息WM_PAINT的发送方式
(1)system自动发送重绘消息
 system会在update region不为空且message queue为空时自动发送WM_PAINT消息. 窗口的拖拽, 移动, 最大化, 最小化会引起system累积更新update region, application也可以通过Invalidate()/InvalidateRect()/InvalidateRgn()来累积更新update region.
(2) application直接发送重绘消息
application可以直接调用SendMessage()或PostMessage()来发送WM_PAINT消息.
(3) application间接发送重绘消息
application可以调用UpdateWindow()/RedrawWindow()来发送WM_PAINT消息. 其中UpdateWindow()的内部实现是检查update region不为空后发送消息--SendMessage(). RedrawWindow()的内部实现是累积更新update region后邮寄消息--PostMessage().

2. 归纳得出重绘消息WM_PAINT的处理方式
application通过消息处理函数OnPaint()来处理消息,但在OnPaint()中, CPaintDC dc(this)在构造时使用了update region初始化dc, 所以重绘的东西都重绘到update region. 如果update region为空, 即使发送WM_PAINT消息, 也好像什么都没做(感觉没重绘一样, 其实是重绘了, 只不过是重绘到空的update region上). 这也是为什么网上一直有人在问SendMessage(WM_PAINT)/SendMessage(WM_PAINT)为啥就不起作用.

3. 归纳得出重绘消息WM_PAINT的重绘局限
搞清楚WM_PAINT发送方式和处理方式后, 还要搞清楚WM_PAINT重绘局限--即在什么时间地点发送它才是合理的. 例如, 在OnInitDialog()函数中添加Invalidate()不起作用, 这是因为在调用OnInitDialog()时, 窗口还没显示, 就无所谓重不重绘的问题了.  在OnPaint()函数中添加Invalide() 不起作用, 这是因为重绘函数中在重绘会导致死循环. 添加到其它函数也是有雷同的效果, 不是在窗口初始化完成前重绘, 就是重绘死循环. 故归纳为 OnInitDialog()和OnPaint()中不可以实现重绘.

根据上述三点归纳可以提出问题的四个solution:
***solution1:  添加定时器. 可以在OnInitDialog()函数中启动一个定时器, 在定时器处理函数中添加Invalidate()并kill it, system会自动发送WM_PAINT消息. 这个方案的好处是比较简单, 但定时器是占用资源的, 所以我推荐solution2.
***solution2: 自定义消息来延迟窗口重绘. 可以自定义一个消息, 添加消息处理函数和消息映射, 在消息处理函数中添加Invalidate(). 然后在OnInitDialog()函数的尾部添加邮寄消息PostMessage(你的消息). 这样就大功告成了. 这个方案只是在对话框初始化中邮寄了一个用户消息, 系统会调用用户消息处理函数中的Invalidate(). 此时,系统使用system自带发送重绘消息方式可在窗口初始化后立即重绘. 这个方案的好处不占资源,但添加的代码较多一些, 所以我推荐solution3.
***solution3: 修改OnPaint. 根据上述的WM_PAINT的处理方式我们可以简单的修改CPlotClass的OnPaint().  第一次使用CDC类型的dc
以后都使用CPaintDC的dc. 这样做的好处是不用定时器, 不用延迟就可在窗口显示的第一次完成坐标和波形的显示.
***solution4: 个人觉得这是最好的解决法案. 我们可以直接波形当成背景画在static控件的背景上, 也就是说波形是以背景的形式存在(不是通过dc话画出来的前景), 系统在需要的时候会自动重绘.
这里推荐另一个类实现实时波形的显示, 叫ChartDirector.  它的功能十分强大, 它的波形就是以背景的形式设置在static控件上的.


REFERENCE:
[1] MSDN

NOTE:
我分享总结, 欢迎你分享意见和评论 (关于内容, 写作, 个人情感的什么都可以), 这样我们才能共同进步.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值