【问题标题】:The correct method for drawing a bitmap image into a window将位图图像绘制到窗口中的正确方法
【发布时间】:2017-10-29 19:59:21
【问题描述】:

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

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);

我有两个问题:

  1. 每当我更改绘图参数时,都会看到闪烁。根据我在这里和那里阅读的内容,解决此问题的标准方法是使用临时 DC 进行双缓冲。但据我了解,这正是我已经在做的事情。

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

谢谢。

【问题讨论】:

  • OnPaint 事件处理程序不应创建自己的 DC 以供绘制。您应该使用 CPaintDC 类。
  • @CodyGray:谢谢。我已经尝试过了,但它似乎对我不起作用。可能是因为我创建的paint-DC 属于对话框本身,而不是我尝试绘制的窗口。您能否提供一些更具体的证据来说明“OnPaint 事件处理程序不应创建自己的 DC”的原因?谢谢。
  • 嗯……你为什么要处理一个窗口(一个对话框)的绘制事件并试图在一个不同的窗口上绘制?如果要在窗口上绘画,请处理 该窗口的 绘画事件。
  • 具体证据,为什么 OnPaint 处理程序不应创建自己的 DC:该 DC 从不验证无效区域,保留 WM_PAINT 消息流。 (CPaintDC 验证其 c'tor 中的无效区域。)
  • 那为什么不直接在对话框上画呢?使用WS_CLIPCHILDREN 避免在其他控件上绘画。

标签: winapi mfc gdi stretchblt setwindowpos


【解决方案1】:
  1. 应在该子窗口的 WM_PAINT 处理程序中将图像绘制到子窗口中,而不是在对话框中完成。您的子窗口可能需要记住父对话框提供的信息,以便它可以独立绘制。通过从对话框的 WM_PAINT 处理程序绘制窗口,您的绘制频率可能超出了必要(并且可能不会导致在图像窗口中发生验证)。

  2. 对话框应该有 WS_CLIPCHILDREN 窗口样式,而您的图像窗口应该有 WS_CLIPSIBLINGS。这将防止对话框控件相互重叠,并且可以通过允许更少量的更新来减少闪烁。

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

【讨论】:

  • 谢谢。图片没有覆盖整个图片窗口,所以我无法覆盖OnEraseBkgnd回调并返回TRUE。
  • 您可以让您的绘图处理程序仔细擦除窗口的未覆盖区域,然后跳过 WM_ERASEBKGND。这可以通过避免两次绘制像素来防止一些闪光。但是,在具有桌面合成的现代系统上,您甚至可能不会注意到闪存。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-15
    • 2019-11-03
    • 2012-11-17
    • 1970-01-01
    • 2019-09-12
    • 1970-01-01
    相关资源
    最近更新 更多