16 августа 2023

Новый режим двойной буферизации VCL-контролов в Delphi 12

    Иногда у приложений написанных на Delphi проявляется одна маленькая, но неприятная проблема – при перерисовке VCL-контрола он "мерцает". Для ее решения разработчики Delphi добавили наследникам TWinControl свойство DoubleBuffered (тип boolean). Если DoubleBuffered имеет значение false, то контрол рисует себя непосредственно в окне. Если DoubleBuffered имеет значение true, то контрол рисует себя сначала на bitmap в памяти, а затем bitmap рисуется на окне. Двойная буферизация уменьшает мерцание, но требует больше памяти. Кроме повышенного расхода памяти есть и более существенные проблемы. Например, зависание VCL-приложений при работе через удаленные рабочий стол (RDP). Этой проблемой страдала даже сама IDE RAD Studio. Любое изменение сеанса RDP (блокировка, разблокировка, подключение, отключение) вызывает изменение общесистемных настроек (WM_SETTINGCHANGE), которое приводит к каскаду сообщений и множеству перерисовок IDE. Устранили это только в RAD Studio 10.4.2. В Delphi 12 механизм двойной буферизации VCL-контролов был доработан.
    В Delphi 12 все контролы, имеющие свойство DoubleBuffered, получили новое свойство DoubleBufferedMode (тип TDoubleBufferedMode). Оно управляет использованием двойной буферизации и имеет два значения:
  • dbmDefault – приложение будет работать как раньше и в некоторых случаях двойная буферизация будет отключена автоматически (например, при работе по RDP).
  • dbmRequested – двойная буферизацию используется всегда (включая работу по RDP).
    Второй доработкой в Delphi 12, связанной с двойной буферизации VCL-контролов, является функция TWinControl.CanUseDoubleBuffering: Boolean. Она вызывается в коде контролов при проверке свойства DoubleBuffered ("FDoubleBuffered and CanUseDoubleBuffering"). Переопределив ее для своего контрола, можно сделать для него нестандартную проверку возможности двойной буферизации. Разработчики Delphi переопределили у TButtonControl функцию CanUseDoubleBuffering и тем самым отключили ему двойную буферизацию по умолчанию. Поэтому для того, чтобы у наследников TButtonControl (TButton, TCheckBox и TRadioButton) использовать двойную буферизацию, необходимо установить контролам этих типов свойство DoubleBufferedMode в состояние dbmRequested.

2 комментария:

  1. В Delphi 12 появилось странное дрожание контролов в Child-окнах MDI-приложения

    1) Компилируем и запускаем демку в Delphi 12 (29.0.50491.5718) Patch 1.
    1.1) Жмем пункт меню "Open Child" (открывается Child-форма, FormStyle = fsMDIChild).
    Жмем кнопку "Test" или пункт меню "Exit".
    Видим как при появлении и скрытии диалогового окна дрожат все контролы
    (Label, Edit, Caption PageControl, Caption TabControl).
    Чем слабее компьютер и видеокарта, тем это дрожание заметнее.
    1.2) Теперь жмем пункт меню "Open Modal" (открывается нормальная форма, FormStyle = fsNormal).
    Жмем кнопку "Test" и ничего не дрожит.

    2) Компилируем и запускаем демку в Delphi 11.3 или ниже.
    Выполняем действия описанные в пункте 1.1 - ничего не дрожит.

    Получается, что то сломали в Delphi 12 ?

    Это лемка ошибки:
    https://drive.google.com/file/d/1h5oK5-LGun5pQHPEkBpINIZSGlv-deOe/view?usp=sharing

    ОтветитьУдалить
    Ответы
    1. А от версии Windows и параметров ее визуальных эффектов не зависит?

      Удалить