POO na prática com Delphi - SimpleMasterDetail

Neste artigo mostramos como criar uma tela simples com MasterDetail orientada a objetos no Delphi.

Olá pessoal, neste artigo mostrarei de forma prática e direta como é fácil utilizar POO no Delphi, criaremos uma classe para conexão e uma classe de clientes para realizar as operações de Select, Insert, Update e Delete no banco. A POO (Programação Orientada a Objetos) facilita e muito a manutenção e o reaproveitamento de código, sendo ainda fácil de se entender e aplicar, vamos pôr a mão na massa?

Crie um banco de dados com uma tabela chamada Clientes:

// Observe que o campo id é auto incremento CREATE TABLE Clientes( id int IDENTITY(1,1) NOT NULL, Nome varchar(50), Endereco varchar(50), Telefones varchar(50), Obs varchar(200) )

Tabela construída vamos agora para a construção de nossa classe de conexão, (File > New > Unit). Nesta eu utilizei ADO, observe abaixo a unit uConn:

unit uConn; interface uses ADODB; type TConn = class public Conn : TADOConnection; constructor Create; end; implementation { TConn } constructor TConn.Create; begin Conn := TADOConnection.Create(nil); Conn.LoginPrompt := false; Conn.ConnectionString := 'Provider=SQLOLEDB.1'+ ';Password=XXXXX'+ ';Persist Security Info=False'+ ';User ID=XXXXX'+ ';Initial Catalog=Clientes'+ ';Data Source=QD_08'; Conn.Connected := true; end; end.

Observe que na classe TConn o create é o único método disponível, e no mesmo a conexão já é realizada, claro, você pode e deve implementar outros métodos nesta classe como capturar a string de conexão de um arquivo ini ou xml, mas como a intenção aqui e mostrar os primeiros passos POO no Delphi fiz de forma reduzida.

Agora vamos a classe de Clientes (File > New > Unit), observe abaixo a unit uClientes:

unit uClientes; interface uses ADODB, DB, SysUtils, uConn; type TClientes = class private FObs: string; FNome: string; FChave: integer; FEndereco: string; FTelefone: string; FQry: TADOQuery; FDs: TDataSource; Conexao : TConn; FDsPesquisa: tDataSource; FQryPesquisa: TADOQuery; procedure SetChave(const Value: integer); procedure SetEndereco(const Value: string); procedure SetNome(const Value: string); procedure SetObs(const Value: string); procedure SetTelefone(const Value: string); procedure SetDs(const Value: TDataSource);7 procedure SetQry(const Value: TADOQuery); procedure SetDsPesquisa(const Value: tDataSource); procedure SetQryPesquisa(const Value: TADOQuery); published public constructor Create(Conn: TConn); // utiliza a classe de conexão // Propriedades property Chave : integer read FChave write SetChave; property Nome : string read FNome write SetNome; property Endereco : string read FEndereco write SetEndereco; property Telefone : string read FTelefone write SetTelefone; property Obs : string read FObs write SetObs; // Componentes property Qry : TADOQuery read FQry write SetQry; property QryPesquisa : TADOQuery read FQryPesquisa write SetQryPesquisa; property Ds : TDataSource read FDs write SetDs; property DsPesquisa : tDataSource read FDsPesquisa write SetDsPesquisa; // Métodos function Selecionar(Chave: Integer; Nome,Ordem: String):Boolean; function Inserir : boolean; function Alterar : boolean; function Deletar(chave: integer) : boolean; end; implementation { TClientes } function TClientes.Alterar: boolean; begin with Qry do begin Close; SQL.Text := ' Update Clientes Set '+ ' Nome = :Nome,'+ ' Endereco = :Endereco,'+ ' Telefones = :Telefones,'+ ' Obs = :Obs'+ ' Where '+ ' id = :id'; // Observe a utilização dos Fileds (FChave,Fnome...etc...) Parameters.ParamByName('id').Value := FChave; Parameters.ParamByName('Nome').Value := Fnome; Parameters.ParamByName('Endereco').Value := Fendereco; Parameters.ParamByName('Telefones').Value := FTelefone; Parameters.ParamByName('Obs').Value := FObs; try ExecSQL; Result := true; except Result := False; end; end; end; constructor TClientes.Create(Conn: TConn); begin { No create é passada a conection das Qrys } Conexao := Conn; Qry := TADOQuery.Create(nil); Ds := TDataSource.Create(nil); QryPesquisa := TADOQuery.Create(nil); DsPesquisa := TDataSource.Create(nil); Qry.Connection := Conexao.Conn; QryPesquisa.Connection := Conexao.Conn; Ds.DataSet := Qry; DsPesquisa.DataSet := QryPesquisa; end; function TClientes.Deletar(Chave: integer): boolean; begin with Qry do begin Close; SQL.Text := ' delete from Clientes'+ ' where id = :Chave'; Parameters.ParamByName('Chave').Value := Chave; try ExecSQL; Result := True; except Result := False; end; end; end; function TClientes.Inserir: boolean; begin with Qry do begin Close; Sql.text := ' Insert into Clientes'+ ' (Nome, Endereco, Telefones, Obs)'+ ' Values '+ ' (:Nome, :Endereco, :Telefones, :Obs)'; // Observe a utilização dos Fileds (FChave,Fnome...etc...) Parameters.ParamByName('Nome').Value := Fnome; Parameters.ParamByName('Endereco').Value := Fendereco; Parameters.ParamByName('Telefones').Value := FTelefone; Parameters.ParamByName('Obs').Value := FObs; try ExecSQL; result := true; except result := false; end; end; end; function TClientes.Selecionar(Chave: Integer; Nome,Ordem: String): Boolean; begin Nome := '%'+Nome+'%'; with QryPesquisa do begin Close; Sql.Text := ' Select * from Clientes where 1=1 '; if Chave > 0 then begin Sql.add(' and id = :Chave'); Parameters.ParamByName('Chave').Value := Chave; end; if Nome <> '' then sql.add(' and Nome like '+quotedstr(Nome)); if Ordem <> '' then sql.add(' Order by '+Ordem); try Open; if not eof then Result := true else Result := false; except Result := false; end; end; end; procedure TClientes.SetChave(const Value: integer); begin FChave := Value; end; procedure TClientes.SetDs(const Value: TDataSource); begin FDs := Value; end; procedure TClientes.SetDsPesquisa(const Value: tDataSource); begin FDsPesquisa := Value; end; procedure TClientes.SetEndereco(const Value: string); begin FEndereco := Value; end; procedure TClientes.SetNome(const Value: string); begin FNome := Value; end; procedure TClientes.SetObs(const Value: string); begin FObs := Value; end; procedure TClientes.SetQry(const Value: TADOQuery); begin FQry := Value; end; procedure TClientes.SetQryPesquisa(const Value: TADOQuery); begin FQryPesquisa := Value; end; procedure TClientes.SetTelefone(const Value: string); begin FTelefone := Value; end; end.

Observem que esta classe é simples e só contém métodos com SQL, estes métodos são usados na nossa tela. Na Figura 1 segue uma sugestão de layout para a tela.

Figura 1. Sugestão de layout

Observe abaixo o código do formulário, note que no create do mesmo instanciei nossas classes e já realizei um select para carregar o grid. Código da unit ufrmPrincipal:

unit ufrmPrincipal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uConn, StdCtrls, Buttons, Grids, DBGrids, ExtCtrls, DBCtrls, ComCtrls, uClientes; type TfrmPrincipal = class(TForm) PageControl1: TPageControl; TabSheet1: TTabSheet; TabSheet2: TTabSheet; TabSheet3: TTabSheet; TabSheet4: TTabSheet; Label1: TLabel; DBNavigator1: TDBNavigator; DBGrid1: TDBGrid; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; edtNome: TEdit; edtEndereco: TEdit; edtTelefone: TEdit; mmoObs: TMemo; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; BitBtn1: TBitBtn; BitBtn2: TBitBtn; mmoUPObs: TMemo; edtUpTelefones: TEdit; Label10: TLabel; Label11: TLabel; edtUpEndereco: TEdit; Label12: TLabel; Label13: TLabel; edtUpNome: TEdit; Label14: TLabel; edtClienteDel: TEdit; BitBtn3: TBitBtn; Label15: TLabel; procedure BitBtn1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure DBGrid1CellClick(Column: TColumn); procedure BitBtn2Click(Sender: TObject); procedure DBGrid1DblClick(Sender: TObject); procedure PageControl1Change(Sender: TObject); procedure BitBtn3Click(Sender: TObject); procedure Label15MouseLeave(Sender: TObject); procedure Label15MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Label15Click(Sender: TObject); private { Private declarations } procedure LimpaCampos; public { Public declarations } end; var frmPrincipal: TfrmPrincipal; Conn : TConn; Clientes : TClientes; implementation uses DB, ufrmSplashSobre; {$R *.dfm} procedure TfrmPrincipal.BitBtn1Click(Sender: TObject); begin if edtNome.text = '' then exit; with Clientes do // preeencho as properties begin Nome := edtNome.text; Endereco := edtEndereco.text; Telefone := edtTelefone.text; Obs := mmoObs.Text; if Inserir then // operação incluir begin Application.MessageBox('Registro incluido com sucesso!','Confirmação',MB_OK); end else begin Application.MessageBox('O registro não foi incluído!','Atenção',MB_OK); end; end; LimpaCampos; end; procedure TfrmPrincipal.BitBtn2Click(Sender: TObject); begin if edtUpNome.text = '' then exit; with Clientes do // preeencho as properties begin Chave := DBGrid1.DataSource.DataSet.FieldByName('id').AsInteger; Nome := edtUpNome.text; Endereco := edtUpEndereco.text; Telefone := edtUpTelefones.text; Obs := mmoUpObs.Text; if Alterar then // operação alterar begin Application.MessageBox('Registro alterado com sucesso!','Confirmação',MB_OK); end else begin Application.MessageBox('O registro não foi alterado!','Atenção',MB_OK); end; end; LimpaCampos; end; procedure TfrmPrincipal.BitBtn3Click(Sender: TObject); begin if edtClienteDel.text = '' then exit; if clientes.Deletar(DBGrid1.DataSource.DataSet.FieldByName('id').asinteger)then begin Application.MessageBox('Registro deletado com sucesso!','Atenção',MB_OK); end else begin Application.MessageBox('O registro não foi deletado!','Atenção',MB_OK); end; LimpaCampos; end; procedure TfrmPrincipal.DBGrid1CellClick(Column: TColumn); begin // carrega dados na tela de update e delete edtUpNome.text := DBGrid1.DataSource.DataSet.FieldByName('Nome').asstring; edtUpEndereco.text := DBGrid1.DataSource.DataSet.FieldByName('Endereco').asstring; edtUpTelefones.text := DBGrid1.DataSource.DataSet.FieldByName('telefones').asstring; mmoUPObs.Text := DBGrid1.DataSource.DataSet.FieldByName('Obs').asstring; edtClienteDel.text := DBGrid1.DataSource.DataSet.FieldByName('Nome').asstring; end; procedure TfrmPrincipal.DBGrid1DblClick(Sender: TObject); begin // duplo click no grid leva para tela de update PageControl1.ActivePageIndex := 2; end; procedure TfrmPrincipal.FormCreate(Sender: TObject); begin Conn := TConn.Create; // Cria a conexão e conecta Clientes := TClientes.Create(Conn); // cria o objeto cliente Clientes.Selecionar(0,'','Nome'); // metodo de seleção de cliente DBGrid1.DataSource := clientes.DsPesquisa; DBNavigator1.DataSource:= Clientes.DsPesquisa; //Conn.Destroy; end; procedure TfrmPrincipal.LimpaCampos; var i : integer; // limpa edits e memos begin for I := 1 to ComponentCount -1 do begin if Components[i] is Tedit then (Components[i] as TEdit).clear; if Components[i] is TMemo then (Components[i] as TMemo).clear; end; end; procedure TfrmPrincipal.PageControl1Change(Sender: TObject); begin if PageControl1.ActivePageIndex = 0 then Clientes.Selecionar(0,'','Nome'); // refresh no grid end; procedure TfrmPrincipal.Label15MouseLeave(Sender: TObject); begin label15.Font.Style := []; // efeito link end; procedure TfrmPrincipal.Label15MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin label15.Font.Style := [fsUnderline]; // efeito link end; procedure TfrmPrincipal.Label15Click(Sender: TObject); var frmSplashSobre : TfrmSplashSobre; begin try frmSplashSobre := TfrmSplashSobre.create(application); frmSplashSobre.ShowModal; finally freeandnil(frmSplashSobre); end; end; end.

Master Detail

Agora mostraremos uma relação simples “Master Detail” com POO no Delphi. Para isso vamos construir nossa tabela de Compras, vejam o código:

CREATE TABLE Compras( id int IDENTITY(1,1) NOT NULL, Produto varchar(50), Valor varchar(50), Data varchar(50), idCliente int )
Nota: Como foi usado o SQL server 2005, o id é auto incremento. Além disso, tudo foi definido como varchar para facilitar e agilizar a construção do exemplo. Não é a forma correta, mas foi a mais rápida.

Tendo em mente que você viu o artigo anterior, neste vou implementar apenas a classe de Compras (ou vendas, fique à vontade), FILE > NEW > UNIT. Observe o código da nossa unit uCompras:

unit uCompras; interface uses ADODB, DB, SysUtils, uConn; type TCompras = class private FChave: integer; FChaveCliente: integer; FValor: string; FProduto: string; FData: string; FQry: TADOQuery; FQryPesquisa: TADOQuery; FDs: TDataSource; FDsPesquisa: tDataSource; Conexao : TConn; procedure SetChave(const Value: integer); procedure SetChaveCliente(const Value: integer); procedure SetData(const Value: string); procedure SetDs(const Value: TDataSource); procedure SetDsPesquisa(const Value: tDataSource); procedure SetProduto(const Value: string); procedure SetQry(const Value: TADOQuery); procedure SetQryPesquisa(const Value: TADOQuery); procedure SetValor(const Value: string); public constructor Create(Conn: TConn); // utiliza a classe de conexão // Propriedades property Chave : integer read FChave write SetChave; property Produto : string read FProduto write SetProduto; property Valor : string read FValor write SetValor; // ou Real property Data : string read FData write SetData; // ou TDatetime property ChaveCliente : integer read FChaveCliente write SetChaveCliente; // Componentes property Qry : TADOQuery read FQry write SetQry; property QryPesquisa : TADOQuery read FQryPesquisa write SetQryPesquisa; property Ds : TDataSource read FDs write SetDs; property DsPesquisa : tDataSource read FDsPesquisa write SetDsPesquisa; // Métodos function Selecionar(Chave,ChaveCliente: Integer; Produto,Ordem: String):Boolean; function Inserir : boolean; function Alterar : boolean; function Deletar(chave: integer) : boolean; end; implementation { TCompras } function TCompras.Alterar: boolean; begin with Qry do begin Close; SQL.Text := ' Update Compras Set '+ ' Produto = :Produto,'+ ' Valor = :Valor,'+ ' Data = :Data,'+ ' idCliente = :idCliente'+ ' Where '+ ' id = :id'; // Observe a utilização dos Fileds (FChave,Fnome...etc...) Parameters.ParamByName('id').Value := FChave; Parameters.ParamByName('Produto').Value := FProduto; Parameters.ParamByName('Valor').Value := FValor; Parameters.ParamByName('Data').Value := FData; Parameters.ParamByName('idCliente').Value := ChaveCliente; try ExecSQL; Result := true; except Result := False; end; end; end; constructor TCompras.Create(Conn: TConn); begin { No create é passada a conection das Qrys } Conexao := Conn; Qry := TADOQuery.Create(nil); Ds := TDataSource.Create(nil); QryPesquisa := TADOQuery.Create(nil); DsPesquisa := TDataSource.Create(nil); Qry.Connection := Conexao.Conn; QryPesquisa.Connection := Conexao.Conn; Ds.DataSet := Qry; DsPesquisa.DataSet := QryPesquisa; end; function TCompras.Deletar(chave: integer): boolean; begin with Qry do begin Close; SQL.Text := ' delete from Compras'+ ' where id = :Chave'; Parameters.ParamByName('Chave').Value := Chave; try ExecSQL; Result := True; except Result := False; end; end; end; function TCompras.Inserir: boolean; begin with Qry do begin Close; Sql.text := ' Insert into Compras'+ ' (Produto, Valor, Data, idCliente)'+ ' Values '+ ' (:Produto, :Valor, :Data, :idCliente)'; // Observe a utilização dos Fileds (FChave,Fnome...etc...) Parameters.ParamByName('Produto').Value := FProduto; Parameters.ParamByName('Valor').Value := FValor; Parameters.ParamByName('Data').Value := FData; Parameters.ParamByName('idCliente').Value := ChaveCliente; try ExecSQL; result := true; except result := false; end; end; end; function TCompras.Selecionar(Chave,ChaveCliente: Integer; Produto, Ordem: String): Boolean; begin {Observe que posso buscar por id da compra ou id do cliente} Produto := '%'+Produto+'%'; with QryPesquisa do begin Close; Sql.Text := ' Select * from Compras where 1=1 '; if Chave > 0 then begin Sql.add(' and id = :Chave'); Parameters.ParamByName('Chave').Value := Chave; end; if ChaveCliente > 0 then begin Sql.add(' and idCliente = :ChaveCliente'); Parameters.ParamByName('ChaveCliente').Value := ChaveCliente; end; if Produto <> '' then sql.add(' and Produto like '+quotedstr(Produto)); if Ordem <> '' then sql.add(' Order by '+Ordem); try Open; if not eof then Result := true else Result := false; except Result := false; end; end; // end do begin with Qrypesquisa do end; procedure TCompras.SetChave(const Value: integer); begin FChave := Value; end; procedure TCompras.SetChaveCliente(const Value: integer); begin FChaveCliente := Value; end; procedure TCompras.SetData(const Value: string); begin FData := Value; end; procedure TCompras.SetDs(const Value: TDataSource); begin FDs := Value; end; procedure TCompras.SetDsPesquisa(const Value: tDataSource); begin FDsPesquisa := Value; end; procedure TCompras.SetProduto(const Value: string); begin FProduto := Value; end; procedure TCompras.SetQry(const Value: TADOQuery); begin FQry := Value; end; procedure TCompras.SetQryPesquisa(const Value: TADOQuery); begin FQryPesquisa := Value; end; procedure TCompras.SetValor(const Value: string); begin FValor := Value; end; end.

Notem que é tudo muito igual ao primeiro artigo, os métodos de SQL têm o mesmo nome, são as operações básicas do dia a dia, com esta classe criada vamos agora para criação da nossa tela, o frmPrincipal, onde teremos dois dbgrids um para exibir o cliente e outro para exibir as compras feitas pelo mesmo, observe abaixo o código da unit ufrmPrincipal:

unit ufrmPrincipal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, DBGrids, StdCtrls, ExtCtrls, DBCtrls, uConn, uClientes, uCompras, Menus, ufrmInsereCompra; type TfrmPrincipal = class(TForm) DBGridMaster: TDBGrid; DBGridDetail: TDBGrid; Label1: TLabel; Label2: TLabel; DBNavMaster: TDBNavigator; DBNavDetail: TDBNavigator; Label3: TLabel; Label4: TLabel; procedure FormCreate(Sender: TObject); procedure DBGridMasterCellClick(Column: TColumn); procedure DBGridMasterDblClick(Sender: TObject); procedure DBGridDetailDblClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var frmPrincipal: TfrmPrincipal; Conn : TConn; Cliente : TClientes; Compra : TCompras; implementation {$R *.dfm} procedure TfrmPrincipal.FormCreate(Sender: TObject); begin Conn := TConn.Create; // cria o obj de conexão e conecta Cliente := TClientes.Create(Conn); // cria o obj cliente e vicula o mesmo a conexão Compra := TCompras.Create(Conn); // cria o obj compra... Cliente.Selecionar(0,'','Nome'); DBGridMaster.DataSource := Cliente.DsPesquisa; DBNavMaster.DataSource := Cliente.DsPesquisa; DBGridDetail.DataSource := Compra.DsPesquisa; DBNavDetail.DataSource := Compra.DsPesquisa; end; procedure TfrmPrincipal.DBGridDetailDblClick(Sender: TObject); begin // deleta registro if Compra.Deletar(DBGridDetail.DataSource.DataSet.FieldByName('id').AsInteger) then begin Application.MessageBox('Registro deletado com sucesso!','Confirmação',MB_OK); end else begin Application.MessageBox('O registro não foi deletado!','Atenção',MB_OK); end; // refresh no grid Compra.Selecionar(0,DBGridMaster.DataSource.DataSet.fieldbyname('id').AsInteger,'','Produto '); end; procedure TfrmPrincipal.DBGridMasterCellClick(Column: TColumn); begin {Com um clique realiza um select na tabela de compras} Compra.Selecionar(0,DBGridMaster.DataSource.DataSet.fieldbyname('id').AsInteger,'','Produto '); end; procedure TfrmPrincipal.DBGridMasterDblClick(Sender: TObject); var frmVende : TfrmInsereCompra; begin // chama form de venda try frmVende := TfrmInsereCompra.Create(nil); frmVende.ShowModal; finally FreeandNil(frmVende); end; // end try end; end.

Observem que não estamos usando ainda a separação das camadas que é altamente recomendável, mas como este é um exemplo para introdução a POO no Delphi usamos aqui apenas a persistência e a tela, facilitando assim o aprendizado.

Seguindo então vamos criar um form para “realizar as vendas conforme o código da unit ufrmInsereCompra:

unit ufrmInsereCompra; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ImgList, Buttons, ExtCtrls; type TfrmInsereCompra = class(TForm) Label1: TLabel; lblClienteSelecionado: TLabel; BitBtn1: TBitBtn; RgProdutos: TRadioGroup; procedure FormCreate(Sender: TObject); procedure BitBtn1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; var frmInsereCompra: TfrmInsereCompra; implementation uses ufrmPrincipal, uCompras; // para ter acesso aos objetos criados la. {$R *.dfm} procedure TfrmInsereCompra.BitBtn1Click(Sender: TObject); begin with Compra do // para valores as properties begin Case RgProdutos.ItemIndex of // para exemplificar o case 0 : begin Produto := 'Corsa 1.0'; valor := 'R$ 30,00'; end; 1 : begin Produto := 'Sabão em pó'; valor := 'R$ 150,00'; end; 2 : begin Produto := 'Galinha Caipira'; valor := 'R$ 80,00'; end; 3 : begin Produto := 'Revista Playboy'; valor := 'R$ 50,00'; end; end; // end case Data := Formatdatetime('dd/mm/yyyy', date); ChaveCliente := Cliente.DsPesquisa.DataSet.fieldbyname('id').asinteger; if Inserir then // operação incluir begin Application.MessageBox('O registro incluído com sucesso !','Confirmação',MB_OK); end else begin Application.MessageBox('O registro não foi incluído!','Atenção',MB_OK); end; end; end; procedure TfrmInsereCompra.FormClose(Sender: TObject; var Action: TCloseAction); begin // antes de fechar dar um refresh no grid Compra.Selecionar(0,frmPrincipal.DBGridMaster.DataSource.DataSet.fieldbyname('id') .AsInteg er,'','Produto'); end; procedure TfrmInsereCompra.FormCreate(Sender: TObject); begin // Observem, o cliente aqui é o mesmo usado no formPrincipal... lblClienteSelecionado.Caption := Cliente.DsPesquisa.DataSet.fieldbyname('Fantasia').asstring; end; end.
Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados