Блокировка перерисовки окна на время обновления его дочерних окон
Открыл для себя сообщение WM_SETREDRAW. Позволяет на какое-то время отключить перерисовку контрола (окна), тем самым избавить пользователя от лишних мерцаний, эффекта шлейфа и тому подобного. Применил в своём сплиттере, теперь при изменении размеров – красота. Сравните две анимашки (т.к. это gif – сохранил в оттенках серого, иначе появляются цветовые артефакты).
До применения WM_SETREDRAW:
Здесь прекрасно видно, что панель слева от сплиттера не успевает отрисовываться (да и правая отстаёт).
А это уже после обрамления кода по изменению ширины AlignControl’а в WM_SETREDRAW:
Обрамление в коде выглядит вот так:
var LLockPaint: Boolean; begin LLockPaint := Parent.HandleAllocated and Parent.Visible; if LLockPaint then SendMessage(Parent.Handle, WM_SETREDRAW, 0, 0); try // код по изменению размеров контролов finally if LLockPaint then begin SendMessage(Parent.Handle, WM_SETREDRAW, 1, 0); RedrawWindow(Parent.Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_ALLCHILDREN); end; end; end;
Хочу отметить, что если просто перерисовывать родительский (по отношению к сплиттеру) контрол, например вызовом Parent.Repaint – то шлейфов тоже не будет, но при этом появляется мерцание, которое заметно в более нагруженных (чем на примере) контролами случаях.
Эту технику можно применять в тех случаях, когда в одном окне необходимо перерасположить несколько контролов. Ну как пример, когда в IDE меняется Layout (Desktop speedsetting) – без блокировки рисования пользователь видит неприятные мерцания.
И ещё одно важное замечание: WM_SETREDRAW меняет видимость окна (оно как бы скрывается, но при этом область под окном – не перерисовывается). И если окно уже было скрыто, то оно может быть ошибочно отображено (и наоборот), поэтому не забывайте проверять этот момент.