简体   繁体   English

WIN32:如何告诉所有者绘制的静态控件进行自我刷新?

[英]WIN32: How Do I Tell an Owner Drawn Static Control to Refresh Itself?

I have a WIN32 owner-drawn static control that draws a progress bar using two source images (filled and unfilled). 我有一个WIN32所有者绘制的静态控件,该控件使用两个源图像(填充的和未填充的)绘制进度条。 Works great on the initial draw: 在初始抽奖时效果很好:

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;

However, I can't seem to get the thing to erase and repaint properly. 但是,我似乎无法正确擦除和重新粉刷东西。 I've tried SendMessage with WM_PAINT and RedrawWindow and neither one has worked quite right: 我已经尝试过使用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;
}

Instead of redrawing the window with the new values, it just sits there with the initially drawn image and ignores further drawing commands. 与其使用新值重新绘制窗口,不如将其与最初绘制的图像一起放置在此处,而忽略其他绘制命令。 It draws the progress correctly for the initial value, whether it's 0%, 50%, etc, and I can verify that my WM_DRAWITEM message handler code is being called. 它可以正确绘制初始值(无论是0%,50%等)的进度,并且我可以验证是否正在调用WM_DRAWITEM消息处理程序代码。

So, what is the correct way to tell this control to erase and redraw in WIN32? 那么,告诉此控件在WIN32中擦除并重画的正确方法是什么?

Is is possible that I need to do something like BeginPaint/EndPaint, or delete the hDC in the DRAWITEMSTRUCT that I've been passed? 是否可能需要执行类似BeginPaint / EndPaint的操作,或删除已通过的DRAWITEMSTRUCT中的hDC?

You aren't deselecting the bitmaps from the memory DC before you destroy the DC. 在销毁DC之前,您无需从内存DC中取消选择位图。 Perhaps the bitmaps are in a state where Windows won't allow you to select them again, so the BitBlts are failing. 也许位图处于Windows不允许您再次选择它们的状态,所以BitBlts失败了。

PS RedrawWindow is what I use in this situation. PS RedrawWindow是在这种情况下使用的。 InvalidateRect works too, but only if your message loop is running. InvalidateRect也可以,但仅当您的消息循环正在运行时才有效。 Which leads to another observation: if you're in the middle of a long running operation, you may not get back to the message loop and your app will appear to be hung, including updates to the progress window. 这会导致另一种观察:如果您处于长时间运行的操作中间,则可能无法回到消息循环,并且您的应用程序似乎已被挂起,包括对进度窗口的更新。

InvalidateRect() is the function you need to call. InvalidateRect()是您需要调用的函数。

You never send or post WM_PAINT messages—the Window manager does that for you when they are needed (eg windows dragged over your window). 您永远不会发送或发布WM_PAINT消息-窗口管理器在需要它们时会为您执行此操作(例如,将窗口拖动到窗口上方)。 If the repaint is due to changes that the Window manager does not know about then you force a repaint cycle by calling InvalidateRect() . 如果重新绘制是由于窗口管理器不知道的更改引起的,则可以通过调用InvalidateRect()强制重新绘制周期。 Pass NULL for lpRect and the entire client area will be repainted. lpRect传递NULL ,整个客户区将被重新绘制。 Pass TRUE for bErase to force the background to be erased when the repaint cycle begins. bErase传递TRUE ,以在重新绘制周期开始时强制擦除背景。

When you call InvalidateRect() what happens is that a WM_PAINT message is placed in your message queue and the InvalidateRect() function call returns. 当您调用InvalidateRect()时,将发生WM_PAINT消息放入消息队列,并且InvalidateRect()函数调用返回的情况。 When you next clear your message queue you the process the WM_PAINT message. 下次清除消息队列时,将处理WM_PAINT消息。

I suggest that you get hold of a copy of Petzold's Programming Windows book and read all about it. 我建议您拿一本Petzold的《编程Windows》书的副本,并阅读所有有关它的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM