65.9K
CodeProject 正在变化。 阅读更多。
Home

关于无闪烁绘图的进一步讨论

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.59/5 (14投票s)

2003年5月24日

2分钟阅读

viewsIcon

205522

一篇关于如何解决闪烁问题的文章。

引言

本文旨在展示一些解决 CTreeCtrlCListCtrl 和 GDI+ 中闪烁问题的实用代码。它也可以看作是对 Keith Rule 的优秀文章“MFC 中的无闪烁绘制”的扩展。

背景

阅读 Keith Rule 的优秀文章是理解本文的前提。感谢他提供的优秀代码。我们将使用他提出的 CMemDC 类。

CTreeCtrl

对于一个 CTreeCtrl 派生类,如果想避免闪烁,可以执行以下步骤。

  • 将文件 memdc.h 添加到你的项目中。
  • 将行 #include "memdc.h" 添加到 stdafx.h 或所需的 .h 文件中。
  • 添加一个公共的 CRect 变量,例如 CRect m_rectClient;
  • 添加 WM_ERASEBKGNDWM_SIZEWM_PAINT 消息的处理程序。

然后应该添加以下代码

BOOL CTreeCtrl::OnEraseBkgnd(CDC* pDC) 
{
    // TODO: Add your message handler code here and/or call default
    UNUSED_ALWAYS(pDC);

    //return CTreeCtrl::OnEraseBkgnd(pDC);
    return TRUE;
}

void CTreeCtrl::OnSize(UINT nType, int cx, int cy) 
{
    CTreeCtrl::OnSize(nType, cx, cy);

    GetClientRect(m_rectClient);
}

void CTreeCtrl::OnPaint() 
{
    CPaintDC dc(this);

    // Paint to a memory device context to reduce screen flicker.
    CMemDC memDC(&dc, &m_rectClient);

    ......

    // Let the window do its default painting...
    CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
}

然后你就能获得无闪烁的效果。

CListCtrl

对于一个 CListCtrl 派生类,所有步骤都相同,除了 OnSize 函数应该修改如下,以允许在报告模式下显示 CHeadCtrl (如果存在)。

void CListCtrl::OnSize(UINT nType, int cx, int cy) 
{
    CListCtrl::OnSize(nType, cx, cy);

    GetClientRect(m_rectClient);

    CHeaderCtrl* pHC;
    pHC = GetHeaderCtrl();
    if (pHC != NULL)
    {
        CRect rectHeader;
        pHC->GetItemRect( 0, &rectHeader );
        m_rectClient.top += rectHeader.bottom;
    }
}

然后你就能获得无闪烁的效果。

GDI+

我发现了一些关于 GDI+ 中无闪烁绘制的文章。但是,我想扩展 Keith Rule 的代码来完成同样的工作,并避免使用 CachedBitmap 重新实现双缓冲机制。因此,我使用以下方法。

  • 将文件 memdc.h 添加到你的项目中。
  • 将行 #include "memdc.h" 添加到 stdafx.h 或所需的 .h 文件中。
  • 添加一个公共的 CRect 变量,例如CRect m_rectClient; 添加 WM_ERASEBKGNDWM_SIZEWM_PAINT 消息的处理程序。

然后应该添加以下代码

BOOL CView::OnEraseBkgnd(CDC* pDC) 
{
    // TODO: Add your message handler code here and/or call default
    UNUSED_ALWAYS(pDC);

    //return CView::OnEraseBkgnd(pDC);
    return TRUE;
}

void CView::OnSize(UINT nType, int cx, int cy) 
{
    CView::OnSize(nType, cx, cy);

    GetClientRect(m_rectClient);
}

void CView::OnPaint() 
{
    CPaintDC dc(this);

    // Paint to a memory device context to reduce screen flicker.
    CMemDC memDC(&dc, &m_rectClient);
    Graphics graphics(memDC);

    ......
}

然后你就能获得无闪烁的效果。这种方法在 CScrollView 中也能很好地工作。好的,最后,还有一个有趣的问题留给你:哪种方法会更快,这种方法还是由 CachedBitmap 实现的双缓冲?

历史

  • 初始发布日期:2003-05-24。
© . All rights reserved.