9 de fevereiro de 2011

Personalizando a edição de propriedades em componentes Delphi - parte II

No último post, eu falei um pouco sobre as preocupações que devemos ter na criação de componentes no Delphi quanto à necessidade de separação do comportamento deles em tempo de execução daqueles comportamentos que são exclusivos do tempo de design – portanto, oferecidos apenas aos programadores.Citei também que a edição de propriedades no Object Inspector é um comportamento de tempo de execução que pode ser customizado pelo programador do componente, bastando criar uma herança da classe TBasePropertyEditor que implemente a interface IProperty.

Dando sequência ao assunto, detalho aqui alguns métodos dessa interface e mostro como criar o editor para uma propriedade que nos permita montar filtros para tipos de arquivos, como o exibido abaixo:
Editor de filtros de tipos de arquivos
Os principais métodos introduzidos pela interface IProperty são listados abaixo:
Edit: Este método é chamado quando se clica o botão de edição apresentado junto à propriedade no Object Inspector. No nosso exemplo, ele criará e exibirá a tela para o programador entrar com os filtros de arquivos desejados.
GetAttributes: Retorna as características da propriedade de forma que o Object Inspector possa determinar quais tipos de controle apresentar ao programador, como botões de edição, caixa com lista para seleção, etc. . Por exemplo, como a propriedade de filtro apresenta uma tela para edição, o Object Inspector deve ser preparado para exibir um botão que dê acesso à tela.
GetEditLimit: Retorna a quantidade máxima de caracteres que o programador pode informar como valor para a propriedade. O nosso exemplo não fará restrições nesse aspecto.
GetValue e SetValue: Respectivamente, obtém o valor atual da propriedade e ajusta um novo valor para a propriedade em tempo de design. Ambas são chamadas automaticamente pelo Object Inspector, desde que a edição da propriedade não se dê através de um diálogo. Como esse é o caso do nosso exemplo, teremos que chamá-las manualmente dentro do método Edit.
GetEditValue: Obtém um texto formatado para apresentar como valor da propriedade em tempo de design. Diferentemente de GetValue e SetValue, essa função não levanta uma exceção caso a propriedade não tenha valor. No nosso exemplo, essa função retornará o mesmo texto que GetValue, já que a propriedade que estamos tratando é do tipo texto.
Para implementar o exemplo com a tela de filtros de arquivos, temos que declarar duas classes. A primeira representa a tela de filtro em si enquanto a segunda tratará os requisitos para intermediar a comunicação com o Object Inspector, isto é, será uma herança de TBasePropertyEditor e implementará a interface IProperty.
{ A tela para edição dos filtros }
TWFilterEditor = class(TForm)
Bevel1: TBevel;
OKButton: TButton;
CancelButton: TButton;
HelpButton: TButton;
procedure FormCreate(Sender: TObject);
procedure HelpBtnClick(Sender: TObject);
private
procedure SetFilter(Value: string);
function GetFilter: string;
end;

{ Classe que gerenciará a comunicação com o Object Inspector }
TWFilterProperty = class(TStringProperty)
public
procedure Edit; override;
function GetAttributes: TPropertyAttributes; override;
end;
Veja que ao criar a classe para comunicação com o Object Inspector eu herdei diretamente da classe da VCL TStringProperty pois ela já implementa grande parte do que precisamos, incluindo os métodos requeridos pela interface IProperty. Aqui, teremos que sobrepor apenas os métodos Edit e GetAttributes para introduzir a parte do comportamento que será diferente para nós:
procedure TWFilterProperty.Edit;
var FilterEditor: TWFilterEditor;
begin
{ Cria e apresenta a tela de filtros }
FilterEditor := TWFilterEditor.Create(Application);
try
FilterEditor.SetFilter(GetValue);
FilterEditor.ShowModal;

{ A edição foi feita com sucesso, ajusta o novo valor para a propriedade }
if FilterEditor.ModalResult = mrOK then
SetValue(FilterEditor.GetFilter);
finally
FilterEditor.Free;
end;
end;

function TWFilterProperty.GetAttributes: TPropertyAttributes;
begin
Result := [paDialog, paMultiSelect];
end;
O método Edit cria uma instância da classe de tela e obtém manualmente o valor da propriedade através do GetValue antes de exibi-la. Ao encerrar a tela após uma edição com sucesso, o valor é novamente atribuído à propriedade, através de uma chamada ao SetValue.

No GetAttributes, retornamos um valor que indica ao Object Inspector que essa propriedade será editada através de uma caixa de diálogo (nossa tela de filtro) e que é permitido ao programador selecionar vários componentes ao mesmo tempo e editar a propriedade em todos eles (paMultiSelect) simultaneamente. Para finalizar, precisamos notificar a VCL sobre qual(is) propriedade(s) deverá(ão) usar nosso editor personalizado:
procedure Register;
begin
RegisterComponents('ABC71', [TWAttachFileBtn]);
RegisterPropertyEditor (TypeInfo(string), TWAttachFileBtn, 'TiposPermitidos', TWFilterProperty);
end;
Observe que o registro do editor para a propriedade ocorre no mesmo local em que o próprio componente é registrado na paleta de componentes do Delphi, isto é, uma função isolada chamada Register criada na própria Unit. Na função acima, nosso editor é associado à propriedade 'TiposPermitidos' de um componente chamado TWAttachFileBtn.

Nenhum comentário :

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.