WIN32: Как сказать статическому элементу управления, нарисованному владельцем, чтобы обновить себя?
У меня есть нарисованный владельцем статический элемент управления 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 ответа
Вы не отменяете выбор растровых изображений из памяти DC, прежде чем уничтожить DC. Возможно, растровые изображения находятся в состоянии, когда Windows не позволит вам выбрать их снова, поэтому битовые биты дают сбой.
PS RedrawWindow - это то, что я использую в этой ситуации. InvalidateRect тоже работает, но только если ваш цикл сообщений работает. Это приводит к другому наблюдению: если вы находитесь в середине длительной операции, вы можете не вернуться к циклу сообщений, и ваше приложение будет зависать, включая обновления в окне прогресса.
InvalidateRect()
это функция, которую нужно вызвать.
Вы никогда не отправляете и не публикуете WM_PAINT
сообщения - оконный менеджер делает это за вас, когда они нужны (например, окна перетаскиваются поверх вашего окна). Если перерисовка происходит из-за изменений, о которых оконный менеджер не знает, вы запускаете цикл перерисовки, вызывая InvalidateRect()
, Проходить NULL
за lpRect
и вся клиентская зона будет перекрашена. Проходить TRUE
за bErase
заставить фон стираться, когда начинается цикл перекраски.
Когда вы звоните InvalidateRect()
что происходит, что WM_PAINT
сообщение помещается в вашу очередь сообщений и InvalidateRect()
вызов функции возвращается. Когда вы в следующий раз очистите свою очередь сообщений, вы обработаете WM_PAINT
сообщение.
Я предлагаю вам взять экземпляр книги Petzold's Programming Windows и прочитать о ней все.