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

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变量.(这里比较简单我就不提供代码了)

视图类构造函数: 

None.gif CUseDCView::CUseDCView() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
InBlock.gif  
this->m_bHDCDisplay = false;
InBlock.gif  
this->m_bHDC = false
InBlock.gif  
this->m_bCDC = false
InBlock.gif  
this->m_bCClientDC = false
InBlock.gif  
this->m_bCPaintDC = false;
InBlock.gif  
this->m_bCWindowDC = false
InBlock.gif  
this->m_bCMetaFileDC = false;
InBlock.gif  m_hMetaFile 
= NULL; 
ExpandedBlockEnd.gif}
 
None.gif

视图类OnDraw函数

 

None.gif void  CUseDCView::OnDraw(CDC *  pDC) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CUseDCDoc
* pDoc = GetDocument();
InBlock.gif    ASSERT_VALID(pDoc); 
InBlock.gif    
InBlock.gif    
//窗体在OnDraw中会自动传入关联当前视图窗体客户矩形区域的CPaintDC
InBlock.gif    
//才能获取相应的设备描述表 
InBlock.gif
    
InBlock.gif    HDC HDCDisplay 
= NULL; //屏幕DC的句柄 对应m_bHDCDisplay
InBlock.gif
    HDC hDC = NULL; //普通DC的句柄 对应m_bHDC;
InBlock.gif
    CDC * pCDC = NULL; //对应m_bCDC
InBlock.gif
    CClientDC * pClientDC = NULL; //对应m_bCClientDC
InBlock.gif
    CPaintDC * pPaintDC = NULL; //对应m_bCPaintDC 
InBlock.gif
    CWindowDC * pWindowDC = NULL; //对应m_bCWindowDC 
InBlock.gif
    CMetaFileDC * pMetaFileDC = NULL; //对应m_bMetaFileDC 
InBlock.gif
    
InBlock.gif    HMETAFILE hMetaFile 
= NULL;
InBlock.gif    
<!--[if !supportLineBreakNewLine]-->
InBlock.gif    
<!--[endif]--> 
InBlock.gif        
InBlock.gif        RECT rect; 
//定义一个设备左上角的矩形区域
InBlock.gif
    rect.left = 0;
InBlock.gif    rect.top 
= 0;
InBlock.gif    rect.right 
= 200;
InBlock.gif    rect.bottom 
= 30
InBlock.gif    
InBlock.gif    
//注意: HDCDisplay和hDC的::Release()中第一个参数HWND
InBlock.gif    
//与GetDC()的第一个参数必须对应。
InBlock.gif
    if(m_bHDCDisplay)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        HDCDisplay 
= ::GetDC(NULL); //获得整个显示器区域的DC
InBlock.gif
        ::DrawText(HDCDisplay, "HDC of Display"14&rect, DT_LEFT|DT_TOP);
InBlock.gif        ::ReleaseDC(NULL, HDCDisplay);
InBlock.gif        HDCDisplay 
= NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
if(m_bHDC) //绘制在客户区域
ExpandedSubBlockStart.gifContractedSubBlock.gif
    dot.gif{
InBlock.gif        hDC 
= ::GetDC(this->m_hWnd); //本窗体的DC
InBlock.gif
        ::DrawText(hDC, "HDC"3&rect, DT_LEFT|DT_TOP);
InBlock.gif        ::ReleaseDC(
this->m_hWnd, hDC);
InBlock.gif        hDC 
= NULL;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
else if(m_bCDC)dot.gif{
InBlock.gif        
//必须释放由程序框架传入的pDC才能获取当前客户区域设备描述表
InBlock.gif
        pCDC = this->GetDC(); //当前窗体(视图)的设备描述表
InBlock.gif
        pCDC->DrawText("Use class CDC"13&rect, DT_LEFT|DT_TOP);
InBlock.gif        
this->ReleaseDC(pCDC);
InBlock.gif        pCDC 
= NULL;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
else if(m_bCClientDC)dot.gif{
InBlock.gif        pClientDC 
= new CClientDC(this); //获取本窗体客户区域的DC
InBlock.gif
        pClientDC->DrawText("Use class CClientDC"&rect, DT_LEFT|DT_TOP);
InBlock.gif        delete pClientDC;
InBlock.gif        pClientDC 
= NULL;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
else if(m_bCPaintDC) dot.gif//测试当前传入的CDC是不是CPaintDC
InBlock.gif
        pPaintDC = (CPaintDC*)pDC;
InBlock.gif        pPaintDC
->DrawText("Use class CPaintDC"&rect, DT_LEFT|DT_TOP);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
else if(m_bCWindowDC)dot.gif{
InBlock.gif        pWindowDC 
= new CWindowDC(this); //获取本窗体框架和客户区域的DC
InBlock.gif        
//注意:绘制字符串的矩形区域空白部分覆盖了视图子窗体的边缘.
InBlock.gif
        pWindowDC->DrawText("Use class CWindowDC"&rect, DT_LEFT|DT_TOP);
InBlock.gif        delete pWindowDC;
InBlock.gif        pWindowDC 
= NULL;
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockStart.gifContractedSubBlock.gif    
else if(m_bCMetaFileDC)dot.gif{
InBlock.gif        
//传入pDC->m_hDC使用pDC绘制,图形在视图窗体左上角
InBlock.gif
        pMetaFileDC = new CMetaFileDC();
InBlock.gif        pMetaFileDC
->m_hDC = pDC->m_hDC;
InBlock.gif        pMetaFileDC
->DrawText("Use class CMetaFileDC"&rect, DT_LEFT|DT_TOP);
InBlock.gif        pMetaFileDC
->Draw3dRect(200030030, (COLORREF)0xffff00, (COLORREF)0x0000ff);
InBlock.gif        m_hMetaFile 
= pMetaFileDC->Close(); 
InBlock.gif        delete pMetaFileDC;
InBlock.gif        pDC
->PlayMetaFile(m_hMetaFile);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


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()。

None.gif void  CUseDCView::OnPaint() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CPaintDC dc(
this); 
InBlock.gif    RECT rect; 
InBlock.gif    rect.left 
= 0;
InBlock.gif    rect.top 
= 0;
InBlock.gif    rect.right 
= 200;
InBlock.gif    rect.bottom 
= 30;
InBlock.gif    dc.Draw3dRect(
&rect, (COLORREF)0xff0000, (COLORREF)0x0000ff);
ExpandedBlockEnd.gif}

None.gif

使用CMetaFileDC

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

else if(m_bCMetaFileDC){

...
...

}

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

None.gif // 传入pDC->m_hDC使用pDC绘制,图形在视图窗体左上角
None.gif
pMetaFileDC  =   new  CMetaFileDC();
None.gifpMetaFileDC
-> m_hDC  =  pDC -> m_hDC;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close();
None.gifdelete pMetaFileDC;
None.gifpDC
-> PlayMetaFile(m_hMetaFile); 

情况2:

None.gif // 传入pDC->m_hDC使用屏幕DC绘制,图形在视图窗体左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  ::GetDC(NULL);
None.gifpMetaFileDC
-> m_hDC  =  pDC -> m_hDC;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gifdelete pMetaFileDC;
None.gif::PlayMetaFile(hdc, m_hMetaFile);
None.gif::ReleaseDC(NULL, hdc); 

情况3:

None.gif // 传入屏幕DC,使用屏幕DC绘制,图像在屏幕左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  ::GetDC(NULL);
None.gifpMetaFileDC
-> m_hDC  =  hdc;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gifdelete pMetaFileDC;
None.gif::PlayMetaFile(hdc, m_hMetaFile);
None.gif::ReleaseDC(NULL, hdc); 

情况4:

None.gif // 传入屏幕DC,使用pDC绘制, 图像在屏幕左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  ::GetDC(NULL);
None.gifpMetaFileDC
-> m_hDC  =  hdc;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gifdelete pMetaFileDC;
None.gifpDC
-> PlayMetaFile(m_hMetaFile);
None.gif::ReleaseDC(NULL, hdc); 

情况5:

None.gif // 传入屏幕DC,使用pDC绘制,但是绘制前释放屏幕DC,
None.gif
// 没有出错,而且图像绘制在屏幕左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  ::GetDC(NULL);
None.gifpMetaFileDC
-> m_hDC  =  hdc;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gifdelete pMetaFileDC;
None.gif::ReleaseDC(NULL, hdc); 
None.gifpDC
-> PlayMetaFile(m_hMetaFile); 

情况6:

None.gif // 传入屏幕pDC->hDC,使用CMetaFileDC绘制,图像在视图窗体左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  pDC -> m_hDC;
None.gifpMetaFileDC
-> m_hDC  =  hdc;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gifpMetaFileDC
-> PlayMetaFile(m_hMetaFile);
None.gifdelete pMetaFileDC;
None.gif::ReleaseDC(NULL, hdc); 

情况7:

None.gif // 传入屏幕DC,使用CMetaFileDC绘制,图像在屏幕左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  ::GetDC(NULL);
None.gifpMetaFileDC
-> m_hDC  =  hdc;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gifpMetaFileDC
-> PlayMetaFile(m_hMetaFile);
None.gifdelete pMetaFileDC;
None.gif::ReleaseDC(NULL, hdc); 

情况8:

None.gif // 传入屏幕DC,使用CMetaFileDC绘制,绘图前释放hdc
None.gif
// 仍然没有出错,图像在屏幕左上角
None.gif
HDC hdc;
None.gifpMetaFileDC 
=   new  CMetaFileDC();
None.gifhdc 
=  ::GetDC(NULL);
None.gifpMetaFileDC
-> m_hDC  =  hdc;
None.gifpMetaFileDC
-> DrawText( " Use class CMetaFileDC " & rect, DT_LEFT | DT_TOP);
None.gifpMetaFileDC
-> Draw3dRect( 200 0 300 30 , (COLORREF) 0xffff00 , (COLORREF) 0x0000ff );
None.gifm_hMetaFile 
=  pMetaFileDC -> Close(); 
None.gif::ReleaseDC(NULL, hdc);
None.gifpMetaFileDC
-> PlayMetaFile(m_hMetaFile);
None.gifdelete pMetaFileDC; 

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

使用CMetaFileDC需要注意:

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

转载于:https://www.cnblogs.com/aoyihuashao/archive/2009/12/23/1630463.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值