基于对话框的简单双缓冲绘图框架

MFC双缓冲绘图 1、为什么使用双缓冲? 我们都知道电脑CPU计算速度是非常快的,但是电脑要把信息显示到显示屏上,是比较慢的,因为显示屏要去更新像素点,假如我们要画1000条线,CPU画一条线只需要微秒,但是显示屏显示一条线需要1毫秒,如果我们不使用双缓冲,使用一个for循环输出1000条线,那么显示屏要刷新1000次才能完成1000条线的绘制,这会花掉1.001秒钟才能绘制一次我们想要的图形。很明显,这是非常低 阅读详情

摘自:http://blog.youkuaiyun.com/clever101/article/details/6073791

作者:朱金灿
来源:http://blog.youkuaiyun.com/clever101/


     基于文档视图结构程序的双缓冲绘图框架比较多,那么如何在对话框上绘图呢?以前通常的做法是拖一个静态文本控件或其它控件当作绘图区域或者在这个区域上创建一个视图出来。看了微软的一个示例程序DrawCli(一个绘图的单文档程序),产生了一些灵感,决心把它移植到对话框绘图上,摸索了一下,搞了一个基于对话框的简单双缓冲绘图框架。


     具体代码如下,对话框头文件代码:


    

[cpp]  view plain copy
  1. #include <vector>  
  2. //@brief 直线结构体  
  3. struct stLine  
  4. {  
  5.     stLine(CPoint &Begin,CPoint &End)  
  6.     {  
  7.         m_Begin = Begin;  
  8.         m_End = End;  
  9.     }  
  10.     //@brief 起点  
  11.     CPoint m_Begin;  
  12.     //@brief 终点  
  13.     CPoint m_End;  
  14. };  
  15. class CDoubleBufDrawDlg : public CDialog  
  16. {  
  17.     DECLARE_DYNAMIC(CDoubleBufDrawDlg)  
  18. public:  
  19.     CDoubleBufDrawDlg(CWnd* pParent = NULL);   // 标准构造函数  
  20.     virtual ~CDoubleBufDrawDlg();  
  21. // 对话框数据  
  22.     enum { IDD = IDD_DIALOG_GDIPLUS };  
  23. protected:  
  24.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持  
  25.     DECLARE_MESSAGE_MAP()  
  26. public:  
  27.     virtual BOOL OnInitDialog();  
  28.     afx_msg void OnBnClickedDrawPoint();  
  29.     afx_msg void OnBnClickedDrawLine();  
  30.     afx_msg void OnSize(UINT nType, int cx, int cy);  
  31.     void AdjustControls();  
  32.     afx_msg void OnPaint();  
  33. protected:  
  34.     //   
  35.     void InitDrawPara();  
  36. protected:  
  37.     //@brief 上一个点  
  38.     CPoint m_PrePt;  
  39.     //@brief 鼠标按下点  
  40.     CPoint m_DownPt;  
  41.     //@brief 直线结构体数组  
  42.     std::vector<stLine> m_Lines;  
  43. public:  
  44.     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);  
  45.     afx_msg void OnMouseMove(UINT nFlags, CPoint point);  
  46.     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);  
  47. };   



    Cpp文件源码(这里只列出主要函数):


   

[cpp]  view plain copy
  1. //@brief 初始化绘图参数  
  2. void CDoubleBufDrawDlg::InitDrawPara()  
  3. {  
  4.     m_PrePt = CPoint(-1,-1);  
  5.     m_DownPt = CPoint(-1,-1);  
  6. }  
  7. CDoubleBufDrawDlg::CDoubleBufDrawDlg(CWnd* pParent /*=NULL*/)  
  8. : CDialog(CDoubleBufDrawDlg::IDD, pParent)  
  9. {  
  10.     InitDrawPara();  
  11. }  
  12. void CDoubleBufDrawDlg::OnLButtonDown(UINT nFlags, CPoint point)  
  13. {  
  14.     // TODO: 在此添加消息处理程序代码和/或调用默认值  
  15.     // 记录鼠标按下点  
  16.     m_DownPt = point;  
  17.     CDialog::OnLButtonDown(nFlags, point);  
  18. }  
  19. void CDoubleBufDrawDlg::OnMouseMove(UINT nFlags, CPoint point)  
  20. {  
  21.     // TODO: 在此添加消息处理程序代码和/或调用默认值  
  22.     // 假如在移动鼠标的同时按下左键  
  23.     if (MK_LBUTTON&nFlags)  
  24.     {  
  25.         CDC *pDC = GetDC();  
  26.         pDC->SetROP2(R2_NOTXORPEN);  
  27.     // 将绘图区域限制在对话框的客户区上面的/4区域  
  28. CRect rtDraw(rtClient.top,rtClient.left,rtClient.Width(),3*(rtClient.Height()/4));  
  29.     CRgn DrawRgn;  
  30.     DrawRgn.CreateRectRgn(rtDraw.left,rtDraw.top,rtDraw.right,rtDraw.bottom);  
  31.     pDC->SelectClipRgn(&DrawRgn);  
  32.         if (m_PrePt.x!=-1)  
  33.         {  
  34.             // 擦除上一条线  
  35.             pDC->MoveTo(m_DownPt);  
  36.             pDC->LineTo(m_PrePt);  
  37.         }  
  38.         // 画线  
  39.         pDC->MoveTo(m_DownPt);  
  40.         pDC->LineTo(point);  
  41.         ReleaseDC(pDC);  
  42.         m_PrePt = point;  
  43.     }  
  44.     CDialog::OnMouseMove(nFlags, point);  
  45. }  
  46. void CDoubleBufDrawDlg::OnLButtonUp(UINT nFlags, CPoint point)  
  47. {  
  48.     // TODO: 在此添加消息处理程序代码和/或调用默认值  
  49.     // 将绘制的直线加入到直线数组  
  50.     m_Lines.push_back(stLine(m_DownPt,point));  
  51.     // 初始化绘图参数  
  52.     InitDrawPara();  
  53.     CDialog::OnLButtonUp(nFlags, point);  
  54. }  
  55. void CDoubleBufDrawDlg::OnPaint()  
  56. {  
  57.     // 最小时绘制菜单图标,因为我是在一个单文档程序中弹出该对话框的,故不需要绘制图标  
  58.     // 如果是基于对话框的程序则需要绘制图标  
  59.     if (IsIconic())  
  60.     {  
  61.         CPaintDC dc(this); // device context for painting  
  62.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);  
  63.         // Center icon in client rectangle  
  64.         //int cxIcon = GetSystemMetrics(SM_CXICON);  
  65.         //int cyIcon = GetSystemMetrics(SM_CYICON);  
  66.         //CRect rect;  
  67.         //GetClientRect(&rect);  
  68.         //int x = (rect.Width() - cxIcon + 1) / 2;  
  69.         //int y = (rect.Height() - cyIcon + 1) / 2;  
  70.         //// Draw the icon  
  71.         //dc.DrawIcon(x, y, m_hIcon);  
  72.     }  
  73.     else  
  74.     {  
  75.         CPaintDC dc(this);  
  76.         // 定义一个兼容DC  
  77.         CDC CompaDC;  
  78.         // 初始化绘图DC指针  
  79.         CDC* pDrawDC = &dc;  
  80.         CBitmap bitmap;  
  81.         CBitmap* pOldBitmap = 0;  
  82.         CRect rtClient;  
  83.         GetClientRect(&rtClient);  
  84.         // 将对话框的客户区上面的/4区域设为绘图区域  
  85.         CRect rtDraw(rtClient.top,rtClient.left,rtClient.Width(),3*(rtClient.Height()/4));  
  86.         // 假如不是打印机DC  
  87.         if (!dc.IsPrinting())  
  88.         {  
  89.             // 创建兼容DC,创建兼容位图,将兼容位图选进兼容DC  
  90.             if (CompaDC.CreateCompatibleDC(&dc))  
  91.             {  
  92.                 if (bitmap.CreateCompatibleBitmap(&dc,rtDraw.Width(),rtDraw.Height()))  
  93.                 {  
  94.                     pDrawDC = &CompaDC;  
  95.                     pOldBitmap = CompaDC.SelectObject(&bitmap);  
  96.                 }  
  97.             }  
  98.         }  
  99.         // 定义一个白色画刷,将背景色设为白色  
  100.         CBrush brush;  
  101.         if (!brush.CreateSolidBrush(RGB(255,255,255)))  
  102.             return;  
  103.         brush.UnrealizeObject();  
  104.         pDrawDC->FillRect(rtDraw,&brush);  
  105.         // 绘制直线  
  106.         for (size_t i = 0;i<m_Lines.size();i++)  
  107.         {  
  108.             pDrawDC->MoveTo(m_Lines[i].m_Begin);  
  109.             pDrawDC->LineTo(m_Lines[i].m_End);  
  110.         }  
  111.         // 使用GDI+绘制一个线性渐变画刷  
  112.         Gdiplus::Graphics graphics(pDrawDC->m_hDC);  
  113.         LinearGradientBrush linGrBrush(Point(100,0),Point(100,100),Color(255,255,0,0),Color(255,0,255,0));  
  114.         Color colors[] = {  
  115.             Color(255, 255, 0, 0),   // red  
  116.             Color(255, 255, 255, 0), //yellow  
  117.             Color(255, 0, 0, 255),   // blue  
  118.             Color(255, 0, 255, 0)};  // green  
  119.             REAL positions[] = {  
  120.                 0.0f,     
  121.                 0.33f,     
  122.                 0.66f,  
  123.                 1.0f};    
  124.                 linGrBrush.SetInterpolationColors(colors, positions,4);  
  125.                 // 填充指定区域矩形  
  126.                 graphics.FillRectangle(&linGrBrush,100,0,100,100);  
  127.                 graphics.ReleaseHDC(pDrawDC->m_hDC);  
  128.                 if (pDrawDC != &dc)  
  129.                 {  
  130.                     // 将绘图DC贴到真正的设备DC上  
  131.                     dc.BitBlt(rtDraw.left,rtDraw.top,rtDraw.Width(),rtDraw.Height(),&CompaDC, 0, 0, SRCCOPY);  
  132.                     CompaDC.SelectObject(pOldBitmap);  
  133.                 }  
  134.     }  
  135. }   


    效果图如下,其中上面的白色区域为绘图区域:


Dlg Double Buf



    现在你怎么改变对话框的大小绘图区域也不会产生非双缓冲绘图那种闪烁。

双缓冲技术解决屏幕刷新闪烁 1. 屏幕刷新时产生闪烁的原因 在MFC对话框上画图形,当需要显示新的图形或使原来的图形显示发生变化时,就需要刷新背景,也就是用背景颜色的画刷把背景重新刷一遍,这样就把原来的图形覆盖掉了,然后画上新图形,即可完成图形的刷新显示或动态显示。但是由于背景颜色(一般是白色)与图形颜色之间的反差,在不断的刷新、显示、刷新、显示过程中就会产生闪烁。这里要强调一下,闪烁本质上就是反差,反差越大,闪烁就越厉 阅读详情

相关推荐

VC对话框添加View,双缓冲画图(升级版)

是对上一版的一些调整和修改...更加完善和复杂

兼容位图的理解与实例

<br />CreateCompatibleBitmap  函数功能:该函数创建与指定的设备环境相关的设备兼容的位图。<br /> <br />通常情况下,如果是同一类设备,创建的DC的初始化环境是相同的,问题在于设备DC在变化,运行过程中一定会调整属性,如果再创建一个同类设备的DC,初始属性肯定不一样,不兼容的可能性是很大的,所以以某个运行时刻的DC为基准创建一个兼容DC,将复制当前时刻的DC属性,它的属性可以保证是相同的,这才是兼容DC的目的,而不是直接使用CreateDC。<br /><br />因为

hanshuangfly的专栏 2972

mfc 双缓存 对话框 实例

资源包含vs2010生成的源程序和exe。mfc对话框双缓存的源程序代码。 实现功能: ①button1:双缓存绘图。 ②button2:普通绘图。 非常简单的内容。便于新手更快理解双缓存的操作。使用时,可结合说明的blog 地址:http://blog.youkuaiyun.com/i_likechard/article/details/53066504

DrawCli一个简单的绘图软件

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34279246的博客 602

在对话框上用双缓冲技术画图

在对话框上建立picture控件,并利用双缓冲技术在控件所在区域画图。

CMOS的宽/长比、传输门与三态门、锁存器与触发器、简单版图、竞争与冒险

目录 1.CMOS的宽长比 2.传输门与三态门 传输门 三态门 3.锁存器与触发器 3.1RS锁存器[3] 3.2D锁存器 3.3D触发器 4.简单CMOS器件的版图 5.竞争与冒险 1.CMOS的宽长比 关于COMS原理及结构图可以参考[1]COMS原理及门电路设计. 栅在源漏方向的长度称作栅的长L,垂直方向称为栅的宽W,如图1中NMOS的版图。 图1 以MOS管...

king阿金 1万+

VC++五子棋开发实战:从MFC入门到AI实现

桌面应用开发是理解操作系统与用户交互的基础,其核心在于消息循环与图形界面渲染机制。在Windows平台,MFC(Microsoft Foundation Classes)框架作为经典的C++ GUI开发库,通过封装Windows API,为开发者提供了构建原生应用程序的高效路径。掌握MFC不仅能深入理解窗口过程、GDI绘图等底层原理,更能锻炼工程化思维,实现从业务逻辑到可视化呈现的完整闭环。例如,在开发类似五子棋的桌面游戏时,开发者需综合运用数据结构设计、胜负判定算法,并处理鼠标消息、实现双缓冲绘图以优化体

weixin_30367169的博客 397

Prometheus常用配置介绍

除了 scrape_configs 外,上部还有 global 和 rule_files 部分, 其中 global 中 是 全 局 参 数 , scrape_interval 指 定 全 局 默 认 的 时 间 间 隔 , evaluation_interval 指定告警规则校验的时间间隔,rule_files 指定了告警规 则文件的位置名称。• annotations(注释):它们被用于存储更长的其他信息,例如警报描述 或者链接,注释值也可以被模板化。• alert:告警的名称。

weixin_42886699的博客 2260

MFC 双缓冲 绘图实例

本文用极其简单的mfc对话框程序,通俗易懂的讲解了双缓存技术。总共八步,按照操作,每一个新手都可以从这个简单的实例中开始学习双缓存绘图。 ————————————————————————————————————————————开始 其实,双缓冲只是名字叫的好听罢了,总体也没什么技术含量,在这里举个小例子就可以了: ...

没有蛀牙lm的博客 4177

gm/ID设计方法实践指南:从理论曲线到电路优化的关键步骤

本文详细介绍了gm/ID设计方法在模拟IC设计中的实践指南。该方法通过直接利用工艺模型数据,将设计焦点从盲目调整晶体管尺寸转向选择关键的gm/ID工作点,从而在先进工艺下实现功耗、增益和带宽等性能的精准权衡与优化。文章从理论曲线生成到具体电路设计步骤,提供了完整的实战流程。

pandas7gardener的博客 480

【Office激活】学校正版Office已激活成功仍弹出激活窗口

学校正版Office激活问题:已激活成功仍弹出激活窗口

ESCM_的博客 1万+

双缓冲应用 之 窗口绘图防闪烁,基于对话框的绘图

在使用VC++编写某些绘图程序时,你可能会发现,窗口在每次重绘时都会发生闪烁。特别是在绘制较复杂的图 像时,这种闪烁将会更加剧烈。这里介绍一种防止窗口绘图时闪烁的双缓冲技术。 首先,先解释一下什么叫双缓冲。双缓冲,即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。 通过这个简短的解释,你是否对双缓冲

SunJerdege 1868

Rk3128投影仪救砖操作和固件分享思路

大家搞一条比较硬的东西,插入耳机口,就可以进入刷机模式了的,我的机器是这样的,大家也可以试试。(看不懂可以往下看)

MMX7088的博客 1万+

MFC双缓冲绘图解决界面闪烁问题

一:为什么会产生界面闪烁? 解释这个之前,我们需要明白的是在MFC里面绘图的消息响应机制,大概的就是如果我们要在某一个 东西上面绘图,比如对话框,单文档等等,就必须先得到图形DC的句柄(handle),然后在指定句柄的基础上进行图形操作,也就是MFC常用的CDC *DC = this->getDC();其中的this就是你想画图的目标。 MFC里在消息响应的过程中,WM_PAINT被转变为OnDraw()(单文档 Single Document)或是OnPaint()(对 话框Dialog...

云海唯C的专栏 1053

NTFS分区变成RAW别乱修!正确数据恢复与修复方法详解

文件系统是操作系统管理存储数据的核心机制,NTFS作为Windows主流文件系统,一旦分区识别异常,常会显示为RAW格式。分区变RAW通常意味着文件系统入口信息损坏,而非数据物理消失,但若采用错误的修复方式,如直接对RAW分区执行chkdsk /f,可能因系统无法正确识别文件系统结构,导致写入操作落在错误偏移位置,二次破坏本可恢复的数据。正确的处理思路是:先停止一切写入操作,通过扇区级镜像备份保留原始现场,再分析DBR、分区表及$MFT状态,依据诊断结果选择修复或深度扫描恢复。实际排查中,常见问题如DBR记

weixin_31155097的博客 134

告别玄学调试:手把手教你读懂全志芯片的sys_config.fex配置文件(以i2c配置为例)

本文深入解析全志芯片的sys_config.fex配置文件,以I2C设备驱动为例,详细讲解从引脚定义到驱动加载的全过程。通过实战案例和高级调试技巧,帮助开发者快速掌握硬件配置与内核驱动的联动机制,提升开发效率。

weixin_33737134的博客 419

CDC双缓冲防闪屏绘图总结

CDC在屏幕绘图可以用以下方法: CDC dc; dc.CreateCompatibleDC(NULL); CBitmap m_bitmap; m_bitmap.LoadBitmap(IDB_BITMAP1); //载入资源文件 dc.SelectObject(&m_bitmap); CDC *pDC = GetDC(); pDC->BitBlt(0,0,200,100,&dc,

huangzhe1927的专栏 1212

C++软件调试与异常排查从入门到精通专栏介绍与文章汇总

根据近几年排查软件异常的实践与经验,系统地讲解了C++软件异常常见原因与常用排查方法,以图文并茂的方式给出具体的分析实例,带领大家逐步掌握C++软件异常排查的相关技术与要领。

dvlinker的技术专栏 23万+
上一篇: 基于单文档的VC++动态曲线绘制
下一篇: VC++绘图时,利用双缓冲解决屏幕闪烁
swping
博客等级 码龄20年 10粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值