我现在做的一个项目中涉及绘制地图的问题,有个定时刷新的问题,如每个0.5秒钟刷新一次。为了不出现界面绘制有延迟闪烁的问题,我使用了双缓冲来绘制,但是不到3个小时的时间就耗光堆栈了。我参照网上人家写的MemDC类,里面每次都要CreateCompatibelDC和DeleteDC,还有CreateCompatibleBitmap和DeleteObject。这样很恼火。请问大家尤其是做游戏开发的同志们是怎么解决这些问题的啊,能给点参考意见吗?代码:
OnPaint()
{
   CPaintDC dc(this);
   XMemDC MemDC(&dc);   // Paint function
   PaintImage(dc.m_hWnd);
}
下面是XMemDC的代码:class XMemDC
{
public:

    // Constructor sets up the memory DC
    XMemDC(CWnd* pWnd)
    {
        ASSERT(pWnd != NULL);

BOOL bResult = FALSE;

m_pWnd   = pWnd;
        m_hOldDC = ::GetDC(pWnd->GetSafeHwnd());
        m_pOldBitmap = NULL;
m_hDC = NULL; ASSERT(m_hOldDC);

        ::GetClipBox(m_hOldDC, &m_rect);

        m_hDC = CreateCompatibleDC(m_hOldDC);
ASSERT(m_hDC != NULL);
        m_bitmap = CreateCompatibleBitmap(m_hOldDC, m_rect.right - m_rect.left, 
m_rect.bottom - m_rect.top);
ASSERT(m_bitmap != NULL);
        m_pOldBitmap = (HBITMAP)::SelectObject(m_hDC, m_bitmap);

// #ifndef _WIN32_WCE
//   ::SetWindowOrg(m_hDC, m_rect.left, m_rect.top);
// #endif
        // EFW - Bug fix - Fill background in case the user has overridden
        // WM_ERASEBKGND.  We end up with garbage otherwise.
        // CJM - moved to fix a bug in the fix.
        FillSolidRect(&m_rect, ::GetBkColor(m_hOldDC));
    } XMemDC(HDC hSrcDC)
    {
BOOL bResult = FALSE;        ASSERT(hSrcDC != NULL);

m_pWnd   = NULL;
        m_hOldDC = hSrcDC;
        m_pOldBitmap = NULL;
m_hDC = NULL;

ASSERT(m_hOldDC);

        ::GetClipBox(m_hOldDC, &m_rect);

        m_hDC = CreateCompatibleDC(m_hOldDC);
ASSERT(m_hDC != NULL);
        m_bitmap = CreateCompatibleBitmap(m_hOldDC, m_rect.right - m_rect.left, 
m_rect.bottom - m_rect.top);
ASSERT(m_bitmap != NULL);
        m_pOldBitmap = (HBITMAP)::SelectObject(m_hDC, m_bitmap);

// #ifndef _WIN32_WCE
//  ::SetWindowOrg(m_hDC, m_rect.left, m_rect.top);
// #endif
        // EFW - Bug fix - Fill background in case the user has overridden
        // WM_ERASEBKGND.  We end up with garbage otherwise.
        // CJM - moved to fix a bug in the fix.
        FillSolidRect(&m_rect, ::GetBkColor(m_hOldDC));
    }

    // Destructor copies the contents of the mem DC to the original DC
    ~XMemDC()
    {
        // Copy the offscreen bitmap onto the screen.
        BitBlt(m_hOldDC, m_rect.left, m_rect.top, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top,
m_hDC, m_rect.left, m_rect.top, SRCCOPY);

        //Swap back the original bitmap.
        ::SelectObject(m_hDC, m_pOldBitmap); // Delete m_bitmap
::DeleteObject(m_bitmap); m_bitmap = NULL; // Delete DC
DeleteDC(m_hDC); m_hDC = NULL; if (m_pWnd)
{
int iRet = ::ReleaseDC(m_pWnd->GetSafeHwnd(), m_hOldDC);
ASSERT(iRet != 0);
}

m_hOldDC = NULL;
    }

HDC GetSafeHdc() { return m_hDC; } void FillSolidRect(RECT* pRect, COLORREF color)
{
HBRUSH hBrush = ::CreateSolidBrush(color); ::FillRect(m_hDC, pRect, hBrush);
::DeleteObject(hBrush); hBrush = NULL;
}

private:
HBITMAP  m_bitmap;      // Offscreen bitmap
    HBITMAP  m_pOldBitmap;  // bitmap originally found in CMemDC
    HDC  m_hOldDC;      // Saves DC passed in constructor
    RECT     m_rect;        // Rectangle of drawing area.
HDC      m_hDC;
CWnd*    m_pWnd;
};

解决方案 »

  1.   

    但问题是:(1) 比如 GetDC返回的DC能保存下来吗,查看MSDN当中每次调用GetDC获取到Wnd的DC,绘制完之后要使用ReleaseDC,这样才能绘制到设备上去,这样保存DC能行吗?还有BeginPaint 和 EndPaint也是一样,绘制的工作也只能在这两个之间啊。
      

  2.   

    我查看过MFC中 CClientDC, CPaintDC, CDC的源代码,里面都是有许多会将dc存到afxMap里面,估计是MFC未来加快速度吧,我现在也是这么做的,将load到内存的资源的索引放到map中了。
      

  3.   

    OnPaint()
    {
       CPaintDC dc(this);
       XMemDC MemDC(&dc);   // Paint function
       PaintImage(dc.m_hWnd);
    }
    你这里根本没有用到MemDC进行绘制啊。另外,你的问题可能出在绘制代码上没有释放GDI资源或者其他地方的内存泄漏。
      

  4.   

    实在是不好意思,上面的是我写错例子,实际例子是:
       if (::IsWindow(m_hWnd))
       {
       PAINTSTRUCT ps;
       HDC hPaintDC = ::BeginPaint(m_hWnd, &ps);
      
       if (hPaintDC)
       {
       XMemDC MemDC(hPaintDC);
       Paint(MemDC.GetSafeHdc());
       }
      
       ::EndPaint(m_hWnd, &ps);
       }
      

  5.   

    我有写了一个新的类,是在Wnd初始化及Create完成之后初始化DC然后就不必每次绘制创建DC,但很遗憾的是绘制不出东东,显示不出来。代码如下,看各位能否给点意见,我现在只能去用API测试了。#ifndef _XATTACHDC_H
    #define _XATTACHDC_Hclass XStabMemDC
    {
    public:
    XStabMemDC(CWnd* pWnd)
    {
    ASSERT(pWnd != NULL); // Zero memory values first at the beginning.
    _pCltDC  = NULL;
    _hDC     = NULL;
    _hBitmap = NULL;
    _hOldMap = NULL;
    ::SetRect(&_rtRender, 0, 0, 0, 0); pWnd->GetClientRect(&_rtRender); _pCltDC = new CClientDC(pWnd);
    ASSERT(_pCltDC != NULL); if (!_hDC && !_hBitmap && !_hOldMap)
    {
    _hDC = ::CreateCompatibleDC(_pCltDC->m_hDC);
    ASSERT(_hDC != NULL); _hBitmap = ::CreateCompatibleBitmap(_pCltDC->m_hDC,
    _rtRender.right - _rtRender.left, _rtRender.bottom - _rtRender.top);
    ASSERT(_hBitmap != NULL); _hOldMap = (HBITMAP)::SelectObject(_hDC, _hBitmap);
    }
    } ~XStabMemDC()
    {
    if (_hDC && _hBitmap && _hOldMap)
    {
    ::SelectObject(_hDC, _hOldMap); _hOldMap = NULL;
    ::DeleteObject(_hBitmap); _hBitmap = NULL;
    ::DeleteDC(_hDC); _hDC = NULL;
    } if (_pCltDC)
    {
    delete _pCltDC; _pCltDC = NULL;
    }
    } BOOL Export()
    {
    if (_pCltDC->m_hDC && _hDC)
    {
    return ::BitBlt(_pCltDC->m_hDC, _rtRender.left, _rtRender.top, 
    _rtRender.right - _rtRender.left, _rtRender.bottom - _rtRender.top,
    _hDC, _rtRender.left, _rtRender.top, SRCCOPY);
    } return FALSE;
    } HDC  GetSafeHdc()
    {
    return _hDC;
    }private:
    CClientDC* _pCltDC; // Screen device.
    HDC _hDC; // Memory device.
    HBITMAP _hBitmap; // Memory device selected bitmap.
    HBITMAP _hOldMap; // the old bitmap that select from _hDC. RECT _rtRender; // The rendering rectangle.
    };#endif//_XATTACHDC_H
    使用方法:在窗口创建时,将XStabMemDC*  _pStabDC = NULL; // 类成员..._pStabDC = new XStabMemDC(this);
    void OnPaint()
    {
       Paint(_pStabDC.GetSageHdc());
       _pStabDC->Export();
    }
      

  6.   

    是你没把代码写好,肯定可以的,医疗监护软件不间断画图,咱也是用的双缓冲,不会出现你说的情况,堆栈累加说明你的代码有问题,不就是创建一张位图,然后在位图中画东西后,再用窗体dc.BitBlt一下么,没那么复杂吧