今天在学习用内存DC画图,终于有了初步了解。现将收集的关于内存DC介绍及其相关操作的资料贴出来共享一下。

danxuezx 2009-06-04 03:59:48

DC 即Device Context,是GDI内部的一个资料结构,一个DC会和某个特定的显示设备(如打印机、屏幕等)产生关联。我们如果能取得该DC的handle 那我们便可以在这显示设备上写字、画图。
在Form 或Picturebox中都有一个hdc的属性,指的便是这东西,但是,怎么又会有一个Memory DC呢?这是一个存在记忆体内的 dc ,它除了不像form picturebox能将图形、文字显示出来之外,其他的几乎都相同,它也可以用在所有的 GDI API 呼叫之上,其实我们在VB中早就有使用上这 Memory DC 了,只是没有自觉。当我们设 form picturebox的AutoRedraw = True时, hdc所指的便是Momoory DC,这时我们在其上作绘图动作,都没有显示在form上,这便是先前说的,它只是在记忆体中,不会真的画出图。而我们下 refresh指令时,便是将这MemoryDC上的图,copy到 form/PictureBox上。
  另外我们也可以使用CreateCompatibleDC() API 它传入一个 hDc ,代表产生的 Memory DC和 hdc相容,若传0则是与屏幕相容的 Memory DC hMemDC = CreateCompatibleDC(0)
  这时候,该hMemDC所指的绘图区有多大呢?其实只有一个单色Pixel,直到我们使用SelectObject( hMemDC, hBitmap)
  那hMemDC显示区就会有和hBitmap一样的宽度、高度、颜色选择等。 而且我们在hMemDC上的任何绘图,也都会反映在 hBitMap上,也就是说,原本hBitMap所指的图,在SelectObject(hMemDC, hBitMap)后,我们使用gdi函式在hMemDC上画一条线,那么该hBitmap所指的图也会有一条线了。
那么Memory DC又有什么作用呢?
我们知道, 在使用VC开发图形相关的应用程序时,常常需要使用MFC的CDC类直接把图形画在窗口上。这通常是通过响应Windows的WM_PAINT消息实现的。如果要画的图形比较复杂,或者比较大,那么画图过程可能会造成窗口的闪烁。当窗口调整大小时,这种闪烁由为明显。
解决窗口闪烁问题的有效办法就是使用内存DC,也称为缓冲DC。在内存中准备一个和窗口DC相同属性的DC,在这个内存DC上执行画图操作。完成画图以后,把画图输出的内容整体复制到目标窗口DC上。因为画图操作不在窗口DC上进行,所以在画图的过程中窗口可以保持原来的内容。当画好的内容被复制到窗口DC时,因为复制操作执行的非常快,所以用户感觉窗口仿佛被立刻被画好,从而消除了从旧画面到白板再到新画面的闪烁现象。
生成内存DC主要用到以下四个函数:
CreateCompatibleDC(CDC* pDC )。CDC类的成员函数,用于创建一个和pDC指向的DC兼容的内存DC。
CreateDiscardableBitmap( CDC* pDC, int nWidth, int nHeight)。CBitmap类的成员函数,用于按指定尺寸创建一个和pDC指向的DC兼容的位图。
SelectObject(CBitmap * pBitmap)。CDC类的成员函数,执行以后,所有在该DC上的图像输出都将被画到pBitmap指向的位图上。
BOOL BitBlt (int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop )。CDC类的成员函数,用于从源DC(pSrcDC)复制一个矩形的图象到当前DC中。
好了,目前我所能理解到的原理就是上面的样子,下面来看看具体应该怎样操作吧。
对于一个窗口,我们可以用下面的代码来创建内存DC,在内存DC上输出,并最终复制到窗口DC上。
void PaintWnd(CWnd * pWnd)
{
CDC * pWndDC = pWnd->GetWindowDC();
CRect WndRect = pWnd->GetWindowRect();
CDC MemDC;
CBitMap MemBitmap;
MemDC.CreateCompatibleDC(pWndDC); // 创建内存DC
MemBitmap.CreateCompatibleBitmap( // 创建兼容的位图
pWndDC,
WndRect.Width(),
WndRect.Height());
MemDC.SelectObject(MemBitmap); // 让内存DC输出到位图(我的理解就是选择画布)
// 使用MemDC画图
……
pWndDC->BitBlt(// 从内存DC复制到窗口DC
0,0,
WndRect.Width(),
WndRect.Height(),
&MemDC,
0,0,
SRCCOPY);
}

当然,实际的情况下,我们需要考虑的更多,因为内存DC、位图的创建都可能会失败。为了简化代码,此处定义了一个类CMemoryDC,包装了内存DC创建过程中的出错处理,内存DC的事后清理等操作,并自动复制内存DC的内容到目标DC上。
声明CMemoryDC类的头文件MemoryDC.h如下:
#pragma once
#include "Afxwin.h"

class CMemoryDC
{
public:
CMemoryDC(CDC *dc, RECT * rect,bool autoRender = false);
~CMemoryDC(void);

bool IsOK();
void Render(CDC * p_objectDC = NULL);
CDC* GetMemoryDC();
operator CDC * ();
private:
bool m_bAutoRender;
CRect m_DCRect;
CDC* m_pOriginalDC;
CDC m_MemoryDC;
CBitmap m_MemoryBmp;
};

类的实现文件CMemoryDC.cpp如下:
 #include ".MemoryDC.h"

CMemoryDC::CMemoryDC(CDC *dc, RECT * rect, bool autoRender)
{
m_bAutoRender = autoRender;
m_pOriginalDC = dc;
if (dc==NULL || rect==NULL)
return;
if (!m_MemoryDC.CreateCompatibleDC(dc))
return;
m_DCRect.SetRect(rect->left, rect->top, rect->right, rect->bottom);
if (!m_MemoryBmp.CreateCompatibleBitmap(dc, m_DCRect.Width(), m_DCRect.Height()))
return;
m_MemoryDC.SelectObject(m_MemoryBmp);
}

CMemoryDC::~CMemoryDC(void)
{
if (m_bAutoRender)
Render();
if (m_MemoryDC.m_hDC!=NULL)
m_MemoryDC.DeleteDC();
if (m_MemoryBmp.m_hObject!=NULL)
m_MemoryBmp.DeleteObject();
}

bool CMemoryDC::IsOK()
{
return m_MemoryDC.m_hDC!=NULL && m_MemoryBmp.m_hObject != NULL;

}
void CMemoryDC::Render(CDC * p_objectDC)
{
if (!IsOK())
return;

CDC * pDC = (p_objectDC==NULL ? m_pOriginalDC : p_objectDC);
CSize Size = m_MemoryDC.GetViewportExt() ;
pDC->BitBlt(
m_DCRect.left,
m_DCRect.top,
m_DCRect.Width(),
m_DCRect.Height(),
&m_MemoryDC,
0,0,
SRCCOPY);
}
CDC* CMemoryDC::GetMemoryDC()
{
return & m_MemoryDC;
}
CMemoryDC::operator CDC * ()
{
return & m_MemoryDC;
}

使用这个类可以大大简化内存DC的创建操作。如果我们在窗口消息WM_PAINT的响应函数中使用内存DC,只要用如下这样简便的代码便可实现:
CRect Rect;
GetClientRect(Rect);
CPaintDC dc(this); // device context for painting
CMemoryDC MemDC(&dc, Rect, true);
if (MemDC.IsOK())
{
// 使用MemDC画窗口
}
// MemDC析构时会自动把图像复制到dc,无需其它操作
使用CMemoryDC创建内存DC防止窗口闪烁,编程的代码和不使用内存DC时相比,数量和复杂性几乎没有增加。


另外,关于此文章的word文档我也上传了,需要的朋友可去下载。http://download.csdn.net/source/1381542
...全文
1181 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
laofana1 2011-10-10
  • 打赏
  • 举报
回复
多些楼主了~~
雨夜枫林 2011-08-20
  • 打赏
  • 举报
回复
来学习学习。。
qq52016000 2010-07-24
  • 打赏
  • 举报
回复
如果要画的图形比较复杂,或者比较大,那么画图过程可能会造成窗口的闪烁。当窗口调整大小时,这种闪烁由为明显。。。。。


我不画图,但我也这样做!但不是制造闪烁,是为了达到更重要的目的。
powerwadeluo 2010-05-24
  • 打赏
  • 举报
回复
O(∩_∩)O
相互学习啊~~~
squwal 2010-04-29
  • 打赏
  • 举报
回复
流着泪顶贴....
chunan4comeon 2009-07-30
  • 打赏
  • 举报
回复
感谢楼主。。。我看了几年都没明白,现在一下感觉进步大了。老泪纵横啊。。。
laozhang79482058 2009-07-27
  • 打赏
  • 举报
回复
请问,用BITBIL函数从窗口DC中截取到兼容DC的位图可以直接操作吗?还是必须将兼容DC中的文件存为位图文件操作。
solu 2009-06-06
  • 打赏
  • 举报
回复
学习啦,谢谢分享!
xianzi123 2009-06-06
  • 打赏
  • 举报
回复
恩,楼主很好!
clever101 2009-06-04
  • 打赏
  • 举报
回复
楼主好人啊!
  • 打赏
  • 举报
回复
不错
基于SABER的DCDC反激变换器仿真 SABER是美国Analogy公司开发、现由Synopsys公司经营的系统仿真软件,被誉为全球最先进的系统仿真软件,也是唯一的多技术、多领域的系统仿真产品,现已成为混合信号、混合技术设计和验证工具的业界标准,可用于电子、电力电子、机电一体化、机械、光电、光学、控制等不同类型系统构成的混合系统仿真,这也是SABER的最大特点。SABER作为混合仿真系统,可以兼容模拟、数字、控制量的混合仿真,便于在不同层面上分析和解决问题,其他仿真软件不具备这样的功能。  SABER仿真软件是当今世界上功能强大的电力电子仿真软件之一,我们从以下几个方面对SABER仿真软件进行介绍:  1) 原理图输入和仿真。SABER Sketch是SABER的原理图输入工具,通过 它可以直接进入SABER仿真引擎。在SABER Sketch中,用户能够创建自己的原理图,启动SABER完成各种仿真(偏置点分析、DC分析、AC分析、瞬态分析、温度分析、参数分析、傅立叶分析、蒙特卡诺分析、噪声分析、应力分析、失真分析等),可以直接在原理图上查看仿真结果,SABER Sketch及其仿真功能可以帮助用户完成混合信号、混合技术(电气、液压等)系统的仿真分析。SABER Sketch中的原理图可以输出成多种标准图形格式,用于报告、设计审阅或创建文档。集成度高:从调用画图程序到仿真模拟,可以在一个环境中完成,不用四处切换工作环境。  2) 数据可视化和分析。Cosmos Scope是SABER的波形查看和仿真结果分 析工具,它的测量工具有50多种标准的测量功能,可以对波形进行准确的定量分析。它的专利工具——波形计算器,可以对波形进行多种数学操作。Cosmos Scope中的图形也可以输出成多种标准图形格式用于文档。Saber提供了SaberScope和DesignProbe来查看仿真结果,而SaberScope功能更加强大。  3) 模块化和层次化:可将一部分电路块创建成一个符号表示,用于层次设计,并可对子电路和整体电路仿真模拟。  4) 模拟行为模型:对电路在实际应用中的可能遇到的情况,如温度变化及 各部件参数漂移等,进行仿真模拟。  5) 模型库。SABER拥有市场上最大的电气、混合信号、混合技术模型库,它具有很大的通用模型库和较为精确的具体型号的器件模型,其元件模型库中有4700多种带具体型号的器件模型,500多种通用模型,能够满足航空、汽车和电源设计的需求。SABER模型库向用户提供了不同层次的模型,支持自上而下或自下而上的系统仿真方法,这些模型采用最新的硬件描述语言(HDL),最大限度的保证了模型的准确性,支持模型共享。  6) 建模。不同类型的设计需要不同类型的模型,SABER提供了完整的建模功能,可以满足各种仿真与分析的需求。其建模语言主要有MAST、VHDL-AMS、Fortran,建模工具包括State-AMS、5维的图表建模工具TLU,SABER可以对SPICE、SIMULINK模型进行模型转换,同时SABER还拥有强大的参数提取工具,可以通过协同仿真实现模型复用。SABER的混合信号、混合技术设计和验证能力已经得到了业界的验证,功能强大的原理图输入、仿真分析、模型库、建模语言、建模功能再加上先进的布局布线设计使SABER成为业界工程师的首选。SABER的架构和独一无二的模型交换能力为市场上提供了最为强大的仿真工具,能够处理所有的仿真需求。  与PSPICE相比,SABER是功能更为强大的仿真软件,它可以仿真电力电子元件、电路和系统,不仅具有PSPICE的功能,而且具有更丰富的元件库和更精致的仿真描述能力,还能结合数学控制方程模块工作。SABER还可以仿真电力传动、机械、热力、流体等其他运动过程。SABER的仿真真实性很好,从仿真的电路到实际的电路实现,期间参数基本不用修改。与PSPICE相仿,SABER的数据处理量亦相当庞大。SABER应用的主要困难是操作较为复杂,软件价格高昂,比较适合于大企业应用,而中小企业一般是通过委托研究、开发来利用该软件。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧