0

我有一个 WIN32 所有者绘制的静态控件,它使用两个源图像(填充和未填充)绘制进度条。在初始抽签中效果很好:

case WM_DRAWITEM:
    {
        DRAWITEMSTRUCT* draw = (DRAWITEMSTRUCT*)lparam;
        // Manually draw the progress bar.
        if( draw->hwndItem == hwndProgress )
        {
            // Progress bar is 526 pixels wide.
            int left = progressPercent * 526 / 100;
            // Paint sections of window with filled and unfilled bitmaps
            // based on progress bar position.
            HDC hdcMem = ::CreateCompatibleDC(draw->hDC);
            ::SelectObject(hdcMem, hBmpProgressFull);
            ::BitBlt(draw->hDC, 0, 0, left, 36, hdcMem, 0, 0, SRCCOPY);
            ::DeleteDC(hdcMem);
            HDC hdcMem2 = ::CreateCompatibleDC(draw->hDC);
            ::SelectObject(hdcMem2, hBmpProgressEmpty);
            ::BitBlt(draw->hDC, left, 0, 526-left, 36, hdcMem2, left, 0, SRCCOPY);
            ::DeleteDC(hdcMem2);
            return TRUE;
        }
    }
    return 0;

但是,我似乎无法正确擦除和重新绘制东西。我已经用 WM_PAINT 和 RedrawWindow 尝试过 SendMessage,但没有一个工作得很好:

bool SetLoginProgressBar(float value)
{
    if( hwndProgress != NULL )
    {
        progressPercent = (int)(value * 100.0);
        //::RedrawWindow(hwndProgress, NULL, NULL, RDW_INVALIDATE|RDW_INTERNALPAINT);
        ::SendMessage(hwndProgress, WM_PAINT, NULL, NULL);
    }
    return true;
}

它不是用新值重新绘制窗口,而是与最初绘制的图像一起坐在那里,并忽略进一步的绘制命令。它为初始值正确绘制进度,无论是 0%、50% 等,我可以验证是否正在调用我的 WM_DRAWITEM 消息处理程序代码。

那么,在WIN32中告诉这个控件擦除和重绘的正确方法是什么?

我是否可能需要执行 BeginPaint/EndPaint 之类的操作,或者删除我已通过的 DRAWITEMSTRUCT 中的 hDC?

4

2 回答 2

6

在销毁 DC 之前,您不会从内存 DC 中取消选择位图。也许位图处于 Windows 不允许您再次选择它们的状态,因此 BitBlts 失败。

PS RedrawWindow 是我在这种情况下使用的。InvalidateRect 也有效,但前提是您的消息循环正在运行。这导致了另一个观察结果:如果您处于长时间运行的操作中,您可能无法返回消息循环,并且您的应用程序将出现挂起,包括对进度窗口的更新。

于 2011-06-24T18:49:10.370 回答
3

InvalidateRect()是你需要调用的函数。

您永远不会发送或发布WM_PAINT消息——窗口管理器会在需要时为您执行此操作(例如,将窗口拖到您的窗口上)。如果重绘是由于窗口管理器不知道的更改,那么您可以通过调用强制重绘周期InvalidateRect()。通行证NULLlpRect整个客户区将被重新粉刷。通过TRUEforbErase强制在重绘周期开始时擦除背景。

当您调用InvalidateRect()时,会发生WM_PAINT消息被放置在您的消息队列中并且InvalidateRect()函数调用返回。当您下次清除消息队列时,您将处理WM_PAINT消息。

我建议您获取 Petzold 的 Programming Windows 书籍并阅读所有相关内容。

于 2011-06-24T18:30:45.763 回答