WIN32: Как сказать статическому элементу управления, нарисованному владельцем, чтобы обновить себя? - PullRequest
0 голосов
/ 24 июня 2011

У меня есть нарисованный владельцем статический элемент управления 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;

Тем не менее, я не могу заставить вещь стереть и перекрасить должным образом.Я пробовал SendMessage с WM_PAINT и RedrawWindow, и ни один из них не работал совершенно правильно:

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 или удалить hDC в DRAWITEMSTRUCT, который мне передали?

Ответы [ 2 ]

6 голосов
/ 24 июня 2011

Вы не отменяете выбор растровых изображений из памяти DC, прежде чем уничтожить DC. Возможно, растровые изображения находятся в состоянии, когда Windows не позволит вам выбрать их снова, поэтому битовые биты дают сбой.

P.S. RedrawWindow - это то, что я использую в этой ситуации. InvalidateRect работает тоже, но только если ваш цикл сообщений работает. Это приводит к другому наблюдению: если вы находитесь в середине длительной операции, вы можете не вернуться к циклу сообщений, и ваше приложение будет зависать, включая обновления в окне прогресса.

3 голосов
/ 24 июня 2011

InvalidateRect() - это функция, которую нужно вызвать.

Вы никогда не отправляете и не публикуете WM_PAINT сообщений - оконный менеджер делает это за вас, когда они нужны (например, окна перетаскиваются поверх вашего окна). Если перерисовка происходит из-за изменений, о которых оконный менеджер не знает, вы запускаете цикл перерисовки, вызывая InvalidateRect(). Передайте NULL для lpRect, и вся клиентская область будет перекрашена. Передайте TRUE для bErase, чтобы принудительно удалить фон при начале цикла перекраски.

Когда вы вызываете InvalidateRect(), происходит следующее: сообщение WM_PAINT помещается в вашу очередь сообщений и возвращается вызов функции InvalidateRect(). Когда вы в следующий раз очищаете свою очередь сообщений, вы обрабатываете сообщение WM_PAINT.

Я предлагаю вам взять экземпляр книги Petzold's Programming Windows и прочитать о ней все.

...