Em várias classes do Delphi existem certos métodos que recebem como parâmetro de entrada uma ação e essa ação será aplicada a elementos internos da classe.
Pode parecer estranho, já que existe um método ele deveria saber o que fazer. Porém o uso de funções de callback pode dar maior flexibilidade quanto à execução do método.
Essa ação que deverá ser passada ao método, é passada em forma de procedimento ou função que deve ser compatível com tipo indicado.
Um exemplo prático da função de callback
Para compreender melhor o que é uma função de callback vamos a um exemplo que organiza uma lista de objetos, para isso vamos usar a classes TList.
A classe TList possui um método que organiza os itens da coleção de objetos armazenados, esse é o método Sort.
Acima mencionamos que alguns métodos podem receber como parâmetro uma ação, no caso do Sort ele requer uma ação de comparação, ou seja, uma função que faça a comparação de seus elementos internos e deve obedecer a seguinte assinatura:
function (Item1: Pointer; Item2: Pointer): integer;
Crie uma classe TClientes como na Listagem 1.
TClientes = class
private
FNome: string;
FEndereco: string;
procedure SetNome(const Value: string);
procedure SetEndereco(const Value: string);
public
property Nome: string read FNome write SetNome;
property Endereco: string read FEndereco write SetEndereco;
end;
Depois, vamos criar as seguintes propriedade e métodos na seção private do formulário principal, Listagem 2.
private
{ Private declarations }
property ListaClientes: TList read FListaClientes write SetListaClientes;
procedure EncheListaClientes;
procedure AtualizaListBox;
Na Listagem 3 vemos a implementação deles.
procedure TForm1.EncheListaClientes;
begin
lCliente1 := TClientes.Create;
lCliente1.Nome := "Paulo";
lCliente1.Endereco := "Av. Joao Pereira Barreto";
ListaClientes.Add(lCliente1);
lCliente2 := TClientes.Create;
lCliente2.Nome := "Andre";
lCliente2.Endereco := "Av. Ayrton Senna";
ListaClientes.Add(lCliente2);
lCliente3 := TClientes.Create;
lCliente3.Nome := "Jair";
lCliente3.Endereco := "Rua Dom Pedro I";
ListaClientes.Add(lCliente3);
end;
procedure TForm1.AtualizaListBox;
var
lIndex: integer;
begin
ListBox1.Items.Clear;
for lIndex := 0 to ListaClientes.Count -1 do
ListBox1.Items.Add(TClientes(ListaClientes[lIndex]).Nome + "-" +
TClientes(ListaClientes[lIndex]).Endereco);
end;
Esta na hora de criar as funções de callback, elas é que vão ditar as regras de comparação/ordenação para o método sort do ListaClientes, veja Listagem 4.
var
Form1: TForm1;
function ClassificaPorNome(item1: Pointer; item2: Pointer): integer;
function ClassificarPorEndereco(item1: Pointer; item2: Pointer): integer;
function ClassificaPorNome(item1, item2: Pointer): integer;
begin
result := CompareText(TClientes(item1).Nome, TClientes(item2).Nome);
end;
function ClassificarPorEndereco(item1, item2: Pointer): integer;
begin
result := CompareText(TClientes(item1).Endereco, TClientes(item2).Endereco);
end;
As funções ClassificaPorNome e ClassificaPorEndereco serão passadas como parâmetro para o método Sort, Listagem 5.
procedure TForm1.Button2Click(Sender: TObject);
begin
ListaClientes.Sort(@ClassificarPorEndereco);
AtualizaListBox;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ListaClientes.Sort(@ClassificaPorNome);
AtualizaListBox;
end;
Observem que não passo o nome da função e sim seu endereço na memória, isso através do operador @. Ao ser chamado, o método Sort localiza a ação a ser tomada, que por sua vez está implementada pela função passada como parâmetro.