Na ABC71, por exemplo, temos um componente "lookup" cujo objetivo é permitir ao usuário digitar um valor qualquer - se ele souber de cabeça um código, a digitação se torna mais rápida - ou escolher um dos valores válidos através da consulta a uma lista. O significado do código é uma das propriedades do componente, podendo ser Cliente, Produtos, Pedidos, Títulos, etc. É exibido ao usuário uma caixa de edição para digitação do código, um botão para acionar a lista (quando for preciso) e outra caixa que exibe uma descrição para o código informado na primeira caixa.
Vou montar um componente mais simples para ilustrar essa técnica, colocando uma caixa de edição para o usuário informar um caminho completo de arquivo e um botão caso ele prefira selecionar visualmente o arquivo desejado. Ao sair da caixa de edição, o programador terá a oportunidade de validar o conteúdo informado através de um evento que criaremos. Algumas propriedades a serem publicadas: o texto inicial para a caixa de edição; se o arquivo informado deve existir ou não; quais máscaras de arquivos poderão ser aceitas; etc.
A primeira decisão a ser tomada é em relação à qual classe deve ser usada como base para o componente. Dado que ele permitirá interações com o usuário, devemo usar TControl ou uma de suas heranças, como o TWinControl. A diferença entre ambos é que o TWinControl encapsula a funcionalidade de uma janela, ou seja, pode, entre outras coisas, receber o foco, receber entrada de dados através do mouse ou do teclado, tratar mensagens do Windows (WM_PAINT, por exemplo). Nosso componente será composto por uma caixa de edição e um botão, que já têm todos esses recursos; por isso, o componente em si não precisará implementá-los. No entanto, esses componentes só são visíveis quando a propriedade Parent é informada - obrigatoriamente um TWinControl. Se quisermos que nosso componente seja o Parent dos que forem adicionados internamente, teremos que criá-lo como um TWinControl.
type
TWSelecionaArq = class(TWinControl)
private
_Edit : TEdit;
_Btn : TBitBtn;
_OpenDialog: TOpenDialog;
{ ... }
constructor TWSelecionaArq.Create(AOwner: TComponent);
begin
inherited;
_Edit := TEdit.Create (Self);
_Edit.Parent := Self;
_Btn := TBitBtn.Create (Self);
_Btn.Parent := Self;
_Btn.OnClick := SelecionarArquivo;
_Btn.SetBounds (0, 0, 28, 25);
{ ... }
_OpenDialog := TOpenDialog.Create (Self);
SetBounds (Left, Top, 200, 0);
{ ... }
O excerto acima mostra ainda a declaração dos membros internos da classe que representam o botão e a caixa de edição. Também mostra um TOpenDialog que será usado para exibir a caixa de diálogo que permitirá ao usuário final selecionar um arquivo.TWSelecionaArq = class(TWinControl)
private
_Edit : TEdit;
_Btn : TBitBtn;
_OpenDialog: TOpenDialog;
{ ... }
constructor TWSelecionaArq.Create(AOwner: TComponent);
begin
inherited;
_Edit := TEdit.Create (Self);
_Edit.Parent := Self;
_Btn := TBitBtn.Create (Self);
_Btn.Parent := Self;
_Btn.OnClick := SelecionarArquivo;
_Btn.SetBounds (0, 0, 28, 25);
{ ... }
_OpenDialog := TOpenDialog.Create (Self);
SetBounds (Left, Top, 200, 0);
{ ... }
No trecho relativo ao construtor, os componentes internos são criados e o Parent de cada um é ajustado para nosso próprio componente (self), responsável por exibí-los. Note que nada é feito para posicionar corretamente os componentes internos. Isto mais uma vez será feito pela função SetBounds, que é chamada sempre que o posicionamento ou tamanho de nosso componente é alterado :
procedure TWSelecionaArq.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
{ Altura do componente é a mesma do botão }
AHeight := _Btn.Height + 2;
{ Comprimento mínimo do componente }
if AWidth < 200 then
AWidth := 200;
{ posiciona o edit e o botão }
_Edit.Width := AWidth - _Btn.Width;
_Btn.Left := _Edit.Width + 1;
{ ajuste dos tamanhos do componente }
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;
begin
{ Altura do componente é a mesma do botão }
AHeight := _Btn.Height + 2;
{ Comprimento mínimo do componente }
if AWidth < 200 then
AWidth := 200;
{ posiciona o edit e o botão }
_Edit.Width := AWidth - _Btn.Width;
_Btn.Left := _Edit.Width + 1;
{ ajuste dos tamanhos do componente }
inherited SetBounds(ALeft, ATop, AWidth, AHeight);
end;
Com o esqueleto do componente pronto, podemos acrescentar declarações para as propriedades e eventos desejados. Volto no próximo post com esses detalhes da implementação.
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.