您的位置:首页 > 其它

关于DC1

2015-06-02 21:26 232 查看
CDC是MFC的DC的一个类

HDC是DC的句柄,API中的一个类似指针的数据类型.

MFC类的前缀都是C开头的

H开头的大多数是句柄

这是为了助记,是编程读\写代码的好的习惯.

CDC中所有MFC的DC的基类.常用的CClientDC dc(this);就是CDC的子类(或称派生类).

CDC等设备上下分类,都含有一个类的成员变量:m_nHdc;即HDC类型的句柄.

记住下面的一句话,会有助于你的理解.

MFC的类,是在用window API语句开发出来的有一定功能的小程序.(也可称为类).使用它的默认方法,就是,记住它的名字与参数(可以用笔记,代替脑记).

如果将window api比做汇编语言

那么MFC就相当于Basic语言.

cdc是设备描述表的基类,clientDC指代客户区的设备描述表,PaintDC只用于OnPaint()函数中

CDC是MFC的DC的一个类

HDC是DC的句柄,API中的一个类似指针的数据类型.

MFC类的前缀都是C开头的

H开头的大多数是句柄

这是为了助记,是编程读\写代码的好的习惯.

CDC中所有MFC的DC的基类.常用的CClientDC dc(this);就是CDC的子类(或称派生类).

CDC等设备上下分类,都含有一个类的成员变量:m_nHdc;即HDC类型的句柄.

记住下面的一句话,会有助于你的理解.

MFC的类,是在用window API语句开发出来的有一定功能的小程序.(也可称为类).使用它的默认方法,就是,记住它的名字与参数(可以用笔记,代替脑记).

如果将window api比做汇编语言

那么MFC就相当于Basic语言.

HDC是WINDOWS的一种数据类型,是设备描述句柄。

而CDC是MFC里的一个类,它封装了几乎所有的关于

HDC的操作。

也可以这样说,HDC定义的变量指向一块内存,这块

内存用来描述一个设备的相关的内容,所以也可以

认为HDC定义的是一个指针;而CDC类定义一个对象,

这个对象拥有HDC定义的一个设备描述表,同时也包

含与HDC相关的操作的函数。

这与HPEN和CPen,POINT与CPoint之间的差别是一样

的。

CDC 到HDC 的转化:

2007-05-09 12:04

方法一: 此方法在设备结束时不会销毁原来的资源(即:hDC,hBitmap)

CDC *pDC = CDC::FromHandle(hDC);

CBitmap *pBitmap = CBitmap::FromHandle(hBitmap);

方法二: 此方法在设备结束时会销毁原来的资源(即:hDC,hBitmap)

CDC dc;

dc.Attach(hDC);

CBitmap bit;

bit.Attach(hBitmap);

在结束的时候加dc.detach()也不会销毁原来资源

HDC hdc;

CDC cdc;

cdc到hdc

hdc = cdc.GetSafeHdc();

hdc到cdc

cdc.Attach(hdc);

回复于 2004-04-08 17:46:03 得分 20

HDC hdc;

CDC cdc;

cdc到hdc

hdc = cdc.GetSafeHdc();

hdc到cdc

cdc.Attach(hdc)

回复于 2004-04-08 17:49:14 得分 15

CDC 是MFC中的类

而HDC是Handle

使用

HDC GetDC()

回复于 2004-04-08 17:51:49 得分 0

CDC cdc;

HDC hDC = cdc.m_hDC

回复于 2004-04-08 17:54:20 得分 20

CDC dc;

HDC hDC = dc.m_hDC

dc.FromHandle(hDC);

回复于 2004-04-08 18:01:51 得分 10

CDC to hdc

用成员变量m_hDC

hdc to CDC

用FromHandle

回复于 2004-04-08 18:02:47 得分 10

dc.FromHandle(hDC)产生一个dc,但是是临时的,mfc不保证系统在什么时候删除dc.

dc.Attach(hDC)是永久的,直到这个dc的生命正常结束。

回复于 2004-04-08 18:05:21 得分 5

以上的都很对。你就查找替换。将所有的(hdc,替换为pdc->(当然。前面声明个

pdc就可以了。

HDC是句柄;CDC是MFC封装的Windows 设备相关的一个类;CClientDC是CDC的衍生类,产生对应于Windows客户区的对象

HDC是WINDOWS的一种数据类型,是设备描述句柄。

而CDC是MFC里的一个类,它封装了几乎所有的关于HDC的操作。

也可以这样说,HDC定义的变量指向一块内存,这块 内存用来描述一个设备的相关的内容,所以也可以 认为HDC定义的是一个指针;而CDC类定义一个对象, 这个对象拥有HDC定义的一个设备描述表,同时也包 含与HDC相关的操作的函数。

这与HPEN和CPen,POINT与CPoint之间的差别是一样的

CDC中有个成员变量m_hDC就是HDC类型的。从CDC中获得HDC只需使用GetSafeHdc()

CDC有几个有用的子类。CPaintDC、CClientDC、CWindowDC和CMetaFileDC。

1. CPaintDC是个循规导矩的类,一般用来响应WM_PAINT消息。"For drawing in a window’s client area(OnPaint handles only)"。

2. CClientDC是个不循规导矩的类,它会在OnPaint的外面创建一个客户区域DC,什么时候需要画图,已经等不及下一个WM_PAINT消息了,就调用此类,马上就可以画个图出来给你看。"For drawing in a window’s client area(anywhere but OnPaint)"。

3. CWindowDC这个类是可以在非客户区域(标题栏啊菜单栏啊啥的)进行绘图的类。会向系统发出WM_NCPAINT消息。"For drawing anywhere in a window, including the noclient area."

4. CMetaFileDC这个类主要是集中了一些GDI指令,可以用来使用并做一些绘制命令。metafile图元文件。

GetClientRect: 是将控件相对于客户区域的区域传给参数lpRect。

GetWindowRect: 获取的是控件相对整个屏幕(对,你是面前的这个)的区域。

函数功能:该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。

函数原型:HDC CreateCompatibleDC(HDC hdc);

参数:

hdc:现有设备上下文环境的句柄,如果该句柄为NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境。

返回值:如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。

CreateCompatibleDc函数只适用于支持光栅操作的设备,应用程序可以通过调用GetDeviceCaps函数来确定一个设备是否支持这些操作。

当不再需要内存设备上下文环境时,可调用DeleteDc函数删除它。

用双缓冲的话还要再定义一个位图对象吧,然后用CreateCompatibleBitmap建立一个与屏幕显示兼容的位图,再用SelectObject将位图选入到内存显示设备中,不知道是不是这样

首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:

CDC MemDC; //首先定义一个显示设备对象

CBitmap MemBitmap;//定义一个位图对象

//随后建立与屏幕显示兼容的内存显示设备

MemDC.CreateCompatibleDC(NULL);

//这时还不能绘图,因为没有地方画 ^_^

//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小,也可以自己定义(如:有滚动条时就要大于当前窗口的大小,在BitBlt时决定拷贝内存的哪部分到屏幕上)

MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);

//将位图选入到内存显示设备中

//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上

CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);

//先用背景色将位图清除干净,这里我用的是白色作为背景

//你也可以用自己应该用的颜色

MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));

//绘图

MemDC.MoveTo(……);

MemDC.LineTo(……);

//将内存中的图拷贝到屏幕上进行显示

pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);

//绘图完成后的清理

MemBitmap.DeleteObject();

MemDC.DeleteDC();

gdi在sdk应该是很重要的东西,不过嘛自己的水平实在是不怎么够品。长久以来一直都没有认识到 CreateCompatibleDC 的用途到底在这里,不过还好从知道这个东西数起的200天内,我终于还是晓得一些关于这个函数或者说内存dc存在的意义了。

在这种情况下,假如你要对屏幕进行比较多的gdi函数操作,如果每一步操作都直接对屏幕dc进行操作,那出现的大多数可能性都是屏幕的闪烁。一个很好的解决方法就是使用内存dc,将这些操作全部先在内存dc上操作,然后依次性在屏幕上进行操作。

例如:如果你单单使用bitblt在屏幕上拷贝一个图,那可以直接使用屏幕的dc。但是如果你要先设置背景(fillrect)然后再bitblt的话,这就涉及到两个屏幕dc的操作,这样的话屏幕很容易闪烁。

物理HDC 设备底层会拥有显存等资源,但是兼容DC并没有给图像像素提供内存空间,因此兼容DC总是和BITMAP配合使用,这样一来,兼容DC就利用BITMAP的图像像素数据空间给自己提供类似于显存的内存空间.

这样有很多好处,以来我们可以在加载图片后,在图片上利用DC的各种绘图功能.请看如下示例:

兼容DC在建立之初,只有1*1像素的尺寸,SelectObject选择bitmap以后才可以进行绘图.

内存DC的可见区域是简单的区域,不像物理DC可见区域可能被其他窗口覆盖而产生复杂的可见区域.由于DC的任何绘图都需要考虑在可见区域内绘图,绝对不能超出可见区域的范围.因此每个GDI绘图输出最终都需要和构成复杂可见区域的每一个巨型区域进行剪裁输出,因此物理DC的绘图效果会比兼容DC速度慢一些.这也就是我们经常用兼容DC进行双缓存输出的一个原因

HDC hdc=GetDC(hwnd);

HDC memdc=CreateCompatibleDC(hdc);

RECT rc;

BITMAP bmp;

HBITMAP holdbmp,hbmp=LoadBitmap(hInstDVBRes,MAKEINTRESOURCE(IDB_CLOCK));//从资源加载位图

holdbmp=(HBITMAP)SelectObject(memdc,hbmp);//这里把hbmp的位图选择到兼容DC memdc,之后这个兼容DC就拥有和

//hbmp同样大小的绘图区域,注意超出位图返回的GDI输出都是无效的.

GetObject(hbmp,sizeof(BITMAP),&bmp);//这里获取位图的大小信息,事实上也是兼容DC绘图输出的范围

SetRect(&rc,0,0,bmp.bmWidth,bmp.bmHeight);

DrawText(memdc,"Center Line Text" -1,&rc,DT_VCENTER|DT_SINGLELINE|DT_CENTER);//在兼容DC中间位置输出字符串

//这样以来我们就相当于把hbmp这个位图加上了文字标注,我们可以把这个增加了文字标注的位图保存起来.一个简单的图像处理基本就OK了.

SelectObject(memdc,holdbmp);//复原兼容DC数据.

DeleteDC(memdc);

//..........

我的理解:

CreateDC创建的是物理层的设备描述表。

兼容DC,也就是用HANDLE memdc = CreateCompatibleDC所创建的,它并有资源或者说是存储空间,所以就把BITMAP扯了进来,你在memdc区域绘图的时候,需要一个位图结构来存储这些数据。就是用SelectObject将hBitmap选入到memdc连联起来,将hBitmap作来memdc的存储空间。

下面的例子获得屏幕位图的例子:

HBITMAP CGetScreenView::GetScreenBitmap(RECT* rect)

{

HDC hScrDC, hMemDC;//屏幕设备描述表和内存设备描述表

HBITMAP hBitmap, hOldBitmap;//hBitmap位图句柄用来保存rect所对应的图片

hScrDC = ::GetDC(NULL);//创建屏幕设备描述表

hMemDC = CreateCompatibleDC(NULL);//创建内存设备描述表

int nWidth = GetDeviceCaps(hScrDC, HORZRES);

int nHeight = GetDeviceCaps(hScrDC, VERTRES);

hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);//创建一个与屏幕设备描述表兼容的位图

hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//把位图选进内存设备描述表

StretchBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, 0, 0, nWidth, nHeight, SRCCOPY);//将屏幕设备描述表的内容拷贝到内存设备描述表中,也就是将屏幕设备表的内容拷贝到了hBitmap中。也就把屏幕位图保存了下来。

hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);//把图片放到hBitmap中

::ReleaseDC(NULL, hScrDC);

DeleteDC(hMemDC);

return hBitmap;

}

这个流程之前不被理解的原因在于,HBITMAP不能从直接从屏幕设备描述表那里获得数据,它需要经过内存DC来将屏幕设备描述表中的数据读出来,并拷贝到HBITMAP中

大家都知道最简单的显示位图的步骤:1,创建位图对象 2.创建兼容DC 3.将位图对象选入兼容DC 4.在目的DC中显示位图

最初编写位图显示的小程序时一直比较纳闷为什么非得要创建兼容DC呢?以前在做绘制基本图形的程序时根本不用创建兼容DC,可以直接在OnDraw()函数內绘制就行了。现在终于弄明白了,原因就是使用兼容DC可以有效防止屏幕闪烁。

因为位图是点阵图像,所以对位图的显示都是一个点一个点依次绘制出来的,而MFC中对任何对象的都要经过屏幕刷新的过程,在这个过程中首先是OnPaint()隐含调用了OnEraseBkGnd()用白色填充背景,这是屏幕完全是白色,然后才是绘制对象,也就是说对于任何对象的显示都要进过这2个步骤,如果直接用目的DC显示位图的话,每一个像素点的显示过程中都有一个屏幕全白的过程,于是就造成了“图像——空白——图像——空白”如此往复循环的过程,这给人眼的视觉感受就是屏幕闪烁。

明白了闪烁的原因,那我们就很好理解兼容DC的作用了,这个兼容DC里的内容并不是直接输出到显示屏幕,而是将兼容DC里的位图(当然可以有其它对象)当做一个整体直接Copy到目的DC当中,这样在显示整个兼容DC的内容时相当于屏幕只刷新了一次,因为刷新时间特别短,人眼几乎无法分辨,所以就感觉不到有闪烁。

说到这里我们应该明白的是:是否使用兼容DC的决定因素不在于显示的对象是不是位图,关键因素是一次性直接由目的DC显示对象数量的多少来决定的,由于一般位图的像素点数都很多,所以位图全部采用兼容DC来绘制。由此可以猜想,那些专业的矢量图形绘制软件(例如CorelDRAW、Illustrator等),一定是采用兼容DC来做图形绘制的,因为一个页面可能同时存在很多矢量图形。

以上仅仅是个人的一点点想法,如果有不当之处,欢迎大家批评指正,在下感激不尽!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: