Um dos recursos adicionados à biblioteca VCL no Delphi 11 é a capacidade de manipular a mensagem WM_SETREDRAW do Windows facilmente com dois métodos específicos adicionados à classe TWinControl: LockDrawing e UnlockDrawing
Eu estava revisando minha lista de tarefas no início desta semana e encontrei um not que indicava que eu deveria seguir a postagem do blog que fiz sobre os novos recursos da VCL no Delphi e C++Builder 11 sobre LockDrawing. Na verdade eu escrevi: “A classe base TWinControl agora oferece os métodos LockDrawing e UnlockDrawing, para desabilitar e controlar a atualização. Isso aciona a execução da mensagem WM_SETREDRAW do Windows. Isso provavelmente vale a sua própria postagem no blog … ” mas eu esqueci totalmente disso. Então aqui está o post do blog, com alguns meses de atraso.
Vamos começar pela API do Windows. A mensagem WM_SETREDRAW é enviada para uma janela para “ permitir que as alterações nessa janela sejam redesenhadas, ou para evitar que as alterações nessa janela sejam redesenhadas. ” Sempre que você precisar realizar um conjunto de operações, cada uma exigindo repintar, você pode colocá-las em espera e repintar apenas no final, evitando oscilações e tornando o processo mais rápido. É claro que é importante remover o bloqueio e chamar uma função especial para forçar a repintura (RedrawWindow).
Tudo isso está devidamente encapsulado em dois métodos TWinControl adicionados à biblioteca VCL no RAD Studio 11, LockDrawing e UnlockDrawing, que enviam a mensagem WM_SETREDRAW com os parâmetros adequados. Eles também implementam uma “lógica de contagem de bloqueios” para que, se você bloquear o mesmo controle duas vezes, seja necessário desbloqueá-lo duas vezes para retomar a pintura. Além disso, o UnlockDrawing chama automaticamente a API RedrawWindow.
Dito isto, quais são os casos de uso? Eu escrevi uma demo mostrando dois cenários, e você também pode conferir esta bela postagem no blog de Radek Cervinka.
Um primeiro caso na minha demonstração é adicionar vários elementos a uma caixa de listagem. Embora o Delphi tradicionalmente ofereça e ainda tenha a capacidade de evitar a repintura “congelando” a atualização da lista de strings, faz sentido bloquear a repintura da interface do usuário. Estes são os dois estilos de codificação alternativos:
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; |
Em ambos os casos, o desempenho é muito maior (e perceptível) do que sem uma das duas soluções. Outro cenário é o de um conjunto de alterações em um componente causando uma repintura. Isso não é trivial para simular em um exemplo simples, mas uma maneira de causar cintilação “de propósito” com código como este:
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; |
Eu sei, isso é bastante estúpido, mas você pode ver que não há cintilação com as chamadas Lock/Unlock, enquanto o efeito parece bastante horrível sem bloquear a interface do usuário. Não que eu possa facilmente renderizar isso em uma captura de tela, mas aqui está o formulário em tempo de execução:
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition