Открыл для себя сообщение 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 меняет видимость окна (оно как бы скрывается, но при этом область под окном – не перерисовывается). И если окно уже было скрыто, то оно может быть ошибочно отображено (и наоборот), поэтому не забывайте проверять этот момент.
7 коммент.:
Класс! Спасибо!
Полезная штука.
Про замечание.
Да, спасибо. Такой трюк делать с TForm - в общем случае опасно (пользователь кликнув в форму мышкой попадёт "под" форму и форма потеряет фокус). Поэтому лучше помещать все контролы на TPanel и "играть" уже с ней.
Однако в конкретном случае со сплиттером - такое срабатывание невозможно, т.к. этот код работает с уже захваченной мышью
Хотя если очень постараться - то можно :)
(Есть в нём возможность программно задать свойство IsSnapped). Теперь вот думаю, что с этим делать.
Ладно, оставлю как есть. Всем совет - использовать панели или фреймы.
http://programmingmindstream.blogspot.ru/2015/09/1160.html
Отправить комментарий