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:
[crayon-67681d116785d667089638/]
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:
[crayon-67681d1167869605851600/]
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: