Одной из функций, добавленных в библиотеку VCL в Delphi 11, является возможность простой обработки сообщения Windows WM_SETREDRAW с помощью двух специальных методов, добавленных в класс TWinControl: LockDrawing и UnlockDrawing.
Ранее на этой неделе я просматривал свой список дел и обнаружил, что не указано, что мне следует продолжить публикацию в блоге о новых функциях VCL в Delphi и C++Builder 11 о LockDrawing. На самом деле я написал: «Базовый класс TWinControl теперь предлагает методы LockDrawing и UnlockDrawing для отключения и управления обновлением. Это инициирует выполнение сообщения Windows WM_SETREDRAW. Это, наверное, стоит отдельного поста в блоге… », но потом я совсем забыл об этом. Итак, вот сообщение в блоге с задержкой в несколько месяцев.
Начнем с Windows API. Сообщение WM_SETREDRAW отправляется окну, чтобы « разрешить перерисовку изменений в этом окне или предотвратить перерисовку изменений в этом окне». Каждый раз, когда вам нужно выполнить набор операций, каждая из которых требует перерисовки, вы можете отложить их и перерисовать только в конце, избегая мерцания и ускоряя процесс. Конечно, важно снять блокировку, а затем вызвать специальную функцию для принудительной перерисовки (RedrawWindow).
Все это должным образом инкапсулировано в двух методах TWinControl, добавленных в библиотеку VCL в RAD Studio 11, LockDrawing и UnlockDrawing, которые отправляют сообщение WM_SETREDRAW с соответствующими параметрами. Они также реализуют «логику подсчета блокировок», так что если вы дважды заблокируете один и тот же элемент управления, вам нужно дважды разблокировать его, чтобы возобновить рисование. Кроме того, UnlockDrawing автоматически вызывает API RedrawWindow.
Сказав это, каковы варианты использования? Я написал демо-версию, показывающую два сценария, и вы также можете проверить этот хороший пост в блоге Радека Червинки.
Первый случай в моей демонстрации — добавление набора элементов в список. Хотя Delphi традиционно предлагает и по-прежнему имеет возможность избежать перерисовки, «замораживая» обновление списка строк, вместо этого имеет смысл заблокировать перерисовку пользовательского интерфейса. Это два альтернативных стиля кодирования:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var I: Integer; begin ListBox1.Items.BeginUpdate; try for I := 1 to 10000 do ListBox1.Items.Add('Line ' + I.ToString); finally ListBox1.Items.EndUpdate; end; var I: Integer; begin ListBox1.LockDrawing; try for I := 1 to 10000 do ListBox1.Items.Add('Line ' + I.ToString); finally ListBox1.UnlockDrawing; end; |
В обоих случаях производительность намного выше (и заметно заметнее), чем без одного из двух решений. Другой сценарий — набор изменений в компоненте, вызывающий перерисовку. Это непросто смоделировать на простом примере, но это один из способов вызвать мерцание «намеренно» с помощью такого кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var I: Integer; begin Panel1.LockDrawing; try for I := 1 to 10000 do begin Panel1.Color := clBlue; Panel1.Repaint; Panel1.Color := clRed; Panel1.Repaint; end; finally Panel1.UnlockDrawing; end; |
Я знаю, это довольно глупо, но вы можете видеть, что при вызовах блокировки/разблокировки мерцания нет, в то время как без блокировки пользовательского интерфейса эффект выглядит довольно ужасно. Не то чтобы я мог легко отобразить это на скриншоте, но в любом случае вот форма во время выполнения:
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition