分享
 
 
 

使用CDC的四个派生类CClientDC,CPaintDC,CWindowDC,CMetaFileDC

王朝system·作者佚名  2006-08-04
窄屏简体版  字體: |||超大  

作者:ftkghost

[转载请注明出处:ftkghost.spaces.msn.com blog.csdn.net/ftkghost]

1.首先介绍一下什么是DC(设备描述表)

Windows应用程序通过为指定设备(屏幕,打印机等)创建一个设备描述表(Device Context, DC)在DC表示的逻辑意义的“画布”上进行图形的绘制。DC是一种包含设备信息的数据结构,它包含了物理设备所需的各种状态信息。Win32程序在绘制图形之前需要获取DC的句柄HDC,并在不继续使用时释放掉。

2.CDC及其派生类

CDC及其派生类的继承视图:

CObject

public |------CDC

public |------CClientDC

public |------CPaintDC

public |------CWindowDC

public |------CMetaFileDC

(注意: 除CMetaFileDC以外的三个派生类用于图形绘制.)

[以下几段是翻译MSDN中资料]

CDC类定义了一个设备描述表相关的类,其对象提供成员函数操作设备描述表进行工作,如显示器,打印机,以及显示器描述表相关的窗口客户区域。

通过CDC的成员函数可进行一切绘图操作。CDC提供成员函数进行设备描述表的基本操作,使用绘图工具, 选择类型安全的图形设备结构(GDI),以及色彩,调色板。除此之外还提供成员函数获取和设置绘图属性,映射,控制视口,窗体范围,转换坐标,区域操作,裁减,划线以及绘制简单图形(椭圆,多边形等)。成员函数也提供绘制文本,设置字体,打印机换码,滚动, 处理元文件。

通过CDC的成员函数可进行一切绘图操作。CDC提供成员函数进行设备描述表的基本操作,使用绘图工具, 选择类型安全的图形设备结构(GDI),以及色彩,调色板。除此之外还提供成员函数获取和设置绘图属性,映射,控制视口,窗体范围,转换坐标,区域操作,裁减,划线以及绘制简单图形(椭圆,多边形等)。成员函数也提供绘制文本,设置字体,打印机换码,滚动, 处理元文件。

其派生类:

PaintDC: 封装BeginPaint和EndPaint两个API的调用。

CClientDC: 处理显示器描述表的相关的窗体客户区域。

CWindowDC: 处理显示器描述表相关的整个窗体区域,包括了框架和控 件(子窗体)。

CMetaFileDC: 与元文件相关的设备描述表关联。

CDC提供两个函数,GetLayout和SetLayout用于反转设备描述表的布局。用于方便阿拉伯,希伯来的书写文化习惯的设计,以及非欧洲表中的字体布局。

CDC包含两个设备描述表,m_hDC和m_hAttribDC对应于相同的设备,CDC为m_hDC指定所有的输出GDI调用,大多数的GDI属性调用由m_hAttribDC控制。(如,GetTextColor是属性调用,而SetTextColor是一种输出调用。)

例子:框架使用这两个设备描述表,一个对象从物理设备中读取属性输出到元文件。打印机预览在框架中被执行时也是相同的形式。你也可以编写代码使用这两个设备描述表在你的应用程序中进行类似的操作。

3.使用方法

创建一个UseDC的MFC单文档程序,定制7个按钮用来选择使用的DC,每个按钮由一个成员变量标识控制[互斥],分别是

bool m_bHDCDisplay ---- 使用整个屏幕的HDC;

bool m_bHDC ---- 使用当前视图的对应的DC;

bool m_bCDC ---- 使用CDC类[当前视图窗体];

bool m_bCClientDC ---- 使用CClientDC类[视图客户区域DC];

bool m_bCPaintDC ---- 使用CPaintDC[视图窗体];

bool m_bCWindowDC ---- 使用CWindowDC[整个视图窗体];

bool m_bCMetaFileDC ---- 使用CMetaFileDC

添加7个按钮的响应函数以控制这些bool变量.(这里比较简单我就不提供代码了)

视图类构造函数:

CUseDCView::CUseDCView()

{

this->m_bHDCDisplay = false;

this->m_bHDC = false;

this->m_bCDC = false;

this->m_bCClientDC = false;

this->m_bCPaintDC = false;

this->m_bCWindowDC = false;

this->m_bCMetaFileDC = false;

m_hMetaFile = NULL;

}

视图类OnDraw函数

void CUseDCView::OnDraw(CDC* pDC)

{

CUseDCDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

//窗体在OnDraw中会自动传入关联当前视图窗体客户矩形区域的CPaintDC

//才能获取相应的设备描述表

HDC HDCDisplay = NULL; //屏幕DC的句柄 对应m_bHDCDisplay

HDC hDC = NULL; //普通DC的句柄 对应m_bHDC;

CDC * pCDC = NULL; //对应m_bCDC

CClientDC * pClientDC = NULL; //对应m_bCClientDC

CPaintDC * pPaintDC = NULL; //对应m_bCPaintDC

CWindowDC * pWindowDC = NULL; //对应m_bCWindowDC

CMetaFileDC * pMetaFileDC = NULL; //对应m_bMetaFileDC

HMETAFILE hMetaFile = NULL;

RECT rect; //定义一个设备左上角的矩形区域

rect.left = 0;

rect.top = 0;

rect.right = 200;

rect.bottom = 30;

//注意: HDCDisplay和hDC的::Release()中第一个参数HWND

//与GetDC()的第一个参数必须对应。

if(m_bHDCDisplay)

{

HDCDisplay = ::GetDC(NULL); //获得整个显示器区域的DC

::DrawText(HDCDisplay, "HDC of Display", 14, &rect, DT_LEFT|DT_TOP);

::ReleaseDC(NULL, HDCDisplay);

HDCDisplay = NULL;

}

if(m_bHDC) //绘制在客户区域

{

hDC = ::GetDC(this->m_hWnd); //本窗体的DC

::DrawText(hDC, "HDC", 3, &rect, DT_LEFT|DT_TOP);

::ReleaseDC(this->m_hWnd, hDC);

hDC = NULL;

}

else if(m_bCDC){

//必须释放由程序框架传入的pDC才能获取当前客户区域设备描述表

pCDC = this->GetDC(); //当前窗体(视图)的设备描述表

pCDC->DrawText("Use class CDC", 13, &rect, DT_LEFT|DT_TOP);

this->ReleaseDC(pCDC);

pCDC = NULL;

}

else if(m_bCClientDC){

pClientDC = new CClientDC(this); //获取本窗体客户区域的DC

pClientDC->DrawText("Use class CClientDC", &rect, DT_LEFT|DT_TOP);

delete pClientDC;

pClientDC = NULL;

}

else if(m_bCPaintDC) { //测试当前传入的CDC是不是CPaintDC

pPaintDC = (CPaintDC*)pDC;

pPaintDC->DrawText("Use class CPaintDC", &rect, DT_LEFT|DT_TOP);

}

else if(m_bCWindowDC){

pWindowDC = new CWindowDC(this); //获取本窗体框架和客户区域的DC

//注意:绘制字符串的矩形区域空白部分覆盖了视图子窗体的边缘.

pWindowDC->DrawText("Use class CWindowDC", &rect, DT_LEFT|DT_TOP);

delete pWindowDC;

pWindowDC = NULL;

}

else if(m_bCMetaFileDC){

//传入pDC->m_hDC使用pDC绘制,图形在视图窗体左上角

pMetaFileDC = new CMetaFileDC();

pMetaFileDC->m_hDC = pDC->m_hDC;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

delete pMetaFileDC;

pDC->PlayMetaFile(m_hMetaFile);

}

}

MFC程序中使用CPaintDC在视图窗口中绘制图象时要注意,应该在OnPaint()编写关于CPaintDC相关的代码,而不是在OnDraw()中.但是请注意,如果使用OnPaint()函数响应WM_PAINT事件,OnDraw函数将会被屏蔽;

可以使用以下代码测试:

在CUseDCView.h,CUseDCView的类定义中语句DECLARE_MESSAGE_MAP()之前加上afx_msg void OnPaint(),在CUseDCView.cpp中BEGIN_MESSAGE_MAP (CUseDCView, CView)和END_MESSAGE_MAP()之间加上ON_WM_PAINT()。

void CUseDCView::OnPaint()

{

CPaintDC dc(this);

RECT rect;

rect.left = 0;

rect.top = 0;

rect.right = 200;

rect.bottom = 30;

dc.Draw3dRect(&rect, (COLORREF)0xff0000, (COLORREF)0x0000ff);

}

使用CMetaFileDC

有兴趣可以在以下语句中可以尝试以下几种情况:

else if(m_bCMetaFileDC){

...

...

}

情况1:(与上面的OnDraw函数中相同)

//传入pDC->m_hDC使用pDC绘制,图形在视图窗体左上角

pMetaFileDC = new CMetaFileDC();

pMetaFileDC->m_hDC = pDC->m_hDC;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

delete pMetaFileDC;

pDC->PlayMetaFile(m_hMetaFile);

情况2:

//传入pDC->m_hDC使用屏幕DC绘制,图形在视图窗体左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = ::GetDC(NULL);

pMetaFileDC->m_hDC = pDC->m_hDC;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

delete pMetaFileDC;

::PlayMetaFile(hdc, m_hMetaFile);

::ReleaseDC(NULL, hdc);

情况3:

//传入屏幕DC,使用屏幕DC绘制,图像在屏幕左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = ::GetDC(NULL);

pMetaFileDC->m_hDC = hdc;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

delete pMetaFileDC;

::PlayMetaFile(hdc, m_hMetaFile);

::ReleaseDC(NULL, hdc);

情况4:

//传入屏幕DC,使用pDC绘制, 图像在屏幕左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = ::GetDC(NULL);

pMetaFileDC->m_hDC = hdc;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

delete pMetaFileDC;

pDC->PlayMetaFile(m_hMetaFile);

::ReleaseDC(NULL, hdc);

情况5:

//传入屏幕DC,使用pDC绘制,但是绘制前释放屏幕DC,

//没有出错,而且图像绘制在屏幕左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = ::GetDC(NULL);

pMetaFileDC->m_hDC = hdc;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

delete pMetaFileDC;

::ReleaseDC(NULL, hdc);

pDC->PlayMetaFile(m_hMetaFile);

情况6:

//传入屏幕pDC->hDC,使用CMetaFileDC绘制,图像在视图窗体左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = pDC->m_hDC;

pMetaFileDC->m_hDC = hdc;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

pMetaFileDC->PlayMetaFile(m_hMetaFile);

delete pMetaFileDC;

::ReleaseDC(NULL, hdc);

情况7:

//传入屏幕DC,使用CMetaFileDC绘制,图像在屏幕左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = ::GetDC(NULL);

pMetaFileDC->m_hDC = hdc;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

pMetaFileDC->PlayMetaFile(m_hMetaFile);

delete pMetaFileDC;

::ReleaseDC(NULL, hdc);

情况8:

//传入屏幕DC,使用CMetaFileDC绘制,绘图前释放hdc

//仍然没有出错,图像在屏幕左上角

HDC hdc;

pMetaFileDC = new CMetaFileDC();

hdc = ::GetDC(NULL);

pMetaFileDC->m_hDC = hdc;

pMetaFileDC->DrawText("Use class CMetaFileDC", &rect, DT_LEFT|DT_TOP);

pMetaFileDC->Draw3dRect(200, 0, 300, 30, (COLORREF)0xffff00, (COLORREF)0x0000ff);

m_hMetaFile = pMetaFileDC->Close();

::ReleaseDC(NULL, hdc);

pMetaFileDC->PlayMetaFile(m_hMetaFile);

delete pMetaFileDC;

由上面代码可见绘图的位置与传入CMetaFileDC::m_hDC的值有关。

使用CMetaFileDC需要注意:

使用CMetaFileDC对象调用一系列你想重复的CDC的GDI命令,只能使用CDC类中GDI输出命令。CDC的PlayMetaFile可以使用图元文件句柄来执行图元文件中的命令,图元文件也能使用CopyMetaFile使其存储在磁盘上。当不再需要图元文件时,调用DeleteMetaFile从内存中删除它。

以上代码都通过测试,有兴趣的朋友欢迎讨论,如果有错误和不足欢迎指出,需要测试源码的朋友可以留下邮箱,我看到后会尽快发给你。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有