Construção de Componentes - VI
Seguindo a mesma linha do último exemplo de criação de componentes, para consolidar os pontos discutidos, construiremos outro exemplo bem semelhante ao anterior mudando um pouco a abordagem quanto a funcionalidade do componente.
O principal objetivo deste será oferecer um solução abstrata para uma funcionalidade tipo “Localizar” (tipo um “find”) para um conjunto de registros listados num DBGrid. Basta clickar com o botão direito do mouse na coluna a qual se deseja fazer a busca, o componente dinamicamente cria um menu popup, com um item cujo a descrição seja “Focalizar [título da coluna]”. Efetuado o click sobe o item de menu, o sistema exibe uma janela de diálogo solicitando digitação do valor para busca e em seguida efetua a busca. Localizando no Grid o dado desejado.
O principal objetivo deste será oferecer um solução abstrata para uma funcionalidade tipo “Localizar” (tipo um “find”) para um conjunto de registros listados num DBGrid. Basta clickar com o botão direito do mouse na coluna a qual se deseja fazer a busca, o componente dinamicamente cria um menu popup, com um item cujo a descrição seja “Focalizar [título da coluna]”. Efetuado o click sobe o item de menu, o sistema exibe uma janela de diálogo solicitando digitação do valor para busca e em seguida efetua a busca. Localizando no Grid o dado desejado.
Descrição da funcionalidade:
- Usuário clicka com o botão direito do mouse sobre a coluna do Grid, a qual deseja localizar um registro.
- Sistema exibe o popup menu com um item de localizar.
- Usuário clicka na opção de localizar.
- Sistema Exibe tela de diálogo para usuário digitar o valor a ser localizado.
- Usuário digita o valor e clicka em “Ok”, confirmando a solicitação de localizar.
- Sistema localiza, focando a célula onde se encontra o registro desejado.
Se você não sabe iniciar, no Delphi, a construção de um componente siga as instruções dos artigos anteriores.
Codifique conforme código abaixo a classe TFinderDataZN.
unit FinderDataZN; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DbGrids, ADODb, Db, Menus; type (* Para indicar a Classe se o Popup Menu foi outo-criado, ou já estava associado ao DbGrid que "foi" associado ao TFinderDataZN *) TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent); TFinderDataZN = class(TComponent) private { Private declarations } protected { Protected declarations } public { Public declarations } published Property ReturnValueStr: String read FReturnValueStr; Property ReturnValueNum: Double read FReturnValueNum; property Grid: TDBGrid read FGrid write SetGrid; end; procedure Register; implementation procedure Register; begin RegisterComponents('EstacaoZN', [TFinderDataZN]); end; end.
Codificando a principal propriedade “SetGrid”. Isto porque, essa propriedade vai preparar o Grid e configurar a classe para seu principal fim. Observe que no método “BuildMenuPopup” vou atribuir um evento ao OnClick do item de menu dinamicamente, da mesma forma que fizemos no artigo anterior, contudo neste momento vou deixar essa atribuição comentada. Pois, pretendo implementar a procedure “LocalizarClick” mais adiante. Preste a atenção na linha “/MyMenuitem.OnClick := LocalizarClick”, do método “BuildMenuPopup”, ela estará comentada. O mesmo serve para o método “SetPopupMenu”, visto que o evento PopupMenuPopup, o qual atribuirei ao evento “OnPopup” do Popup Menu associado ao Grid.
unit FinderDataZN; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DbGrids, ADODb, Db, Menus; type (* Para indicar a Classe se o Popup Menu foi outo-criado, ou já estava associado ao DbGrid que "foi" associado ao TFinderDataZN *) TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent); TFinderDataZN = class(TComponent) private FReturnValueNum: Double; FReturnValueStr: String; FGrid: TDBGrid; FADataSet: TCustomADODataSet; FPopupMenu: TPopupMenu; FIsPopupExistent: TPopupExistent; FSelectedColumn: TColumn; FAFieldSearch: TField; // Será usado para setar foco procedure SetGrid(const Value: TDBGrid); procedure SetADataSet(const Value: TCustomADODataSet); procedure SetPopupMenu(const Value: TPopupMenu; const nAllowCreate: Boolean = False); protected procedure CreatePopupMenuItem(const NameItem, CaptionItem: String); virtual; procedure BuildMenuPopup; virtual; procedure SetSelectedColumn(const Value: TColumn); virtual; function GetSelectedColunm: TColumn; virtual; public { Public declarations } published Property ReturnValueStr: String read FReturnValueStr; Property ReturnValueNum: Double read FReturnValueNum; property Grid: TDBGrid read FGrid write SetGrid; end; procedure Register; implementation const PopupMenuItemName: array [0..1] of String = ('ConfigurarGridSep', 'fdLocalizar'); AMenuItemCaption = 'Localizar %s'; procedure Register; begin RegisterComponents('EstacaoZN', [TFinderDataZN]); end; { TFinderDataZN } procedure TFinderDataZN.BuildMenuPopup; var i: Integer; MyMenuitem: TMenuItem; begin (* Verifco se o componente encontra-se em run time*) if not (csDesigning in Self.ComponentState) then begin if Assigned(FPopupMenu) then begin for i := 0 to High(PopupMenuItemName) do begin if (FPopupMenu.Items.Count > 0) and (i = 0) then CreatePopupMenuItem(PopupMenuItemName[i], '-'); if (i = 1) then CreatePopupMenuItem(PopupMenuItemName[i], Format(AMenuItemCaption, [FGrid.Columns[0].Title.Caption])); end; MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1])); if assigned(MyMenuitem) then //MyMenuitem.OnClick := LocalizarClick; end; end; end; procedure TFinderDataZN.CreatePopupMenuItem(const NameItem, CaptionItem: String); var MyMenuitem: TMenuItem; begin MyMenuitem := TMenuItem(Self.FindComponent(NameItem)); if not assigned(MyMenuitem) then begin MyMenuitem := TMenuItem.Create(Self); with MyMenuitem do begin Name := NameItem; Caption := CaptionItem; end; FPopupMenu.Items.Add(MyMenuitem); end; end; function TFinderDataZN.GetSelectedColunm: TColumn; var i: Integer; AuxField: TField; begin Result := nil; for i := 0 to Pred(FGrid.Columns.Count) do begin AuxField := FGrid.Columns[i].Field; if Assigned(AuxField) then if AuxField.FieldName = FGrid.SelectedField.FieldName then Result := FGrid.Columns[i]; if Assigned(Result) then Break; end; end; procedure TFinderDataZN.SetADataSet(const Value: TCustomADODataSet); begin FADataSet := Value; end; procedure TFinderDataZN.SetGrid(const Value: TDBGrid); begin if FGrid <> Value then begin FGrid := Value; if FGrid <> nil then begin FGrid.FreeNotification(Self); SetSelectedColumn(GetSelectedColunm); FADataSet := TCustomADODataSet(FGrid.DataSource.DataSet); (* Cuida da associação, menu popup, associada ao DBGrid *) SetPopupMenu(FGrid.PopupMenu); (* Monta os itens de menu, os quais nos referimos na especificação do componente *) BuildMenuPopup; end; end; end; procedure TFinderDataZN.SetPopupMenu(const Value: TPopupMenu; const nAllowCreate: Boolean); begin if (FPopupMenu = Value) and (Value <> nil) then Exit; If not Assigned(Value) or (nAllowCreate) then begin FPopupMenu := TPopupMenu.Create(Self); FGrid.PopupMenu := FPopupMenu; FIsPopupExistent := peInternalCreated; end else begin FPopupMenu := Value; FIsPopupExistent := peExternalAssociation; end; if FPopupMenu <> nil then begin FPopupMenu.FreeNotification(Self); //FPopupMenu.OnPopup := PopupMenuPopup; end; end; procedure TFinderDataZN.SetSelectedColumn(const Value: TColumn); begin (* Armazena a coluna do Grid aqual foi clickada com o botão direito do mouse, para capturar informações como: Titúlo e etc.. *) FSelectedColumn := Value; if FSelectedColumn <> nil then FAFieldSearch := FSelectedColumn.Field; end; end.
Codificando as procedures que serão atribuídas aos eventos :
“procedure LocalizarClick(Sender: TObject)” para efetuará a localização do registro desejado.
“procedure PopupMenuPopup(Sender: TObject) ”, para criar o caption, o título do item de menu, referente ao registro o qual será localizado.
protected procedure CreatePopupMenuItem(const NameItem, CaptionItem: String); virtual; procedure BuildMenuPopup; virtual; procedure SetSelectedColumn(const Value: TColumn); virtual; function GetSelectedColunm: TColumn; virtual; (* Eventos que serão atribuidos dinamicamente *) procedure LocalizarClick(Sender: TObject); virtual; procedure PopupMenuPopup(Sender: TObject);
Primeiro a implementação da nova procedure que vai setar o título o item de menu dinamicamente de acordo com o título da coluna do Grid:
procedure TFinderDataZN.PopupMenuPopup(Sender: TObject); var MyMenuitem: TMenuItem; begin MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1])); if assigned(MyMenuitem) then begin SetSelectedColumn(GetSelectedColunm); MyMenuitem.Caption := Format(AMenuItemCaption, [FSelectedColumn.Title.Caption]); end; end;
A funcionalidade de Localizar precisa exibir uma janela (tela) para que o usuário digite o valor desejado. Logo, precisamos, antes de codificar criarmos um novo form. Adicione a classe um novo Form, propriedade name = “FindDataDlgFormZN”, salve a unit com o nome de “FindDataDlgFrmZN”. Segue o código do dfm do form:
object FindDataDlgFormZN: TFindDataDlgFormZN Left = 192 Top = 107 Width = 189 Height = 138 Caption = 'Localizar %s' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Label1: TLabel Left = 12 Top = 12 Width = 126 Height = 13 Caption = 'Digite o Código do Serviço' end object EdtDado: TEdit Left = 12 Top = 33 Width = 159 Height = 21 TabOrder = 0 end object PnlBottom: TPanel Left = 0 Top = 67 Width = 181 Height = 44 Align = alBottom BevelOuter = bvNone TabOrder = 1 object BtnCancel: TBitBtn Left = 100 Top = 12 Width = 75 Height = 25 TabOrder = 0 Kind = bkCancel end object BtnOk: TBitBtn Left = 12 Top = 12 Width = 75 Height = 25 TabOrder = 1 Kind = bkOK end end end
No form codifique o evento OnCloseQuery e um método público “Execute” conforme exemplificado abaixo:
unit FindDataDlgFrmZN; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls; type TFindDataDlgFormZN = class(TForm) Label1: TLabel; EdtDado: TEdit; PnlBottom: TPanel; BtnCancel: TBitBtn; BtnOk: TBitBtn; procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); private { Private declarations } public function Execute: Boolean; end; var FindDataDlgFormZN: TFindDataDlgFormZN; implementation {$R *.dfm} procedure TFindDataDlgFormZN.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if (Self.ModalResult = MrOk) and (Trim(EdtDado.Text) = '') then ModalResult := mrCancel; end; function TFindDataDlgFormZN.Execute: Boolean; begin Self.BorderStyle := bsDialog; Self.FormStyle := fsNormal; Self.Position := poMainFormCenter; Result := (Self.ShowModal = mrOk); end; end.
Implementado o procedimento que vai gerenciar a localização do registro “function InputSearchValue”.
protected procedure CreatePopupMenuItem(const NameItem, CaptionItem: String); virtual; procedure BuildMenuPopup; virtual; procedure SetSelectedColumn(const Value: TColumn); virtual; function GetSelectedColunm: TColumn; virtual; (* Eventos que serão atribuidos dinamicamente *) procedure LocalizarClick(Sender: TObject); virtual; procedure PopupMenuPopup(Sender: TObject); (*método que vai gerenciar a localização do registro *) function InputSearchValue: String; virtual; public { Public declarations } published Property ReturnValueStr: String read FReturnValueStr; Property ReturnValueNum: Double read FReturnValueNum; property Grid: TDBGrid read FGrid write SetGrid; end;
Adicione na clausula “uses” da seção “implamentation” a unit da classe “TFinderDataZN”, a unit do form que acabamos de criar. Na seção “private” defina um novo campo FAFieldSearch: TField;
procedure Register; implementation uses FindDataDlgFrmZN; const PopupMenuItemName: array [0..1] of String = ('ConfigurarGridSep', 'fdLocalizar'); AMenuItemCaption = 'Localizar %s';
var FindDataDlgForm: TFindDataDlgForm; AuxCaption: String; begin if (FADataSet.IsEmpty) then Exit; try FindDataDlgForm := TFindDataDlgForm.Create(Self); FindDataDlgForm.Caption := Format(FindDataDlgForm.Caption, [FSelectedColumn.Title.Caption]); FindDataDlgForm.Label1.Caption := FSelectedColumn.Title.Caption; if FindDataDlgForm.Execute then begin Result := FindDataDlgForm.EdtDado.Text; if FADataSet.Locate(FSelectedColumn.Field.FieldName, FindDataDlgForm.EdtDado.Text, []) then begin FAFieldSearch.FocusControl; if FGrid.CanFocus then FGrid.SetFocus end; end; finally FindDataDlgForm.Free; end;
Agora, para finalizar , o método “LocalizarClick”.
procedure TFinderDataZN.LocalizarClick(Sender: TObject); var AValue: String; AValueNum: Double; begin try AValue := InputSearchValue; except on Exception do AValue := ''; end; end;
Não esqueça de descomentar as linhas dos métodos “BuildMenuPopup” e “SetPopupMenu”.
Segue o código completo do componente:
unit FinderDataZN; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, DbGrids, ADODb, Db, Menus; type (* Para indicar a Classe se o Popup Menu foi outo-criado, ou já estava associado ao DbGrid que "foi" associado ao TFinderDataZN *) TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent); TFinderDataZN = class(TComponent) private FReturnValueNum: Double; FReturnValueStr: String; FGrid: TDBGrid; FADataSet: TCustomADODataSet; FPopupMenu: TPopupMenu; FIsPopupExistent: TPopupExistent; FSelectedColumn: TColumn; FAFieldSearch: TField; procedure SetGrid(const Value: TDBGrid); procedure SetADataSet(const Value: TCustomADODataSet); procedure SetPopupMenu(const Value: TPopupMenu; const nAllowCreate: Boolean = False); protected procedure CreatePopupMenuItem(const NameItem, CaptionItem: String); virtual; procedure BuildMenuPopup; virtual; procedure SetSelectedColumn(const Value: TColumn); virtual; function GetSelectedColunm: TColumn; virtual; (* Eventos que serão atribuidos dinamicamente *) procedure LocalizarClick(Sender: TObject); virtual; procedure PopupMenuPopup(Sender: TObject); (*método que vai gerenciar a localização do registro *) function InputSearchValue: String; virtual; public { Public declarations } published Property ReturnValueStr: String read FReturnValueStr; Property ReturnValueNum: Double read FReturnValueNum; property Grid: TDBGrid read FGrid write SetGrid; end; procedure Register; implementation uses FindDataDlgFrmZN; const PopupMenuItemName: array [0..1] of String = ('ConfigurarGridSep', 'fdLocalizar'); AMenuItemCaption = 'Localizar %s'; procedure Register; begin RegisterComponents('EstacaoZN', [TFinderDataZN]); end; { TFinderDataZN } procedure TFinderDataZN.BuildMenuPopup; var i: Integer; MyMenuitem: TMenuItem; begin (* Verifco se o componente encontra-se em run time*) if not (csDesigning in Self.ComponentState) then begin if Assigned(FPopupMenu) then begin for i := 0 to High(PopupMenuItemName) do begin if (FPopupMenu.Items.Count > 0) and (i = 0) then CreatePopupMenuItem(PopupMenuItemName[i], '-'); if (i = 1) then CreatePopupMenuItem(PopupMenuItemName[i], Format(AMenuItemCaption, [FGrid.Columns[0].Title.Caption])); end; MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1])); if assigned(MyMenuitem) then MyMenuitem.OnClick := LocalizarClick; end; end; end; procedure TFinderDataZN.CreatePopupMenuItem(const NameItem, CaptionItem: String); var MyMenuitem: TMenuItem; begin MyMenuitem := TMenuItem(Self.FindComponent(NameItem)); if not assigned(MyMenuitem) then begin MyMenuitem := TMenuItem.Create(Self); with MyMenuitem do begin Name := NameItem; Caption := CaptionItem; end; FPopupMenu.Items.Add(MyMenuitem); end; end; function TFinderDataZN.GetSelectedColunm: TColumn; var i: Integer; AuxField: TField; begin Result := nil; for i := 0 to Pred(FGrid.Columns.Count) do begin AuxField := FGrid.Columns[i].Field; if Assigned(AuxField) then if AuxField.FieldName = FGrid.SelectedField.FieldName then Result := FGrid.Columns[i]; if Assigned(Result) then Break; end; end; function TFinderDataZN.InputSearchValue: String; var FindDataDlgForm: TFindDataDlgFormZN; AuxCaption: String; begin if (FADataSet.IsEmpty) then Exit; try FindDataDlgForm := TFindDataDlgFormZN.Create(Self); FindDataDlgForm.Caption := Format(FindDataDlgForm.Caption, [FSelectedColumn.Title.Caption]); FindDataDlgForm.Label1.Caption := FSelectedColumn.Title.Caption; if FindDataDlgForm.Execute then begin Result := FindDataDlgForm.EdtDado.Text; if FADataSet.Locate(FSelectedColumn.Field.FieldName, FindDataDlgForm.EdtDado.Text, []) then begin FAFieldSearch.FocusControl; if FGrid.CanFocus then FGrid.SetFocus end; end; finally FindDataDlgForm.Free; end; end; procedure TFinderDataZN.LocalizarClick(Sender: TObject); var AValue: String; AValueNum: Double; begin try AValue := InputSearchValue; except on Exception do AValue := ''; end; end; procedure TFinderDataZN.PopupMenuPopup(Sender: TObject); var MyMenuitem: TMenuItem; begin MyMenuitem := TMenuItem(Self.FindComponent(PopupMenuItemName[1])); if assigned(MyMenuitem) then begin SetSelectedColumn(GetSelectedColunm); MyMenuitem.Caption := Format(AMenuItemCaption, [FSelectedColumn.Title.Caption]); end; end; procedure TFinderDataZN.SetADataSet(const Value: TCustomADODataSet); begin FADataSet := Value; end; procedure TFinderDataZN.SetGrid(const Value: TDBGrid); begin if FGrid <> Value then begin FGrid := Value; if FGrid <> nil then begin FGrid.FreeNotification(Self); SetSelectedColumn(GetSelectedColunm); FADataSet := TCustomADODataSet(FGrid.DataSource.DataSet); (* Cuida da associação, menu popup, associada ao DBGrid *) SetPopupMenu(FGrid.PopupMenu); (* Monta os itens de menu, os quais nos referimos na especificação do componente *) BuildMenuPopup; end; end; end; procedure TFinderDataZN.SetPopupMenu(const Value: TPopupMenu; const nAllowCreate: Boolean); begin if (FPopupMenu = Value) and (Value <> nil) then Exit; If not Assigned(Value) or (nAllowCreate) then begin FPopupMenu := TPopupMenu.Create(Self); FGrid.PopupMenu := FPopupMenu; FIsPopupExistent := peInternalCreated; end else begin FPopupMenu := Value; FIsPopupExistent := peExternalAssociation; end; if FPopupMenu <> nil then begin FPopupMenu.FreeNotification(Self); FPopupMenu.OnPopup := PopupMenuPopup; end; end; procedure TFinderDataZN.SetSelectedColumn(const Value: TColumn); begin (* Armazena a coluna do Grid aqual foi clickada com o botão direito do mouse, para capturar informações como: Titúlo e etc.. *) FSelectedColumn := Value; if FSelectedColumn <> nil then FAFieldSearch := FSelectedColumn.Field; end; end.
Nenhum comentário:
Postar um comentário