Чтобы полностью избежать мерцания, вам необходимо выполнить все рисование в промежутке между обновлениями экрана. Windows не предоставляет каких-либо простых способов сделать это для обычной окраски окон (Vista предоставляет составной чертеж через DWM , но на это нельзя полагаться даже в системах, работающих под управлением Vista). Поэтому лучшее, что вы можете сделать, чтобы свести к минимуму мерцание, это нарисовать все как можно быстрее ( уменьшить разрыв, увеличивая ваши шансы на завершение всего рисования в цикле обновления), и избежать перерисовки (рисование части экрана а затем рисовать что-то еще поверх: рискует представить пользователю частично нарисованный экран).
Давайте обсудим методы, представленные здесь до сих пор:
Ничего не делать OnEraseBkgnd () : помогает избежать перерисовки, предотвращая заполнение недействительной области окна цветом фона окна. Полезно, когда вы снова будете рисовать всю область во время WM_PAINT обработки в любом случае , как в случае рисования с двойной буферизацией ... но смотрите Примечания по предотвращению перерисовки путем предотвращения рисование по вашему WM_PAINT методу .
Возврат NULL для OnCtlColor () : на самом деле это не должно делать что-либо ..., если в вашей форме нет дочерних элементов управления. В этом случае см. Примечания по предотвращению перерисовки путем предотвращения рисования вместо вашего WM_PAINT метода вместо этого.
Рисунок с двойной буферизацией : помогает избежать разрыва (и, возможно, также перерисовки), уменьшая фактическое изображение на экране до одного BitBLT . Хотя это может повредить время, необходимое для рисования: аппаратное ускорение не может быть использовано (хотя при использовании GDI + шансы на использование любого аппаратного рисования весьма невелики), необходимо создавать и заполнять закадровое растровое изображение для каждой перерисовки, а также все окно должно быть перекрашено для каждой перерисовки. См. Примечания по эффективной двойной буферизации .
Использование вызовов GDI вместо GDI + для BitBlt : Это часто хорошая идея - Graphics::DrawImage()
может быть очень медленным. Я даже обнаружил, что обычный вызов GDI BitBlt()
работает быстрее в некоторых системах. Поиграйте с этим, но только после того, как попробуете несколько других предложений.
Избегание стилей класса окна, которые вызывают полное перерисовывание при каждом изменении размера ( CS_VREDRAW , CS_HREDRAW ) : это поможет, но только если вы не нужно , чтобы перерисовать все окно при изменении размера.
Замечания о том, как избежать оверлея путем предотвращения рисования до вашего WM_PAINT метода
Когда все или часть окна будут признаны недействительными, они будут стерты и перекрашены. Как уже отмечалось, вы можете пропустить удаление, если планируете перекрасить всю недействительную область. Однако , если вы работаете с дочерним окном, то вы должны убедиться, что родительское окно (окна) также не стирает вашу область экрана. Стиль WS_CLIPCHILDREN должен быть установлен во всех родительских окнах - это предотвратит рисование областей, занятых дочерними окнами (включая ваш вид).
Замечания о том, как избежать оверлея путем предотвращения рисования после вашего WM_PAINT метода
Если у вас есть любые дочерние элементы управления, размещенные в вашей форме, вы можете использовать стиль WS_CLIPCHILDREN , чтобы не рисовать их (и впоследствии не перетягивать их. , это несколько повлияет на скорость процедуры BitBlt.
Замечания по эффективной двойной буферизации
Прямо сейчас вы создаете новое изображение заднего буфера каждый раз, когда представление отрисовывается само. Для больших окон это может представлять значительный объем выделяемой и освобождаемой памяти, и приведет к значительным проблемам с производительностью. Я рекомендую сохранять динамически размещаемое растровое изображение в вашем объекте представления, перераспределяя его по мере необходимости, чтобы соответствовать размеру вашего представления.
Обратите внимание, что при изменении размера окна это приведет к тому же количеству выделений, что и к существующей системе, поскольку для каждого нового размера потребуется выделение нового растрового изображения заднего буфера для его соответствия - вы можете немного ослабить боль, округление размеров до следующего наибольшего числа, кратного 4, 8, 16 и т. д., что позволяет избежать перераспределения при каждом крошечном изменении размера.
Обратите внимание, что, если размер окна не изменился с момента последнего рендеринга в задний буфер, вам не нужно повторно отображать его, когда окно недействительно - просто выпустите уже визуализированный изображение на экран.
Кроме того, выделите растровое изображение, соответствующее битовой глубине экрана. Конструктор для Bitmap
, который вы сейчас используете, по умолчанию будет 32bpp, ARGB-layout; если это не соответствует экрану, то его придется конвертировать. Попробуйте получить метод GDI CreateCompatibleBitmap()
, чтобы получить соответствующее растровое изображение.
Наконец-то ... я предполагаю, что ваш пример кода - это просто иллюстративный фрагмент. Но, если вы на самом деле ничего не делаете, кроме визуализации существующего изображения на экране, тогда вам вообще не нужно поддерживать резервный буфер - просто Blt непосредственно из изображения (и заранее конвертируйте формат изображения в соответствовать экрану).