Winapi 将位图图像绘制到窗口中的正确方法

Winapi 将位图图像绘制到窗口中的正确方法,winapi,mfc,gdi,stretchblt,setwindowpos,Winapi,Mfc,Gdi,Stretchblt,Setwindowpos,我有一个函数,它获取位图图像的矩形区域,将其重新缩放到不同的尺寸,并在我的对话框应用程序的窗口内的某个偏移处绘制它: void DrawImage(HANDLE hImageBitmap, CDC* pDstDC,const CRect& dstRect, CDC* pSrcDC,const CRect& srcRect) { pSrcDC->SelectObject(hImageBitmap);

我有一个函数,它获取位图图像的矩形区域,将其重新缩放到不同的尺寸,并在我的对话框应用程序的窗口内的某个偏移处绘制它:

void DrawImage(HANDLE hImageBitmap,
               CDC* pDstDC,const CRect& dstRect,
               CDC* pSrcDC,const CRect& srcRect)
{
    pSrcDC->SelectObject(hImageBitmap);
    pDstDC->SetStretchBltMode(HALFTONE);
    pDstDC->StretchBlt
    (
        dstRect.left,dstRect.top,dstRect.Width(),dstRect.Height(),pSrcDC,
        srcRect.left,srcRect.top,srcRect.Width(),srcRect.Height(),SRCCOPY
    );
}
我使用
CWnd m_cImageWindow
成员变量创建和维护窗口

我从对话框的
OnPaint
处理程序执行绘图,如下所示:

CDC* pDC = m_cImageWindow.GetDC();
CDC  cDC;
cDC.CreateCompatibleDC(pDC);

CRect srcRect = ...;
CRect dstRect = ...;
DrawImage(m_hImageBitmap,pDC,dstRect,&cDC,srcRect);

cDC.DeleteDC();
m_cImageWindow.ReleaseDC(pDC);
我有两个问题:

  • 每当更改图形参数时,我都会看到闪烁。根据我在这里和那里读到的内容,解决这个问题的标准方法是使用临时DC进行双缓冲。但据我所知,这正是我正在做的

  • 如果某些目标区域位于窗口之外,则它将绘制在对话框中的其他控件上。我可以通过为每个控件调用
    MoveWindow
    SetWindowPos
    部分解决此问题。但我仍然可以看到他们身后的图像在闪烁。我尝试过以各种不同的方式调用
    SetWindowPos
    ,希望它能规定控件的严格Z顺序,但徒劳


  • 谢谢。

    我发现OnEraseBkgnd是减少绘制位图闪烁的正确位置

  • 将图像绘制到子窗口中应该在该子窗口的WM_绘制处理程序中完成,而不是在对话框中完成。子窗口可能需要记住父对话框提供的信息,以便可以独立绘制。通过从对话框的WM_绘制处理程序绘制窗口,您可能绘制的次数超过了需要的次数(并且可能不会导致在图像窗口中进行验证)

  • 对话框应该有WS_CLIPCHILDREN窗口样式,图像窗口应该有WS_ClipShildren窗口样式。这将防止对话框控件相互重叠,并通过允许更少量的更新来减少闪烁

  • 如果图像始终完全覆盖整个图像窗口,则需要确保图像窗口没有发生背景擦除,因为这可能会导致背景颜色闪烁,看起来像绘画。有几种方法可以做到这一点,但最简单的可能是提供一个仅返回TRUE的WM_ERASEBKGND处理程序


  • OnPaint
    事件处理程序不应创建自己的DC来进行绘制。您应该使用
    CPaintDC
    类。@CodyGray:谢谢。我试过了,但似乎对我不起作用。可能是因为我创建的绘制DC属于对话框本身,而不是我试图在其中绘制的窗口。您能否提供一些更具体的证据来说明“
    OnPaint
    事件处理程序不应该创建自己的DC”的原因?谢谢。嗯……你为什么要处理一个窗口(对话框)的绘制事件,并尝试在另一个窗口上绘制?如果要在窗口上绘制,请处理该窗口的绘制事件。
    OnPaint
    处理程序不应创建自己的DC的具体证据:该DC从不验证无效区域,保留一个
    WM_paint
    消息流。(
    CPaintDC
    验证其目录中的无效区域。)那么为什么不直接在对话框上绘制呢?使用
    WS\u CLIPCHILDREN
    避免在其他控件上绘画。谢谢。图像没有覆盖整个图像窗口,因此我无法覆盖
    OnEraseBkgnd
    回调并返回TRUE。您可以让绘制处理程序仔细擦除窗口的未覆盖区域,然后跳过WM_ERASEBKGND。这可以通过避免两次绘制像素来防止一些闪光。不过,在现代桌面合成系统中,您可能甚至没有注意到flash。