DC,CDC和HDC理解

 MFC中的DC,CDC和HDC

       设备描述表(DC是Windows中的一种数据结构,它包含GDI需要的所有关于显示界面情况的描述字段,包括相连的物理设备和各种各样的状态信息。

        图形显示功能是由显卡来完成的,你想要利用显卡的图形显示功能来完成你的图形输出,怎么办,给你一块硬件能用吗?好,现在厂商给你提供一个驱动程序,给你一些调用的接口,你就可以访问了吧。但这种访问是在驱动层,很麻烦,更麻烦的是,每个厂商给自己显卡提供的驱动程序还不一样,那我们写的图形输出程序岂不是换台机器(不一样的显卡)就得修改,一个字:累,两个字:麻烦。现在一个救世主出现了,Bill兄,他让他的兄弟们在驱动之上实现一个抽象层,当然也可以认为是一个中间层的软件代码(我们管他叫设备上下文如何,也叫设备描述表DC),由这些代码和驱动打交道(当然,这些驱动得支持Windows平台)。然后,他将这种实现封装到动态链接库中提供给我们使用,我们能通过动态链接库暴露的API函数(相关概念见VC下半部分),得到一个这种实现(可以说是一种资源)的句柄,设备上下文的句柄(HDC),利用的这个句柄,就好像有了访问这中实现的钥匙了,以后就可以.......,剩下的参照VC上半部分的内容。

       设备描述表DC是一个定义一组图形对象及其属性、影响输出的数据结构。windows提供设备描述表,用于应用程序和物理设备之间进行交互,从而提供了应用程序设计的平台无关性。设备描述表又称为设备上下文,或者设备环境。 
  设备描述表是一种数据结构,它包括了一个设备(如显示器和打印机)的绘制属性相关的信息。所有的绘制操作通过设备描述表进行。设备描述表与大多WIN32结构不同,应用程序不能直接访问设备描述表,只能由各种相关API函数通过设备描述表的句柄(HDC)间接访问该结构。 
  设备描述表总是与某种系统硬件设备相关。比如屏幕设备描述表与显示设备相关,打印机设备描述表与打印设备相关等等。 
  屏幕设备描述表,一般我们简单地称其为设备描述表。它与显示设备具有一定的对应关系,在windows GDI界面下,它总是相关于某个窗口或这窗口上的某个显示区域。通常意义上窗口的设备描述表,一般指的是窗口的客户区,不包括标题栏、菜单栏所占有的区域,而对于整个窗口来说,其设备描述表严格意义上来讲应该称为窗口设备描述表,它包含窗口的全部显示区域。二者的操作方法完全一致,所不同的仅仅是可操作的范围不同而已。 

windows 窗口一旦创建,它就自动地产生了与之相对应的设备描述表数据结构,用户可运用该结构,实现对窗口显示区域的GDI操作,如划线、写文本、绘制位图、填充等,并且所有这些操作均要通过设备描述表句柄了进行。 

要说设备描述表就必须先说GDI(图形设备接口)。我们要在程序窗口上显示图形或文本等,就可以使用这些GDI函数在程序上“画画”、“写字”。设备描述表(DC)实际上是GDI内部保存的数据结构。设备描述表中的有些值是图形化的“属性”,这些属性定义了一些GDI函数工作的情况,如:文本颜色、图形填充的情况等。HDC是设备描述表句柄类型,句柄可以简单的理解为指针,被定义为32位的无符号整数。  

             以上内容转自:http://longzxr.blog.sohu.com/187934817.html

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

        在c++ 编程中常会见到HDC,CDC,CClientDC,CPaintDC,CWindowDC这样的类。

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

        CDC是MFC的DC的一个类。

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

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

      CObject
      public |------CDC
      public |------|------CClientDC
      public |------|------CPaintDC
      public |------|------CWindowDC
      public |------|------CMetaFileDC
      (
注意: 除CMetaFileDC以外的三个派生类用于图形绘制.)

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

表相关的窗口客户区域。

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

其派生类:

         1.CPaintDC:封装BeginPaint和EndPaint两个API的调用。
(1)用于响应窗口重绘消息(WM_PAINT)的绘图输出。
(2)CPaintDC在构造函数中调用BeginPaint()取得设备上下文,在析构函数中调用EndPaint()释放设备上下文。 EndPaint()除了释放设备上下文外,还负责从消息队列中清除WM_PAINT消息。因此,在处理窗口重画时,必须使用CPaintDC,否则 WM_PAINT消息无法从消息队列中清除,将引起不断的窗口重画。
(3)CPaintDC也只能用在WM_PAINT消息处理之中。
         2.CClientDC(客户区设备上下文): 处理显示器描述表的相关的窗体客户区域。

     构造时自动调用GetDC函数,析构时自动调用ReleaseDC函数.一般应用于客户区窗口的绘制。

     需要处理一个鼠标的单击,然后马上画出一个圆,你不能等到下一个WM_PAINT的消息到来才画图,而是马上,这是就需要CclientDC了。它可以在OnPaint的外面创建一个客户区域DC

    void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point)
    {
        CRect rect;
        GetClientRect (&rect);

        CClientDC dc (this);
        dc.MoveTo (rect.left, rect.top);
        dc.LineTo (rect.right, rect.bottom);
        dc.MoveTo (rect.right, rect.top);
        dc.LineTo (rect.left, rect.bottom);
    }


         3.CWindowDC: 处理显示器描述表相关的整个窗体区域,包括了框架和控 件(子窗体)。
(1)可在非客户区绘制图形,而CClientDC,CPaintDC只能在客户区绘制图形。
(2)坐标原点是在屏幕的左上角,CClientDC,CPaintDC下坐标原点是在客户区的左上角。
(3)关联一特定窗口,允许开发者在目标窗口的任何一部分进行绘图,包含边界与标题,这种DC同WM_NCPAINT消息一起发送。

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

 

下面说下一些细点的知识点
1、CClientDC,CWindowDC 
区别不大, 可以说 CWindowDC包含了CClientDC。 就拿记事本来说,CClientDC 就只是我们可以编辑文字的那个区域,是客户区,CWindowDC 除了上面说的区域, 还包括菜单栏和工具栏等。

2、CClientDC和CWindowDC与 CPaintDC 的区别大点,在DC的获取方面 CClientDC和CWindowDC 使用的是并只能是GetDC 和 ReleaseDC。CPaintDC 使用的是并只能是 BeginPaint 和 EndPaint。

3、CPaintDC只能用在响应 WM_PAINT 事件CClientDC,CWindowDC 只能用在响应非WM_PAINT 事件

4、关于 WM_PAINT事件
         系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由系统管理的,应用只是被动地接收该消息,在消息处理函数中进行绘制操作;大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和InvalidateRgn函数来完成的。InvalidateRect和 InvalidateRgn把指定的区域加到窗口的Update Region中,当应用的消息队列没有其他消息时,如果窗口的Update Region不为空时,系统就会自动产生WM_PAINT消息。

        系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽可能地推后做。不过这样也有利于提高绘制的效率:两个WM_PAINT消息之间通过 InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。像这种通过InvalidateRect和InvalidateRgn来使窗口区域无效,依赖于系统在合适的时机发送WM_PAINT消息的机制实际上是一种异步工作方式,也就是说,在无效化窗口区域和发送WM_PAINT消息之间是有延迟的;有时候这种延迟并不是我们希望的,这时我们当然可以在无效化窗口区域后利用SendMessage 发送一条WM_PAINT消息来强制立即重画,但不如使用Windows GDI为我们提供的更方便和强大的函数:UpdateWindow和RedrawWindow。UpdateWindow会检查窗口的Update Region,当其不为空时才发送WM_PAINT消息;RedrawWindow则给我们更多的控制:是否重画非客户区和背景,是否总是发送 WM_PAINT消息而不管Update Region是否为空等。
5、HDC和CDC相互转换:

(1)、HDC到CDC的转换:
方法一: 此方法在设备结束时不会销毁原来的资源(即:hDC,hBitmap)
CDC *pDC = CDC::FromHandle(hDC);

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

(2)、CDC到HDC的转换:

   CDC  dc;

   HDC  hDC;

   hDC dc.GetSafeHdc();

6、首先:CDC 不可以释放。 FromHandle 是通过 HDC 来创建了一个CDC 对象,以方便操作,释放 DC 的操作应该针对于HDC 而非此CDC , 如果释放了它   pDC->ReleaseDC,就会造成隐患。 
      HDC   hDC   =   GetDC(hWnd);  
      CDC   *pDC   =   CDC::FromHandle(hDC);   
      这两者是指向的一个DC对象,只能释放一次,而这个释放应该针对 hDC 而非 pDC。

      然后:GetDC和ReleaseDC的调用匹配,CreateDC和DeleteDC的调用匹配。GetDC是从窗口获取現有的DC,而CreateDC是创建DC,所以ReleaseDC和DeleteDC的作用一个是释放,一个是销毁。

<think> 首先,用户的问题是:"我想理解DCHDC这两个概念 请问如何理解DCHDC"。这基于之前的引用内容,这些引用是关于DC(设备上下文)、HDC(设备上下文句柄)CDCMFC类)的。 关键点从引用中提取: - DC(Device Context)是设备上下文,用于在Windows编程中绘制图形。 - HDCDC的句柄,是一种类似指针的数据类型,用于API中操作DC。 - CDCMFC中的类,包装了HDC,提供面向对象的接口。 - 引用[1]:CDCMFCDC类,HDC是句柄。CDC包含成员变量m_hDC,即HDC类型。 - 引用[2]:操作系统通过DC结构管理图形对象,如画笔、画刷等。应用程序通过函数间接操作DC。 - 引用[3]:CDC对象不应直接释放,而是通过释放HDC来管理资源。 - 引用[4]:示例代码使用HDC直接进行绘图操作。 用户可见层指令要求: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如[^1]。 系统级指令: - 所有行内数学表达式用$...$格式(但这个问题主要是概念性的,可能没有数学)。 - 独立公式用$$...$$格式单独成段(可能不适用)。 - LaTeX语法正确(如果需要)。 - 使用中文回答。 - 生成相关问题。 - 添加引用标识。 结构回答: 1. **解释DCHDC的基本概念**:从基础开始,定义DCHDC。 2. **详细说明区别关系**:基于引用,解释HDC是句柄,DC是概念,CDCMFC封装。 3. **使用示例或类比**:帮助理解。 4. **引用整合**:在相关部分添加引用。 5. **生成相关问题**:在最后部分。 内容大纲: - **第一部分:DC是什么?** - 设备上下文(DC)是Windows GDI中的核心概念,用于管理图形输出。它包含绘图所需的状态信息,如画笔、画刷、字体等[^2]。 - **第二部分:HDC是什么?** - HDC是设备上下文的句柄,是一个无符号整数值,用作API函数中引用DC的方式。它不是指针,但类似标识符[^1][^2]。 - **第三部分:DCHDC的关系** - DC是抽象概念,操作系统内部管理;HDC是应用程序操作DC的句柄。通过HDC,调用函数如LineTo或MoveToEx来绘图[^2][^4]。 - **第四部分:在MFC中的CDC类** - CDCMFC提供的类,封装了HDC,简化操作。例如,CClientDC dc(this);创建一个DC对象。CDC对象包含m_hDC成员,即HDC[^1][^3]。 - **第五部分:资源管理** - 使用HDC时,需要释放资源,如ReleaseDCCDC对象通常通过析构函数自动管理,但需注意不手动释放已关联HDCCDC对象[^3]。 生成相关问题: - 相关问题应基于内容,如DC的使用、常见函数、优化等。 确保回答真实可靠:基于提供的引用一般知识。 </think> ### 理解DCHDC的概念 在Windows图形编程中,DC(Device Context,设备上下文)HDC(Handle to Device Context,设备上下文句柄)是核心概念,尤其在GDI(Graphics Device Interface)MFC(Microsoft Foundation Classes)框架中。我将一步步解释它们的概念、关系区别,帮助您清晰理解。以下内容基于您提供的引用资料,并整合了相关知识以确保准确性。 #### 1. **DC(Device Context)是什么?** DC(设备上下文)是Windows操作系统用于管理图形输出的一个抽象层。它代表了绘图的目标设备(如屏幕、打印机或内存位图),并包含绘图所需的所有状态信息,包括: - 图形对象:如画笔(用于画线)、画刷(用于填充)、字体(用于文本)位图(用于图像)。 - 绘图属性:如背景颜色、映射模式(坐标系统)绘图模式[^2]。 操作系统通过DC结构统一管理这些资源,应用程序不能直接访问DC的内部结构,而是通过调用GDI函数间接操作它。例如,绘制一条线时需要先设置画笔属性,再调用绘图函数。DC的类型包括: - 显示设备DC(用于屏幕输出) - 打印DC(用于打印机) - 内存DC(用于位图操作) - 信息DC(用于查询设备属性)[^2]。 简言之,DC是“绘图环境”的封装,确保图形操作独立于具体硬件[^2]。 #### 2. **HDC(Handle to Device Context)是什么?** HDCDC的句柄(Handle),本质上是操作系统分配给DC的唯一标识符(类似于指针或ID)。在Windows API中: - HDC是一个无符号整数类型(如指针),用于在函数调用中引用某个DC实例。 - 应用程序通过获取HDC来操作DC,例如调用`GetDC`函数获取窗口的HDC,然后使用`LineTo`或`MoveToEx`绘图[^1][^4]。 关键点: - HDC不是DC本身,而是访问DC的“钥匙”。例如,在API编程中,您会先声明`HDC hdc;`,然后通过`hdc = GetDC(hWnd);`获取句柄,再进行绘图操作[^4]。 - 资源管理:使用HDC后必须手动释放资源,避免内存泄漏。例如,绘图结束后调用`ReleaseDC(hWnd, hdc);`释放句柄[^3][^4]。 HDC直接工作在底层API层,是高效但较原始的绘图方式[^1][^2]。 #### 3. **DCHDC的关系与区别** - **关系**:DC是概念上的绘图环境,HDC是操作它的句柄。每个DC都有一个对应的HDC,操作系统通过HDC管理DC的生命周期。例如,当您调用`GetDC`时,操作系统创建一个DC并返回其HDC给应用程序[^2]。 - **核心区别**: | 特性 | DC | HDC | |---------------|-----------------------------------|--------------------------------------| | **本质** | 抽象数据结构(操作系统内部管理) | 句柄(应用程序可见的操作标识) | | **访问方式** | 只能通过函数间接操作 | 直接在API函数中使用(如`MoveToEx`) | | **适用范围** | 通用概念,适用于所有Windows图形编程 | 主要用于API或MFC的底层交互 | | **资源管理** | 由操作系统自动管理 | 需手动获取释放(`GetDC`/`ReleaseDC`) | 简单类比:DC像一个“画布工作室”(包含画布、画笔等工具),HDC则是进入工作室的“门禁卡”。您用HDC刷卡进入,操作工具,完成后归还门禁卡[^1][^2]。 #### 4. **在MFC框架中的CDC类** 在MFC中,CDC(Class Device Context)是DC的面向对象封装。它简化了HDC的操作: - CDC类包含一个成员变量`m_hDC`(类型为HDC),直接关联底层句柄[^1]。 - 常用派生类如`CClientDC`(用于窗口客户区绘图),使用方式:`CClientDC dc(this);`,它会自动获取释放HDC。 - 优势:CDC自动管理资源(析构时释放HDC),减少了手动错误。但注意:不要直接释放从HDC创建的CDC对象(如`CDC::FromHandle`返回的指针),否则可能导致资源冲突[^3]。例如: ```cpp HDC hdc = GetDC(hWnd); // 获取HDC句柄 CDC* pDC = CDC::FromHandle(hdc); // 从HDC创建CDC指针 // 使用pDC绘图 ReleaseDC(hWnd, hdc); // 释放HDC,pDC会自动失效 ``` 这里,CDCHDC的高级包装,推荐在MFC项目中使用以提高代码可读性安全性[^1][^3]。 #### 5. **实际应用示例** - **纯API编程(使用HDC)**: ```cpp HDC hdc = GetDC(hWnd); // 获取窗口的HDC MoveToEx(hdc, startX, startY, NULL); // 移动绘图起点 LineTo(hdc, endX, endY); // 画线 ReleaseDC(hWnd, hdc); // 释放HDC[^4] ``` - **MFC编程(使用CDC)**: ```cpp CClientDC dc(this); // 自动创建关联HDCCDC对象 dc.MoveTo(startX, startY); // CDC封装的方法 dc.LineTo(endX, endY); // 自动管理资源,无需手动释放[^1] ``` 总结:DC是绘图环境的抽象概念,HDC是操作它的句柄(底层API),而CDCMFC为简化HDC操作提供的类。理解它们的关键在于区分层次:HDC是直接句柄,CDC是面向对象的封装[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值