1

我有一个显示图像的 wxWidgets C++ 应用程序。当图像被另一个窗口遮挡时,我非常缓慢地拖动另一个窗口以打开图像,图像经常显示没有被绘制的背景颜色带。

图像在位图中,并在滚动窗格中呈现。OnPaint 函数尽可能简单。无论我使用 true 还是 false 作为 DrawBitmap 的最后一个参数(“use_mask”),行为都是相同的。

void OnPaint(wxPaintEvent &) {
    wxPaintDC dc(this);
    PrepareDC(dc);
    dc.DrawBitmap(bitmap, 0,0, false);
}

我尝试使用 wxBufferedPaintDC。问题依然存在。我能做些什么呢?

在下图中,我刚刚将 Firefox 窗口缓慢拖到右侧,显示了我的应用程序的图片。

竖条纹是假的

我正在 Windows 7 服务包 1 上对此进行测试。AMD A6-3620 APU 与 Radeon(tm) HD Graphics 2.2 GHz。VC++ 2012。wxWidgets 2.9.4。

4

2 回答 2

1

这是版本 2.9.4 中的错误。它在之前的稳定版本 2.8.12 中不存在。它似乎只影响滚动的窗口。

目前最好的解决方案可能是使用 build 2.8.12。如果这不切实际,您可以通过使用 wxClientDC 绘制整个图像来解决此问题。最好只是偶尔这样做。我想出了一个启发式方法来确定何时可能错过了一条条纹。它基于保持更新区域的最新历史。它会出现误报,但不会导致闪烁,至少在我的机器上是这样。

当我知道更多时,我会发布更多。

更新 Eric Jensen 报告说另一种解决方法是重写 OnDraw 方法来进行绘画,并且根本不使用 on-paint 处理程序。

更新问题在使用 Windows Aero 主题时不会出现。

已修复 - http://trac.wxwidgets.org/ticket/14757

于 2012-10-14T04:39:16.767 回答
1

禁用擦除背景事件。当 wxWidgets 想要更新显示时,它会发出两个事件:一个擦除背景事件和一个绘制事件。您必须为擦除背景事件实现一个空方法(换句话说:拦截 EVT_ERASE_BACKGROUND 事件并且不要调用 event.Skip())。

由于您的位图覆盖了整个面板,因此您无需擦除背景。

使用 wxClientDC 的原因是因为“在 EVT_PAINT() 处理程序中使用 wxPaintDC 会自动将剪切区域设置为窗口的损坏区域。不会出现在该区域之外绘制的尝试。”

由于剪切区域存在问题,因此忽略剪切区域“解决”了问题。

这在 wxPaintDC 和 wxClientDC 类参考文档的详细描述部分中有介绍。


这是一个“更好”答案的草图。这比您的计时器和重绘所有解决方案要复杂得多,但从某种意义上说,它更节省系统资源,因此您的应用程序将变得更具响应性。

需要两件事。

  1. 显示位图的更快方法

  2. 仅重绘位图的损坏区域。

(注意:在 wxPaintDC 上使用 DrawBitmap 实际上是处理整个位图,然后对输出进行裁剪)

为了加快位图部分的显示速度,您需要将位图绘制到内存 DC 中,并将其放在方便的地方(此解决方案不节省内存,但这通常不是现代计算机的问题),以便您可以将所需的部分粘贴到 wxPaintDC 中。

wxMemoryDC memdc;
memdc.SelectObject(bitmap);
dc.Blit( ...

这是 Blit 参数的描述http://docs.wxwidgets.org/2.8/wx_wxdc.html#wxdcblit

要仅处理损坏的区域,您需要调用 GetUpdateRegion 并使用区域迭代器通过 reutun 工作。我看到您正在使用滚动面板,因此您必须允许这样做,因为更新区域是根据窗口中的客户区域,而不是您的 bitmap 中的逻辑区域。

 wxRegionIterator upd(GetUpdateRegion());
 while ( upd )
 {  wxRect rect(upd,GetRect());
    // calculate damaged rectangle in terms of your complete bitmap
    ...
    // blit the calculated rectangle from bitmap in memoryDC to damaged recatngle in wxPaintDC
    ...

    upd++;
 {
于 2012-10-13T22:12:34.420 回答