Olá Galera, vamos ver neste artigo um pouco sobre classes. Vou mostrar como criar uma classe do zero, e explicar o que o Delphi faz quando usamos CTRL + SHIF + C ( Comando para implementar as propriedades e Métodos de uma determinada classe ). Inicialmente vamos criar uma Classe chamada de TCliente, para isso criarmos uma unit, e vamos salvar seu nome como uCliente.pas unit uCliente; interface implementation end.
Neste momento vamos criar a classe Veja no código abaixo, como vamos criar a classe no Delphi. unit uCliente; interface Type TCliente = class private protected public published end;
implementation end.
Criaremos agora as propriedades básicas da Classe TCliente, ID, Nome, Sexo, CPF, RG, Telefone, Endereco, Bairro, Cidade, CEP.
Veja o código como ficará.
unit uCliente; interface Type TCliente = class private protected public published end; implementation end.
Vamos criar as propriedades básicas da Classe TCliente, ID, Nome, Sexo, CPF, RG, Telefone, Endereco, Bairro, Cidade, CEP. Veja o código como ficará unit uCliente; interface Type TCliente = class private protected public property property property property property property property property property property
ID Nome Sexo CPF RG Telefone Endereco Bairro Cidade CEP
published end; implementation end.
:String; :String; :String; :String; :String; :String; :String; :String; :String; :String;
Ao final da digitação da property CEP: String, iremos usar a combinação de teclas CTRL + SHIF + C, para implementar a classe. Seu código agora irá modificar complementa, incluindo várias procedures e Fields. Vamos analisar como ficou o código. unit uCliente; interface Type TCliente = class private FNome: String; FBairro: String; FCEP: String; FID: String; FCPF: String; FSexo: String; FCidade: String; FEndereco: String; FTelefone: String; FRG: String; procedure SetBairro(const Value: String); procedure SetCEP(const Value: String); procedure SetCidade(const Value: String); procedure SetCPF(const Value: String); procedure SetEndereco(const Value: String); procedure SetID(const Value: String); procedure SetNome(const Value: String); procedure SetRG(const Value: String); procedure SetSexo(const Value: String); procedure SetTelefone(const Value: String); protected public property property property property property property property property property property published end;
ID Nome Sexo CPF RG Telefone Endereco Bairro Cidade CEP
:String :String :String :String :String :String :String :String :String :String
read read read read read read read read read read
FID write SetID; FNome write SetNome; FSexo write SetSexo; FCPF write SetCPF; FRG write SetRG; FTelefone write SetTelefone; FEndereco write SetEndereco; FBairro write SetBairro; FCidade write SetCidade; FCEP write SetCEP;
implementation { TCliente } procedure TCliente.SetBairro(const Value: String); begin FBairro := Value; end; procedure TCliente.SetCEP(const Value: String); begin FCEP := Value; end; procedure TCliente.SetCidade(const Value: String); begin FCidade := Value; end; procedure TCliente.SetCPF(const Value: String); begin FCPF := Value; end; procedure TCliente.SetEndereco(const Value: String); begin FEndereco := Value; end; procedure TCliente.SetID(const Value: String); begin FID := Value; end; procedure TCliente.SetNome(const Value: String); begin FNome := Value; end; procedure TCliente.SetRG(const Value: String); begin FRG := Value; end; procedure TCliente.SetSexo(const Value: String); begin FSexo := Value; end; procedure TCliente.SetTelefone(const Value: String); begin FTelefone := Value; end; end.
O que houve? Para cada property criada, por exemplo:
property ID
:String; . O Delphi
criou 2 métodos de leitura(Read) e escrita(Write) : property ID
:String
read FID write SetID; , onde: FID = Field para armazenar o valor passado para propriedade SetID = Procedure para validar por exemplo um ID já existe, ou então se o CPF é válido, e logo em seguida atribuir o conteúdo informado para o Field FID, veja como o Delphi implementa o SetID; procedure TCliente.SetID(const Value: String); begin FID := Value; end;
Com este método o parâmetro Const(não pode ser alterado dentro do método) Value contém o valor informado quando usamos por exemplo : Procedure TFrmCliente.Novo; begin Cliente.ID := 1; End;
Sendo assim, o que este método SetID faz simplesmente é armazenar o Value em FID, como a linha abaixo mostra : FID := Value
O código fica bem grande, dando a entender que fizemos muitas implementações e tudo mais, porém fizemos alguma validação com os campos ? Fizemos alguma regra de negocio ? NÃO!!!
Vamos implementar uma regra básica para entendermos como fazer e depois adaptar. Supondo que gostaríamos de validar a quantidade de caracteres de um CPF, contando os pontos e traço. Sendo assim teríamos 14 caracteres, como um exemplo 123.456.789-01. Usando a função Length , encontrada na unit System, podemos ver o tamanho de uma string, veja como ficaria o código para saber se foi informado 14 caracteres ou não. procedure TCliente.SetCPF(const Value: String); begin If Length(Value) = 14 Then FCPF := Value else raise Exception.Create('CPF inválido, número de caracteres maior ou menor que 14'); //Para usar o Exception devemos dar uses em SysUtils; end;
Com isso temos uma suposta regra de negócios, onde o CPF tem que 14 caracteres, nem a mais, nem a menos. Voltando então a pergunta inicial, temos regras de negocio nesta nossa classe de Cliente ? Inicialmente não , então não precisamos ter procedures SetID, SetNome,SetCPF,Set.... O que vou fazer é bem simples , mas requer muita atenção. Inicialmente vamos apagar todas as procedures declaradas e implementadas. Feito isso seu código ficará assim : unit uCliente; interface uses SysUtils; Type TCliente = class private FNome: String; FBairro: String; FCEP: String; FID: String; FCPF: String; FSexo: String;
FCidade: String; FEndereco: String; FTelefone: String; FRG: String; {REMOVEMOS AS DECLARAÇÕES DAS PROCEDURES DAQUI } protected public property property property property property property property property property property
ID Nome Sexo CPF RG Telefone Endereco Bairro Cidade CEP
:String :String :String :String :String :String :String :String :String :String
read read read read read read read read read read
FID write SetID; FNome write SetNome; FSexo write SetSexo; FCPF write SetCPF; FRG write SetRG; FTelefone write SetTelefone; FEndereco write SetEndereco; FBairro write SetBairro; FCidade write SetCidade; FCEP write SetCEP;
published end; implementation
{REMOVEMOS AS IMPLEMENTAÇÕES DAS PROCEDURES DAQUI }
end.
Já esta pronto ? Não!! Falta agora remover o método de escrita(Write) nas propertys e modificar para escrever diretamente nos Fields, mas como assim? Veja abaixo o código unit uCliente; interface Type TCliente = class private FNome: String; FBairro: String; FCEP: String; FID: String; FCPF: String; FSexo: String; FCidade: String; FEndereco: String; FTelefone: String; FRG: String; protected
public {Observe que onde esta SetID, SetNome, Set... Foi modificado agora para FID, FNome,F...} property property property property property property property property property property
ID Nome Sexo CPF RG Telefone Endereco Bairro Cidade CEP
:String :String :String :String :String :String :String :String :String :String
read read read read read read read read read read
FID write FID; FNome write FNome; FSexo write FSexo; FCPF write FCPF; FRG write FRG; FTelefone write FTelefone; FEndereco write FEndereco; FBairro write FBairro; FCidade write FCidade; FCEP write FCEP;
published end; implementation end.
Como vocês podem ver a Unit fica mais limpa, a classe fica bem mais simples de se visualizar e dar manutenção, agora atenção, isso é se você não tiver regras de negocio para suas propertys ok? Caso tenha você faz como o Delphi implementa, cria a procedure, associa ela ao Write da property e implementa ela com sua regra de negócio. Ficará então da seguinte forma com a única regra de negocio que criamos, a do tamanho do CPF unit uCliente; interface uses SysUtils; Type TCliente = class private FNome: String; FBairro: String; FCEP: String; FID: String; FCPF: String; FSexo: String; FCidade: String; FEndereco: String; FTelefone: String; FRG: String; {Metodo de validação do CPF}
procedure SetCPF(const Value: String); protected public property property property {Property property property property property property property property
ID :String Nome :String Sexo :String CPF agora tem um CPF :String RG :String Telefone :String Endereco :String Bairro :String Cidade :String CEP :String
read FID write FID; read FNome write FNome; read FSexo write FSexo; mecanismo de validação para sua escrita} read FCPF write SetCPF; read FRG write FRG; read FTelefone write FTelefone; read FEndereco write FEndereco; read FBairro write FBairro; read FCidade write FCidade; read FCEP write FCEP;
published end; implementation
{ TCliente }
procedure TCliente.SetCPF(const Value: String); begin If Length(Value) = 14 Then FCPF := Value else raise Exception.Create('CPF inválido, número de caracteres maior ou menor que 14'); end;
end.
Para usar sua classe e testar, faça o seguinte: crie um form e coloque um BitBtn. Precisamos dar Uses em uCliente para poder acessar a Classe TCliente. Feito isso, no evento onClick do BitBtn, implemente o seguinte : procedure TFrmCliente.BtnNovoClick(Sender: TObject); Var C: TCliente; Begin C := TCliente.Create; C.Nome:= 'WESLEY YAMAZACK' ; C.Bairro:= 'CENTRO' ; C.CEP:= '216548-856 ' ;
C.ID:= '00005' ; C.CPF := '123.456.789-100' ; // Deste jeito você vera o erro C.CPF := '123.456.789-10' ; // Deste jeito irá funcionar C.Sexo:= 'M' ; C.Cidade:= 'RIO DE JANEIRO ' ; C.Endereco:= 'RUA M, N 145, APTO 809' ; C.Telefone:= '(21)3222-1111 ' ; C.RG:= '12.313.214-1' ; C.Free; end;
POO e DAO Pattern no Delphi: Criando uma tela de login Veja neste artigo como utilizar de maneira prática assuntos como Programação Orientada a Objetos, DAO Pattern, e o framework DbExpress 4, assuntos muito importantes dentro da comunidade Delphi.
Introdução A POO (Programação Orientada a Objetos), cujos pilares básicos são: Herança,
Polimorfimo e Encapsulamento, é uma metodologia inteligente de desenvolvimento de software, que visa tornar os sistemas mais flexiveis a mudanças, fáceis de manter, e permite uma grande reutilização de código. Um dos problemas encontrados em sistemas escritos de maneira procedural é a descentralização de responsabilidades (regras de negócio misturadas a camada de apresentação), onde o mesmo código aparece repetidas vezes em diferentes pontos do sistema, tornando o custo de manutenção cada vez maior. Não são raros os casos de empresas que precisaram reescrever sistemas do zero por tais problemas. Para corrigir este problema, podemos utilizar a POO em conjunto com o Design Pattern DAO. O Padrão DAO (Data Access Object) é um pattern que permite separar acesso a dados e regras de negócio da camada de apresentação, centralizando as responsabilidades de manipulação do banco de dados e facilitando a manutenção. Neste tutorial criaremos um sistema simples de Login, utilizando conceitos de programação orientada a objetos e separação de camadas com DAO Pattern, utilizando a linguagem e IDE Delphi. O Delphi é uma linguagem de alto nível, compilada, fortemente tipada, que suporta os paradigmas de programação estruturada e orientada a objetos, sendo uma excelente ferramenta de desenvolvimento. Para esse artigo foi utilizado o Delphi XE e banco de dados Firebird 2.5
Criação do Projeto Crie um novo diretório, onde serão salvos o Banco de Dados (caso use firebird/interbase) e os arquivos do Projeto. Utilizando o Banco de Dados e o Front End de sua preferência, crie um novo banco e execute os scripts abaixo para criação da tabela Usuarios, e o usuario administrador, respectivamente:
Listagem 1: Scripts do Banco de Dados // Criação da tabela USUARIOS CREATE TABLE USUARIOS ( CODIGO
INTEGER NOT NULL,
USUARIO
VARCHAR(20) NOT NULL,
SENHA
VARCHAR(20) NOT NULL,
CONSTRAINT PK_USUARIOS PRIMARY KEY (CODIGO) )
// INSERT do primeiro Usuario da tabela INSERT INTO USUARIOS (CODIGO, USUARIO, SENHA) VALUES (1,’administrador’,’admin123’)
Utilizando o Delphi, crie um novo projeto no Menu New -> VCL Forms Application – Delphi. Adicione uma nova Unit ao projeto no Menu New -> Unit –Delphi. Iremos utilizar a nova Unit para criação da classe TLoginModel, que será responsável por transferir informações entre a camada de negócios e a camada de apresentação. A classe TLoginModel possui dois campos, que são: FUsuario e FSenha. Respeitando as boas práticas de POO, não iremos expor publicamente nossos campos, mas iremos encapsular o acesso a eles utilizando métodos getters, setters e propriedades. Listagem 2: Class TLoginModel unit uLoginModel;
interface Type TLoginModel = class strict private // campos
FUsuario: string; FSenha: string;
// getters function GetUsuario: string; function GetSenha: string;
// setters procedure SetUsuario(const Value: string); procedure SetSenha(const Value: string);
public // propriedades property Usuario : string read GetUsuario write SetUsuario; property Senha : string read GetSenha write SetSenha; end;
implementation
{ TLoginModel }
function TLoginModel.GetSenha: string; begin Result := FSenha; end;
function TLoginModel.GetUsuario: string; begin Result := FUsuario;
end; procedure TLoginModel.SetSenha(const Value: string); begin FSenha := Value; end;
procedure TLoginModel.SetUsuario(const Value: string); begin FUsuario := Value; end; end.
Volte ao formulário da aplicação e altere a propriedade Name para frmLogin. Utilizando a Tool Palette, adicione os seguintes controles:
3 Labels; 2 Edits; 2 Buttons.
Altere a propriedade Name dos controle para:
3 Labels (lblTitulo, lblUsuario, lblSenha); 2 Edits (edtUsuario, edtSenha); 2 Buttons (btnLogar, btnSair);
Organize o formulário e altere a propriedade Caption dos controle conforme a imagem abaixo:
Figura 1: Formulário frmLogin Utilizando o menu New, adicione um Data Module ao seu projeto. Adicione um controle do tipo SQLConnection da paleta DbExpress, que será usado para criar uma conexão com o Banco de Dados. Configure o controle SQLConnection de acordo de o caminho do seu banco. Defina a propriedade LoginPrompt como False para que a senha do banco não seja solicitada novamente a cada nova conexão. Altere a propriedade Name do Data Module para dm_dados e a propriedade Name SQLConnection para LOGINOO. Salve o projeto e as units no diretório criado no início do artigo, seguindo a nomenclatura:
Formulário Login - uFrmLogin; Unit Login Model - uLoginModel; Data Module - uDm_Dados; Nome do Projeto – LOGINOO;
Inclua uma nova Unit no Menu New -> Unit –Delphi.
Salve a nova Unit criada como uLoginDAO. A classe TLoginDAO será usada para centralizar as regras de negócio e o acesso ao banco de dados. Para nossa classe TLoginDAO, utilizaremos métodos do framework DbExpress 4, que é a engine de acesso e manipulação de dados mais utilizada pelos programadores Delphi. A nova arquitetura do DbExpress 4 traz novas features que permitem um desenvolvimento totalmente orientado a objetos, de maneira simples e elegante. Digite as informações da classe TLoginDAO, e não esqueça de dar uses nas Units uLoginModel, DBXCommon, SysUtils. Listagem 3: Classe TLoginDAO unit uLoginDAO;
interface
uses uLoginModel, DBXCommon, SysUtils;
type TLoginDAO = class
public // função Logar passando um objeto LoginModel como parâmetro function Logar(LoginModel: TLoginModel): Boolean; end;
implementation
uses Dialogs;
{ TLoginDAO }
function TLoginDAO.Logar(LoginModel: TLoginModel): Boolean; var dbcon
: TDBXConnection; // objeto para conexao
sql
: TDBXCommand;
// objeto para executar instruçoes SQL
parametro : TDBXParameter; // objeto para parametrizar instruçao SQL reader : TDBXReader; // objeto que guarda o resultado de um TDBXCommand; begin try try
// fabrica uma conexão com o banco dbcon:=TDBXConnectionFactory.GetConnectionFactory.GetConnection('L OGINOO', 'sysdba','masterkey'); // cria um comando sql no objeto dbcon sql := dbcon.CreateCommand; // instrução SQL sql.Text := 'SELECT * FROM USUARIOS WHERE UPPER(USUARIO) = UPPER(?) ' + ' AND UPPER(SENHA) = UPPER(?)';
// parametro Usuario parametro := sql.CreateParameter; parametro.DataType := TDBXDataTypes.WideStringType; parametro.Name := 'pUsuario'; sql.Parameters.AddParameter(parametro); sql.Parameters.Parameter[0].Value.SetWideString(LoginModel.Usuario );
// parametro Senha parametro := sql.CreateParameter; parametro.DataType := TDBXDataTypes.WideStringType; parametro.Name := 'pSenha'; sql.Parameters.AddParameter(parametro); sql.Parameters.Parameter[1].Value.SetWideString(LoginModel.Senha);
sql.Prepare; // prepara a instrução SQL para executar no Banco reader := sql.ExecuteQuery; // executa o SQL e guarda o resultado no reader;
while (reader.Next) do // retorna True se o reader não estiver vazio Result := True;
except on E : Exception do ShowMessage('Não foi possível logar no sistema' + #13 + E.Message); end; finally // libera os objetos da memória FreeAndNil(dbcon); FreeAndNil(sql); FreeAndNil(reader); end; end; end.
Passaremos agora à codificação do formulário de nossa aplicação. Adicione o seguinte código ao evento OnClick do botão btnLogar: Listagem 4: Evento OnClick do Botão btnLogar
procedure TfrmLogin.btnLogarClick(Sender: TObject); var LoginModel: TLoginModel; LoginDAO: TLoginDAO; begin LoginModel := TLoginModel.Create; // cria o objeto LoginModel na Memória LoginDAO := TLoginDAO.Create; // cria o objeto LoginDAO na Memória
// verifica se há algum edit em branco if (edtUsuario.Text = '') or (edtSenha.Text = '') then raise Exception.Create('Digite usuário e senha') else begin try LoginModel.Usuario := edtUsuario.Text; LoginModel.Senha := edtSenha.Text; if LoginDAO.Logar(LoginModel) then begin ShowMessage('Acesso Autorizado'); end else ShowMessage('Acesso não liberado'); finally // libera os objetos da memória FreeAndNil(LoginModel); FreeAndNil(LoginDAO); end; end; end;
No evento OnClick do botão btnSair, digite o seguinte o seguinte comando: Listagem 5: Evento OnClick do Botão btnSair procedure TfrmLogin.btnSairClick(Sender: TObject); begin Application.Terminate; // encerra a aplicação; end;
conclusão
A programação orientada a objetos e a aplicação do DAO Pattern melhoram em muito a qualidade de nosso código. Este é apenas um exemplo de como criar aplicações orientadas a objetos no Delphi. Teste o código, refatore e otimize este exemplo. Um abraço.
POO na prática com Delphi - SimpleMasterDetail 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; implementation { TConn }
constructor Create;
end;
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 FNome: string; FChave: integer;
FObs: string;
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 SQL.Text :=
begin
Close;
' 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;
ExecSQL; except
Result := true; 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);
try
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 SQL.Text
begin
Close;
:= ' delete from Clientes'+ ' where id = :Chave';
Parameters.ParamByName('Chave').Value := Chave; try ExecSQL; except
Result := True;
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 Nome
begin
:= 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').asintege r)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 Clientes cliente
:= TConn.Create; // Cria a conexão e conecta := TClientes.Create(Conn); // cria o objeto
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 )
Observações: 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 unituCompras: 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;
Result := False;
end;
except 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 SQL.Text
begin Close; := ' delete from Compras'+ ' where id = :Chave';
Parameters.ParamByName('Chave').Value := Chave; try ExecSQL;
Result := True;
Result := False;
end;
except 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').AsInt eger) 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 unitufrmInsereCompra: unit ufrmInsereCompra; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ImgList, Buttons, ExtCtrls; type TfrmInsereCompra = class(TForm) lblClienteSelecionado: TLabel;
Label1: TLabel; BitBtn1: TBitBtn;
RgProdutos: TRadioGroup; procedure FormCreate(Sender: TObject); BitBtn1Click(Sender: TObject);
procedure
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'; 30,00'; end; 1 : begin
valor
Produto := 'Sabão em pó'; end;
:= 'R$
valor
:= 'R$ 150,00';
2 : begin
Produto := 'Galinha Caipira'; end; 3 : begin
valor
:= 'R$
80,00';
Produto := 'Revista Playboy'; end; end; // end case
valor
:= 'R$
50,00'; 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.field byname('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.