Windows GDI:CDC使用总结

一、DC函数的配对使用

GetDC — ReleaseDC
GetWindowDC — ReleaseDC
CreateDC — DeleteDC

二、GetDC与GetWindowDC

1、HDC GetDC(HWND hWnd)
int ReleaseDC(HWND hWnd,
HDC hDC);

2、HDC GetWindowDC(HWND hWnd);
int ReleaseDC(HWND hWnd,
HDC hDC);

通过GetDC与GetWindowDC获取HDC,使用完毕之后均需ReleaseDC,否则会有资源泄露
GetDC与GetWindowDC的区别是:
GetDC获取的是客户区的DC
GetWindowDC获取的是the device context (DC) for the entire window,包括非客户区

怎样获取整个屏幕的DC?
GetDC(NULL)
GetWindowDC(NULL)

二、CDC

CDC:

class CDC : public CObject
{
public:
HDC m_hDC;
public:
BOOL Attach(HDC hDC);
HDC Detach();

static CDC* PASCAL FromHandle(HDC hDC);
static void PASCAL DeleteTempMap();
}

1、先看一下析构函数

CDC::~CDC()
{
if (m_hDC != NULL)
::DeleteDC(Detach());
}

很显然,在析构函数中先Detach()了,再DeleteDC了

2、再看一下Attach与Detach

Attach在于将HDC与CDC的对象关联起来,并且在Map表中创建一条记录

BOOL CDC::Attach(HDC hDC)
{
    if (hDC == NULL)
    {
        return FALSE;
    }

    m_hDC = hDC;
    CHandleMap* pMap = afxMapHDC(TRUE); // create map if not exist
    pMap->SetPermanent(m_hDC, this);

    return TRUE;
}

Detach在于将HDC与CDC的对象去除关联,当然会在Map表中删除这条记录

HDC CDC::Detach()
{
    HDC hDC = m_hDC;
    if (hDC != NULL)
    {
        CHandleMap* pMap = afxMapHDC(); // don't create if not exist
        if (pMap != NULL)
            pMap->RemoveHandle(m_hDC);
    }

    m_hDC = NULL;
    return hDC;
}

3、CDC* FromHandle(HDC hDC)

在CDC<>HDC的Map表中查找hDC对应的CDC

CDC* PASCAL CDC::FromHandle(HDC hDC)
{
    CHandleMap* pMap = afxMapHDC(TRUE); //create map if not exist
    CDC* pDC = (CDC*)pMap-&gt;FromHandle(hDC);
    return pDC;
}

Note:如果在CDC<>HDC的Map表中没有找到hDC相关的记录,系统会创建一个临时的CDC.
此时,不用我们delete了,系统会用空闲线程处理.不必深究,知道就可以了.
由于CDC的析构函数调用的是DeleteDC,所以CDC一般用来接收CreateDC得到的HDC.
或者也可以这样用,先Attach不是用CreateDC获取的HDC,再Detach,这样就不会DeleteDC了.
CClientDC的析构函数调用的是ReleaseDC
CPaintDC的析构函数调用的是EndPaint

4、DeleteTempMap

Called automatically by the CWinApp idle-time handler, DeleteTempMap deletes any temporary CDC objects created by FromHandle,
but does not destroy the device context handles (hDCs) temporarily associated with the CDC objects.

5、CDC::SelectObject()

CPen* SelectObject(
    CPen* pPen
);
CBrush* SelectObject(
    CBrush* pBrush
);
...
CPen* CDC::SelectObject(CPen* pPen)
{
    HGDIOBJ hOldObj = NULL;

    if (m_hDC != m_hAttribDC)
    hOldObj = ::SelectObject(m_hDC, pPen-&gt;GetSafeHandle());
    if (m_hAttribDC != NULL)
        hOldObj = ::SelectObject(m_hAttribDC, pPen-&gt;GetSafeHandle());
    return (CPen*)CGdiObject::FromHandle(hOldObj);
}

SelectObject返回的CPen*为CGdiObject::FromHandle获取的
假若这里通过CGdiObject::FromHandle得到的是临时创建的CPen*
由于CGdiObject::DeleteTempMap也不会DeleteObject掉临时CGdiObject关联的HGDIOBJECT
所以,这种机制才保证了代码的正确性:

CDC dc;
dc.CreateDC(...)
CPen pen;
pen.CreatePen(...)
CPen* pOldPen = dc.SelectObject(&amp;pen);
...
dc.SelectObject(pOldPen);

三、CClientDC

CClientDC:

class CClientDC : public CDC
{
protected:
    HWND m_hWnd;
}

1、先看一下构造与析构函数

CClientDC::CClientDC(CWnd* pWnd)
{
    Attach(::GetDC(m_hWnd = pWnd-&gt;GetSafeHwnd()));
}
CClientDC::~CClientDC()
{
    ::ReleaseDC(m_hWnd, Detach());
}

2、CClientDC在MFC对话框中的常用用法

CCientDC dc(this);
dc.执行操作

四、CPaintDC

CPaintDC:

class CPaintDC : public CDC
{
protected:
    HWND m_hWnd;
}

1、先看一下构造与析构函数

CPaintDC::CPaintDC(CWnd* pWnd)
{
    Attach(::BeginPaint(m_hWnd = pWnd-&gt;m_hWnd, &amp;m_ps));
}
CPaintDC::~CPaintDC()
{
    ::EndPaint(m_hWnd, &amp;m_ps);
    Detach();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值