Na maioria das vezes, ao programar no Delphi, você não precisa criar dinamicamente um componente. Se você soltar um componente em um formulário, o Delphi manipula a criação do componente automaticamente quando o formulário é criado. Este artigo abordará a maneira correta de criar componentes programaticamente em tempo de execução.
Criação dinâmica de componentes
Existem duas maneiras de criar componentes dinamicamente. Uma maneira é tornar um formulário (ou outro TComponent) o proprietário do novo componente. Essa é uma prática comum ao criar componentes compostos nos quais um contêiner visual cria e possui os subcomponentes. Isso garantirá que o componente recém-criado seja destruído quando o componente proprietário for destruído.
Para criar uma instância (objeto) de uma classe, chame seu método "Create". O construtor Create é um método de classe, em oposição a praticamente todos os outros métodos que você encontrará na programação Delphi, que são métodos de objetos.
Por exemplo, o TComponent declara o construtor Create da seguinte maneira:
construtor Create (AOwner: TComponent); virtual;
Criação dinâmica com proprietários
Aqui está um exemplo de criação dinâmica, em que Auto é um descendente de TComponent ou TComponent (por exemplo, uma instância de um TForm):
com TTimer. Criar (Self) do
início
Intervalo: = 1000;
Ativado: = Falso;
OnTimer: = MyTimerEventHandler;
fim;
Criação dinâmica com uma chamada explícita para liberar
A segunda maneira de criar um componente é usar nada como o proprietário. Observe que, se você fizer isso, também deverá liberar explicitamente o objeto que criar, assim que não precisar mais dele (ou produzirá um vazamento de memória). Aqui está um exemplo do uso de nil como proprietário:
com TTable. Criar (nil) fazer
experimentar
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
Aberto;
Editar;
FieldByName ('Ocupado') .AsBoolean: = True;
Postar;
finalmente
Livre;
fim;
Criação dinâmica e referências a objetos
É possível aprimorar os dois exemplos anteriores, atribuindo o resultado da chamada Create a uma variável local ao método ou pertencente à classe. Isso geralmente é desejável quando referências ao componente precisa ser usado mais tarde, ou quando escopo problemas potencialmente causados por blocos "Com" precisam ser evitados. Aqui está o código de criação do TTimer acima, usando uma variável de campo como referência ao objeto TTimer instanciado:
FTimer: = TTimer. Criar (Self);
com o FTimer do
início
Intervalo: = 1000;
Ativado: = Falso;
OnTimer: = MyInternalTimerEventHandler;
fim;
Neste exemplo, "FTimer" é uma variável de campo particular do formulário ou contêiner visual (ou o que seja "Self"). Ao acessar a variável FTimer a partir de métodos nesta classe, é uma boa idéia verificar se a referência é válida antes de usá-la. Isso é feito usando a função Assigned do Delphi:
se atribuído (FTimer), então FTimer. Ativado: = Verdadeiro;
Criação dinâmica e referências de objeto sem proprietários
Uma variação disso é criar o componente sem proprietário, mas manter a referência para destruição posterior. O código de construção para o TTimer ficaria assim:
FTimer: = TTimer. Criar (nulo);
com o FTimer do
início
...
fim;
E o código de destruição (presumivelmente no destruidor do formulário) ficaria assim:
FTimer. Livre;
FTimer: = nulo;
(*
Ou use o procedimento FreeAndNil (FTimer), que libera uma referência de objeto e substitui a referência por zero.
*)
Definir a referência do objeto como nulo é essencial ao liberar objetos. A chamada para Free primeiro verifica se a referência ao objeto é nula ou não e, se não for, chama o destruidor do objeto Destroy.
Criação dinâmica e referências de objeto local sem proprietários
Aqui está o código de criação TTable acima, usando uma variável local como referência ao objeto TTable instanciado:
localTable: = TTable. Criar (nulo);
experimentar
com localTable do
início
DataBaseName: = 'MyAlias';
TableName: = 'MyTable';
fim;
...
// Mais tarde, se queremos especificar explicitamente o escopo:
localTable. Aberto;
localTable. Editar;
localTable. FieldByName ('Ocupado') .AsBoolean: = True;
localTable. Postar;
finalmente
localTable. Livre;
localTable: = nulo;
fim;
No exemplo acima, "localTable" é um variável local declarado no mesmo método que contém esse código. Observe que, após liberar qualquer objeto, em geral, é uma boa idéia definir a referência como nula.
Uma palavra de aviso
IMPORTANTE: Não misture uma chamada para Free com a passagem de um proprietário válido para o construtor. Todas as técnicas anteriores funcionarão e são válidas, mas o seguinte deve nunca ocorre no seu código:
com TTable. Criar (auto) fazer
experimentar
...
finalmente
Livre;
fim;
O exemplo de código acima apresenta hits de desempenho desnecessários, afeta um pouco a memória e tem o potencial de apresentar bugs difíceis de encontrar. Descubra o porquê.
Nota: Se um componente criado dinamicamente tiver um proprietário (especificado pelo parâmetro AOwner do construtor Create), esse proprietário será responsável por destruir o componente. Caso contrário, você deverá ligar explicitamente para Free quando não precisar mais do componente.
Artigo originalmente escrito por Mark Miller
Um programa de teste foi criado no Delphi para cronometrar a criação dinâmica de 1000 componentes com contagens variáveis de componentes iniciais. O programa de teste aparece na parte inferior desta página. O gráfico mostra um conjunto de resultados do programa de teste, comparando o tempo necessário para criar componentes, tanto com proprietários quanto sem proprietários. Observe que isso é apenas uma parte do acerto. Um atraso de desempenho semelhante pode ser esperado ao destruir componentes. O tempo para criar componentes dinamicamente com os proprietários é 1200% a 107960% mais lento que o tempo para criar componentes sem proprietários, dependendo do número de componentes no formulário e no componente que está sendo criada.
O Programa de Teste
Aviso: Este programa de teste não rastreia e libera componentes criados sem proprietários. Ao não rastrear e liberar esses componentes, os tempos medidos para o código de criação dinâmica refletem com mais precisão o tempo real para criar dinamicamente um componente.
Baixar código fonte
Atenção!
Se você deseja instanciar dinamicamente um componente Delphi e liberá-lo explicitamente algum tempo depois, sempre passe nulo como proprietário. Não fazer isso pode apresentar riscos desnecessários, além de problemas de desempenho e manutenção de código. Leia o artigo "Um aviso sobre a instanciação dinâmica de componentes Delphi" para saber mais ...