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