понедельник, 21 сентября 2015 г.

Блокировка перерисовки окна на время обновления его дочерних окон

Открыл для себя сообщение WM_SETREDRAW. Позволяет на какое-то время отключить перерисовку контрола (окна), тем самым избавить пользователя от лишних мерцаний, эффекта шлейфа и тому подобного. Применил в своём сплиттере, теперь при изменении размеров – красота. Сравните две анимашки (т.к. это gif – сохранил в оттенках серого, иначе появляются цветовые артефакты).

До применения WM_SETREDRAW:

before_gs

Здесь прекрасно видно, что панель слева от сплиттера не успевает отрисовываться (да и правая отстаёт).

А это уже после обрамления кода по изменению ширины AlignControl’а в WM_SETREDRAW:

after_gs

 

Обрамление в коде выглядит вот так:

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 коммент.:

Coriolis комментирует...

Класс! Спасибо!

Roman Yankovsky комментирует...

Полезная штука.

Александр Алексеев комментирует...

Про замечание.

Николай Зверев комментирует...

Да, спасибо. Такой трюк делать с TForm - в общем случае опасно (пользователь кликнув в форму мышкой попадёт "под" форму и форма потеряет фокус). Поэтому лучше помещать все контролы на TPanel и "играть" уже с ней.

Однако в конкретном случае со сплиттером - такое срабатывание невозможно, т.к. этот код работает с уже захваченной мышью

Николай Зверев комментирует...

Хотя если очень постараться - то можно :)
(Есть в нём возможность программно задать свойство IsSnapped). Теперь вот думаю, что с этим делать.

Николай Зверев комментирует...

Ладно, оставлю как есть. Всем совет - использовать панели или фреймы.

Александр Люлин комментирует...

http://programmingmindstream.blogspot.ru/2015/09/1160.html

Отправить комментарий

.

.