sexta-feira, 23 de julho de 2010

Pesquisa entre faixa de valores com Firebird

Fonte: www.activedelphi.com.br

Caso queira abrir uma tabela do Firebird pelo Delphi, começando por exemplo, pelo registro com ID 11200 até o ID 11400, deverá usar esta procedure e chamá-la por um botão
Você poderá usar os componentes de acesso a dados de sua preferência, mas em meu caso, estou trabalhando com DBExpress (um SQLConection, um SimpleDataSet e um DataSource):
procedure TForm1.SQLFiltra(Sender: TObject);
var
  Campo1, Campo2: string;
  Ok1, Ok2: Boolean;
begin
  Campo1:=
'';
  Campo2:=
'';
  //recupera o código inicial na variável Campo1
  InputQuery(
'Código Inicial',
   
'Digite o Código onde começará a ser salvo a tabela',
    Campo1);
  //recupera o código final na variável Campo2
  InputQuery(
'Código Final',
   
'Digite o Código onde terminará a seleção para ser salvo a tabela',
    Campo2);
  //se informou os dois códigos
  if (Campo1 <> '') and (Campo2 <> '') then
  begin

    //monta o select utilizando o operador BETWEEN, que faz a pesquisa
    //entre uma faixa de valores, seja numérico, caracter ou date/hora

    SimpleDataSet1.Close;
    SimpleDataSet1.DataSet.CommandText :=
'SELECT * FROM TABELA' +
     
' WHERE CAMPOTABELA BETWEEN ' + Campo1 + ' AND ' + Campo2;
    SimpleDataSet1.Open;
  end
  else

    ShowMessage(
'Valor(es) não digitado(s)');
end;

quinta-feira, 22 de julho de 2010

Usando funções no MySQL


No nosso exemplo, criaremos e utilizaremos uma função que retornará a idade do cliente
Crie uma pequena tabela com a seguinte estrutura:

CREATE TABLE `clientes` (
`ID` int(11) NOT NULL auto_increment,
`NOME` varchar(45) default NULL,
`DATANASC` date default NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ID` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;



Inclua as linhas abaixo na tabela, ou digite suas próprias informações:


INSERT I NTO `clientes` (`ID`, `NOME`, `DATANASC`) VALUES
(1, 'SILVIO SANTOS', '1971-09-18'),
(2, 'SILLAS SANTOS', '1993-04-27');


Agora, crie a função conforme o exemplo abaixo:


CREATE FUNCTION `idade`(pDATA DATE)
RETURNS varchar(15) CHARSET latin1
NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER
COMMENT ''
Begin
DECLARE vIDADE varchar(30);
IF DATE_FORMAT(NOW( ),'00-%m-%d') >= DATE_FORMAT(pDATA,'00-%m-%d') THEN
SET @idade=DATE_FORMAT(NOW( ),'%Y')-DATE_FORMAT(pDATA,'%Y');
ELSE
SET @idade=DATE_FORMAT(NOW( ),'%Y')-DATE_FORMAT(pDATA,'%Y')-1;
END IF;
RETURN(concat(@idade,' anos'));
end;


Esta função, retornará a idade da pessoa de acordo com o campo DATANASC, da tabela ‘clientes’.
Veja que a função receberá um valor (pDATA, que no nosso exemplo será o campo ‘DATANASC’ de nossa tabela) e fará a subtração da “dat a corrente” pela data do campo DATANASC.
Dentro da função, criamos uma variável (vIDADE), onde armazenaremos o valor a ser retornado pela função. Note também que a função possui retorno do tipo String (RETURNS varchar(30)), que deverá ter o tamanho suficiente para comportar o resultado retornado. Ou seja, se o valor retornado tiver 15 caracteres, o ‘RETURNS’ da função precisa ter tamanho de 15 ou mais caracteres, senão, pode acontecer de não retornar nenhum valor.

Após ter criado a tabela, inserido as linhas na mesma e criado a função, execute a seguinte instrução:


SELECT NOME, idade(DATANASC) IDADE FROM clientes;


No SQL acima, a consulta irá retornar o Nome, e a idade assim: “XX anos”, para cada cliente.

Como você viu, utilizar funções dentro do banco de dados por ser muito mais prático do que fazê-lo dentro da aplicação (me refiro a funções para retorno de dados, claro).

Lembrando que este exemplo é apenas uma base, pois podemos criar funções para qualquer necessdiade, como: calculo de preços, juros de mora, datas, horas, concatenação de campos complexos, junções de tabelas (como nos inner, left e right joins (desde que precise retornar apenas um valor), e muito mais.

Utilizando Barras de Progresso


Nesta dica comentarei sobre dois componentes muito utilizados para montarmos barras de progresso no Delphi: o ProgressBar e o Gauge
Para fazermos uma aplicação de exemplo, insira no form de um novo projeto:
3 Componentes TLabel - Paleta Standard;
1 Componente ProgressBar - Paleta Win32;
1 Componente TGauge - Paleta Samples;
1 Componente TTimer – Paleta System;
1 Componente TButton – Paleta Standard;
2 Componentes TRadioButton – Paleta Standard;
Mude a propriedade Caption do formuláo para Barras de Progresso. Mude também a propriedade Interval do componente TTimer para 100 (ou menos) e sua propriedade Enabled para False:

Ainda com o TTimer, no seu evento OnTimer, adicione o seguinte código:
procedure TForm1.Timer1Timer(Sender: TObject);
begin  //Se o RadioButton1 estiver marcado executa o código abaixo 
  if RadioButton1.Checked then
   begin

     label2.Caption := inttostr(ProgressBar1.Position)+ '%';
     progressbar1.position := progressbar1.position+5;
     if progressbar1.position = 10 then
      begin
        Label1.caption:='Carregando Telas: '; //escreva o que quiser
        label1.Repaint;
      end;
     if progressbar1.position = 35 then
      begin
        label1.caption:='Carregando as Tabelas';
        label1.Repaint;
      end;
     if progressbar1.position = 85 then
      begin
        label1.caption:='Finalizando';
        label1.Repaint;
      end;
   end; //FIM IF RADIOBUTTON1

  //Se o RadioButton2 estiver marcado executa o código abaixo
  if RadioButton2.Checked then
   begin
     gauge1.progress := gauge1.progress+5;
     if gauge1.progress = 10 then
      begin
        Label3.caption:='Carregando Telas: '; //escreva o que quiser
        label3.Repaint;
      end;
     if gauge1.progress = 35 then
      begin
        label3.caption:='Carregando as Tabelas';
        label3.Repaint;
      end;
     if gauge1.progress = 85 then
      begin
        label3.caption:='Finalizando';
        label3.Repaint;
      end;
   end; //FIM IF RADIOBUTTON2


 end; 
Para finalizarmos, no evento OnClick do TButton, faça:
ProgressBar1.Position := 0;
  Gauge1.Progress := 0;
  Timer1.Enabled := True;
  if RadioButton1.Checked then
    while ProgressBar1.Position < 100 do
      Application.ProcessMessages;
  if RadioButton2.Checked then
    while Gauge1.Progress < 100 do
      Application.ProcessMessages;
  Timer1.Enabled := False;
Como você pode perceber, esta rotina simplesmente aumenta a posição de uma das barras de progresso em um intervalo de tempo pré definido, o que costuma ser utilizado em telas de Splash e também formuláos de consultas demoradas. Porém em operações de processamento demorados e que se sabe a quantidade de execuções (como percorrer os registros de uma tabela, por exemplo), o correto é fazermos:
//atribuir o valor máximo /qtde de processamento
  Gauge1.MaxValue := DataSet.RecordCount;
  while not DataSet.Eof do
  begin
    //processamento dos dados

    DataSet.Next;
    //ajustar a posição da barra de progresso
    Gauge1.Progress := Gauge1.Progress;
  end;


quarta-feira, 21 de julho de 2010

Listas em Memória

Fonte: www.activedelphi.com.br Tratar estruturas de dados em memória é uma alternativa técnica interessante quando se deseja velocidade no processamento, sendo, às vezes, a única alternativa que se apresenta

Por exemplo, imagine produzir um relatório com uma query envolvendo três tabelas, na ordem de milhões de linhas cada, e dispondo-se de um tempo curto e crítico. Isso pode ser conseguido se transferirmos conscientemente algum trabalho de organização e seleção de dados, para a memória.

A opção pelo tratamento consciente de dados em memória, além de aliviar o trabalho do servidor, poderá dar um aumento significativo de velocidade ao processamento.

Ou seja, são várias as situações que admitem esse tipo de solução, pois nem sempre é conveniente ou viável que se reestruture o banco de dados para atender a uma situação específica. Além disso, existem situações em que é necessária a manipulação de massas de dados que não estão sob controle de um SGBD.

O Delphi disponibiliza um poderoso dispositivo que nos auxilia no tratamento de dados, que são as listas em memória, da classe TSTRINGLIST, as quais permitem criar e manipular listas, de modo simples e eficiente.

Um objeto STRINGLIST dispõe de dois métodos que simplificam o seu uso, Sort e Find, que, combinados, fazem grande parte do trabalho.

Este artigo trata do uso prático desse recurso, e para tanto desenvolveremos 3 casos, de complexidade crescente, dando oportunidade a que sejam apresentadas algumas técnicas interessantes. Os casos são estudados a seguir.

Caso 1. Verificando se existe.

Este primeiro caso é bem simples, meramente ilustrativo dos métodos da classe.

Suponhamos uma tabela, tab_A, que desejamos filtrar, e a condição de seleção é que o dado DADO exista em um arquivo plano.

Seria equivalente ao uso da condição EXISTS, do Sql. sendo que, no nosso caso, a lista com os critérios de seleção está em um arquivo texto.

Vejamos o código, simples, para tratar a situação.

procedure TForm1.pega_do_txt;
var lista : TStringList;
   n,ind : integer;
begin

  // carrega Txt para a lista, e a ordena

  lista := TStringList.Create();
  lista.LoadFromFile('c:\revista_delphi\dado.txt');
  lista.Sorted := true;
  // o SORTED é necessário para uso do FIND, mais adiante

  // lê a tabela A, e verifica se existe o dado na lista - "n" é meramente ilustrativo
  n := 6;
  tab_A.Active := true;
  tab_A.First;
  while not tab_A.eof do
       begin
       if lista.Find(tab_A.Fields[n].Value, ind) then
          begin
          // trata linha selecionada
          end;
       tab_A.Next;
       end;
  tab_A.Active  := false;

  lista.Free;
end;

Comentários:

1. Memória ocupada: Se o arquivo texto tem 10.000 linhas, por exemplo, e o dado buscado tem 20 caracteres de comprimento, a stringlist irá ocupar algo em torno de 0,2MB apenas.

2. A propriedade SORTED foi setada por ser uma condição para o método FIND funcionar.

3. Observe que a posição do DADO na lista ficou anotada no campo ind. Isso será utilizado nos próximos exemplos.

4. Em complemento ao método loadfromfile, que foi utilizado no exemplo, existe o savetofile, que permite que os dados da lista, de uso bem simples, sejam despejados em um arquivo plano.

Caso 2. Indexando.

Suponha agora duas tabelas. Na primeira, tab_A, existe um campo, COD que servirá para buscar um DADO na segunda tabela, tab_B.

Na tab_B, existem dois campos: COD e DADO. Esse dado será recuperado de tab_B sempre que COD for encontrado.

Ou seja: toma-se COD de A e procura-se em B: se encontrado, recupera-se DADO.

O programa fica assim: os dois campos da tabela B, COD e DADO, são carregados em listas na memória; em seguida, para cada linha da tabela A, pesquisa-se COD na lista B, recuperando-se o dado DADO.

(Vamos modificar o exemplo anterior, acrescentando mais uma lista, ficando uma para COD, e outra para DADO. Também, as tabelas serão lidas do banco de dados, e não mais de um arquivo texto.)

Mas, agora surge um problema: se carregarmos as duas listas distintas, e em seguida fizermos a ordenação, perdem-se as relações entre as posições dos itens das duas. Para evitar isso, usaremos duas técnicas diferentes, a seguir:

- alternativa 1: ordenando as duas listas juntas

Uma alternativa é agregar COD + DADO numa só lista, ordenar, e em seguida, desmembrar em duas listas, que manterão a posição relativa entre os itens. O desmembramento é necessário porque, se mantivéssemos os dados agregados, o FIND não iria encontrá-los.

Esquematicamente, fica assim:

Figura 1 - Ordenação das duas listas como um todo (juntas em uma única lista)

No passo I, são agregados COD e DADO numa só lista; No passo II, COD + DADO é ordenado, e;

No passo III, COD e DADO são segregados ficando, porém nas mesmas posições nas respectivas listas.

O código fica:

procedure TForm1.indexando_ordenando_as_duas;
var lst_COD,lst_DADO : TStringList;
   n,ind            : integer;
   dado_recuperado  : string;
begin
  lst_COD  := TStringList.Create();
  lst_DADO := TStringList.Create();


  // carrega COD e DADO da tabela B, usando uma query

  query.SQL.Text := 'select COD, DADO from tabela_B';
  query.Active   := true;
  query.First;
  while not query.eof do
       begin
       lst_COD.Add(query.Fields[0].value + query.Fields[1].value);
       query.Next;
       end;
  query.Active   := false;

  lst_COD.Sort;   // ordena os pares de dados
  lst_COD.Sorted := false;


  // agora, desmembra a lista em duas, com os itens emparelhados

  for ind := 0 to lst_COD.Count - 1 do
     begin
     lst_DADO.add(copy(lst_COD[ind], 4, 99));
     // no caso, o comprimento de COD seria 3
     lst_COD[ind]  := copy(lst_COD[ind], 1, 3);
     end;
  lst_COD.Sorted := true;
  // lê a tabela A, e verifica se existe o dado na lista  -
  //"n" é meramente ilustrativo
  n := 6;
  tab_A.Active  := true;
  tab_A.First;
  while not tab_A.eof do
       begin
       if lst_COD.Find(tab_A.Fields[n].Value, ind) then
          //dado_recuperado := lst_DADO[ind]
       else
          dado_recuperado := '';
       tab_A.Next;
       end;
  tab_A.Active  := false;

  lst_COD.Free;
  lst_DADO.Free;
end;

Comentário:

No exemplo acima, confiamos que o comprimento de COD fosse fixo. Caso seja necessário trabalhar com formatos que não resultem em strings fixos, como inteiros, por exemplo, sugerimos que a “chave” carregada na lista seja formatada pela função FORMAT. Assim também pode ser feito quando a chave de busca é formada por múltiplos campos.

- alternativa 2: indexação relativa

A segunda alternativa é construir um vetor (uma lista), carregada apenas com os índices relativos, apontando para a outra lista donde os dados serão recuperados.

Isso é útil, por exemplo, quando DADO, do exemplo anterior, é uma estrutura ou registro, com vários campos, ou ponteiros, ou marcadores, etc. Enfim, quando não se for conveniente que DADO participe da ordenação.

Nesse caso, ao carregarmos a lista COD, carregamos a lista DADO ao mesmo tempo, e a posição em que o dado foi inserido (ind) ficará agregada junto a COD. Depois da ordenação, COD e o índice de DADO são desmembrados em duas listas. Agora são três listas.

Esquematicamente, fica assim:

Figura 2 - Utilizando uma lista/vetor auxiliar

No passo I, são carregadas as listas, e a posição relativa é anotada junto a COD;

No passo II, COD e seu antigo índice são ordenados, e;

No passo III, COD e o índice são desmembrados, ficando o índice como “ponte” para DADO

Esse exemplo ilustra uma técnica forte, que pode ser útil em várias situações.

procedure TForm1.indexando_relativo;
var lst_COD,
   lst_DADO,
   lst_IND          : TStringList;
   n,ind            : integer;
   dado_recuperado  : string;
begin
  lst_COD  := TStringList.Create();
  lst_DADO := TStringList.Create();
  lst_IND  := TStringList.Create();


  // carrega COD e DADO da tabela B, usando uma query

  query.SQL.Text := 'select COD, DADO from tabela_B';
  query.Active   := true;
  query.First;
  ind := -1;
  while not query.eof do
       begin
       inc(ind);
       lst_COD.Add(query.Fields[0].value + inttostr(ind));
       lst_DADO.Add(query.Fields[1].value);
       query.Next;
       end;
  query.Active   := false;

  lst_COD.Sort;      // ordena os codigos, mais os índices para dados
  lst_COD.Sorted := false;


  // agora, desmembra a lista em duas

  for ind := 0 to lst_COD.Count - 1 do
     begin
     lst_IND.add(copy(lst_COD[ind], 4, 99));
     // no caso, o comprimento de COD seria 3
     lst_COD[ind] := copy(lst_COD[ind],  1, 3);
     end;
  lst_COD.Sorted := true;

  // lê a tabela A, e verifica se existe o dado na lista
  //"n" é meramente ilustrativo

  n := 6;
  tab_A.Active  := true;
  tab_A.First;
  while not tab_A.eof do
       begin
       if lst_COD.Find(tab_A.Fields[n].Value, ind) then
         dado_recuperado := lst_DADO[ strtoint(lst_IND[ ind ]) ]
       else
          dado_recuperado := '';
       tab_A.Next;
       end;
  tab_A.Active  := false;

  lst_COD.Free;
  lst_DADO.Free;
  lst_IND.Free;
end;

Caso 3. Uma aplicação.

Imaginemos agora duas tabelas, uma de ORÇAMENTOS, e outra de VENDAS realizadas, e desejamos saber o percentual de rejeição dos orçamentos, por produto.

Na tabela VENDAS está registrado o número do orçamento que deu origem à venda, mais o código do produto.

Porém, na tabela ORÇAMENTOS, não há referência se o orçamento foi aceito ou rejeitado. Essa tabela contém apenas o número do orçamento e o código do produto,

Ambas as tabelas têm em torno de 1.500.000 linhas. O número do orçamento é um código numérico, de 8 posições. Sabemos também que a tabela de PRODUTOS tem em torno de 5.000 linhas.

Então, se carregarmos todos os números de orçamentos, que estão na tabela VENDAS, para uma lista, tal lista ocupará em torno de 12MB, o que é bastante viável.

Trabalharemos então com a seguinte estrutura:

- duas listas, a primeira com os códigos de todos os produtos, ordenados, e, a segunda, com os códigos dos orçamentos aceitos, ou seja, que se transformaram em vendas.

- e mais um vetor de duas posições inteiras, com uma entrada para cada produto, onde serão armazenados contadores dos orçamentos emitidos, e dos orçamentos aceitos.

A indexação do vetor será relativa à lista de produtos.

Esquematicamente, fica assim:

Figura 3 - Aplicação das ordenações

O programa, então, fica:

- carregam-se todos os códigos de orçamentos que estão na tabela VENDAS para uma lista, que também é ordenada. (Orçamentos de “Vendas”)

- carregam-se os códigos dos produtos para outra lista, que é depois ordenada. (COD)

- tomam-se todos os orçamentos (código do orçamento e código do produto), da tabela ORÇAMENTOS, e:

soma-se 1 ao contador ORÇADO do produto, e:

se o orçamento existe na tabela de VENDAS (ou seja, na lista que foi carregada), soma-se 1 ao contador VENDIDO do produto.

Vamos ao código:

procedure TForm1.contando_os_orcamentos;
var lst_PROD,
   lst_ORCS         : TStringList;
   conta            : array[1..10000,1..2] of integer; // 1-orcado; 2-vendido
   ind,aux          : integer;
   orcado, vendido  : integer;
begin

  orcado := 1;
  vendido:= 2;

  lst_PROD := TStringList.Create();
  lst_ORCS := TStringList.Create();


  // carrega os códigos dos produtos, usando uma query

  query.SQL.Text := 'select PROD from PRODUTOS';
  query.Active   := true;
  query.First;
  ind := 0;
  while not query.eof do
       begin
       lst_PROD.Add(query.Fields[0].Value);
       inc(ind);
       conta[ind,orcado]  := 0;
       conta[ind,vendido] := 0;
       query.Next;
       end;
  query.Active    := false;


  // carrega os códigos dos orçamentos que vingaram

  query.SQL.Text := 'select COD_ORC from VENDAS';
  query.Active   := true;
  query.First;
  ind := -1;
  while not query.eof do
       begin
       lst_ORCS.Add(query.Fields[0].value);
       query.Next;
       end;
  query.Active   := false;

  lst_PROD.Sorted := true;
  lst_ORCS.Sorted := true;


  // carrega os orçamentos, e verifica se foram aceitos ou não

  query.SQL.Text := 'select COD_ORC,PROD from ORCAMENTOS';
  query.Active   := true;
  query.First;
  while not query.eof do
       begin
       lst_PROD.Find(query.Fields[1].value,ind);   //pega o índice do produto
       inc(conta[ind, orcado]);                    //conta orçamento
       if lst_ORCS.Find(query.Fields[0].value, aux) then // conta se foi aceito
          inc(conta[ind, vendido]);
       query.Next;
       end;
  query.Active  := false;

  lst_PROD.Free;
  lst_ORCS.Free;
end;

Comentário:

A lista de produtos poderia ser já uma lista de um componente STRINGBAND, por exemplo.

Esse caso poderia ser modificado para incluir as tuplas (COD, Descrição e contadores, etc) descritas em registros, e o vetor passar a ser uma estrutura com tais registros.

Conclusão.

Utilizando principalmente uma classe e dois métodos da classe, demonstramos como é simples tratar dados, de modo consciente e eficiente, em memória. Ou seja, pode ser simples implementarmos estratégias personalizadas para o tratamento dos dados, o que quase sempre representa um ganho significativo de desempenho para a aplicação.

Então, se juntarmos o conhecimento formal de estruturas de dados, com os poderosos recursos que o Delphi disponibiliza, poderemos primar pela eficiência da programação, sem comprometer os prazos de desenvolvimento. E mais, podemos avançar no tratamento de estruturas complexas, como grafos, por exemplo, lançando mão apenas da nossa ferramenta básica do dia-a-dia.

Por: Pedro Jales - Graduado em Engenharia Química, e pós-graduado em Engenharia de Sistemas e em Administração de Empresas. Começou a programar em 1975, inicialmente em Fortran e Cobol. Trabalhou como Analista de Sistemas de 1978 a 2002, desenvolvendo programação, Projetos de Sistemas e Análise Organizacional. Programa em Delphi desde 1998. Contato: pedrojales@ig.com.br

Dica do Editor

Listas em memória podem ajudam a obter melhor performance em vários casos, porém, os exemplos de pesquisa e ordenação mostrados nesta artigo do amigo Pedro Jales não devem ser considerados como a melhor forma para lidar com banco de dados, seja um SGBD ou um com dados somente em memória.

Nestes casos é melhor utilizar um componente já pronto, como um ClientDataSet, um RxMemoryData ou um JvMemoryData para realizar as operações de ordenação (por índice virtual em memória), filtro (propriedade Filter), busca (Locate, FindKey, FindNearest), etc, para não ter que reinventar a roda e desfrutar de códigos já testados e aprovados por tantas pessoas.

Utilizar listas em memória são úteis em cruzamento de dados, em aplicações críticas ou com certa limitação de hardware.

Além disso, há outros tipos de listas (que não a StringList) que podem ser utilizadas em processamentos críticos. Um exemplo disto é trabalhar com ponteiros e montar os apontamentos entre os endereços diretamente no registro armazenado neles.

Veja abaixo alguns materiais aqui do site, sobre listas e dados em memória que podem ser úteis:

Usando Record, Ponteiro e TList Criando tabelas temporárias Criando arquivos XML com ClientDataSet com Pesquisa e Ordenação de Colunas

Criando Arrays dinâmicos de objetos no Delphi

Fonte: www.activedelphi.com.br Caros amigos delphianos, neste tutorial vou explicar para vocês como manipular objetos num array dinamicamente. Farei uma aplicação demostrando a impressão de cheques

Primeiro criaremos a classe, a classe é criada após o uses e antes da implementation, neste caso a classe criada de exemplo sera a Tcheque.

//-------------------------------------------------------------------// // DESCRIÇÃO : CLASSE CHEQUE // //------------------------------------------------------------------// type TCheque = class protected //----- Get e Set procedure SetBanco(const Value: String); function GetBanco:String; procedure SetNumero(const Value: String); function GetNumero:String; procedure SetValor(const Value: String); function GetValor:String; procedure SetFavorecido(const Value: String); function GetFavorecido:String; procedure SetCidade(const Value: String); function GetCidade:String; procedure SetData(const Value: String); function GetData:String; procedure SetVerso(const Value: String); function GetVerso:String;

private //----- Atributos FBanco : String; FNumero : String; FValor : String; FFavorecido : String; FCidade : String; FData : String; FVerso : String;

public property Banco : String read GetBanco write SetBanco; property Numero : String read GetNumero write SetNumero; property Valor : String read GetValor write SetValor; property Favorecido : String read GetFavorecido write SetFavorecido; property Cidade : String read GetCidade write SetCidade; property Data : String read GetData write SetData; property Verso : String read GetVerso write SetVerso;

//----- Metódos Criar e destruir objeto constructor Create; destructor Destroy; //---- end;

Está é a estrutura da classe que irei usar neste exemplo, não irei colocar as funções delas por que não é objetivo deste tutorial mostrar orientação ao objetos, caso haja um interesse futuramente posso postar um artigo mais completo mostrando como trabalhar com POO no Delphi.

Após a criação da estrutura da classe que iremos utilizar, agora vou mostrar como pegar os dados de um DataSet e jogá-los dentro de um array.

Procedure GeraCheques; var ACheques : array of TCheque; // Array de Cheques dinâmico InInd : Integer; // Indice do array begin //----------------------------------------------------// // Cria o Array de Cheques // //----------------------------------------------------// //Primeiro registro DataSet.First; while not DataSet.Eof do begin //Aloca uma posição no array SetLength(ACheques,Length(ACheques)+1); //Pega o indice do ultimo registro que foi alocado InInd := Length(ACheques) - 1; // Crio o objeto ACheques[InInd] := TCheque.Create;

//Insere os valores no objeto ACheques[InInd].Banco := DataSetBAN_IN_NUMERO.AsString; ACheques[InInd].Numero := DataSetATO_ST_CHEQUE.AsString; ACheques[InInd].Valor := FormatFloat('###########0.00',DataSetATO_RE_VALORPAGO.AsFloat); ACheques[InInd].Favorecido := DataSetATO_ST_NOMINAL.AsString; ACheques[InInd].Cidade := Ed_Local.Text; ACheques[InInd].Data := FormataData('dd/mm/yy',DataSetATO_DT_VALIDOPARA.AsDateTime); ACheques[InInd].Verso := Ed_Memo.Lines.Text;

// Pula para o próximo registro DataSet.Next; end; end;

Em muitas situações trabalhar com obejetos diretos na memória se torna viável em ganho de performance, cabe a cada umverificar a utilidade do seu uso.

Como deletar arquivos temporários da Internet

Esta dica mostra como deletar arquivos temporários da internet:
Uses WinInet;

procedure deletar;
var
  info: PInternetCacheEntryInfo;
  diretorio: LongWord;
  tamanho: LongWord;
begin
  tamanho := 0;
  FindFirstUrlCacheEntry(nil, TInternetCacheEntryInfo(nil^), tamanho) ;
  GetMem(info, tamanho) ;
  if tamanho > 0 then info^.dwStructSize := tamanho;
  diretorio := FindFirstUrlCacheEntry(nil, info^, tamanho) ;
  if diretorio <> 0 then
  begin
    repeat
      DeleteUrlCacheEntry(info^.lpszSourceUrlName) ;
      FreeMem(info, tamanho) ;
      tamanho := 0;
      FindNextUrlCacheEntry(diretorio, TInternetCacheEntryInfo(nil^), tamanho) ;
      GetMem(info, tamanho) ;
      if tamanho > 0 then info^.dwStructSize := tamanho;
    until not FindNextUrlCacheEntry(diretorio, info^, tamanho);
  end;
  FreeMem(info, tamanho) ;
  FindCloseUrlCache(diretorio) ;
end;

Add To Repository: O repositório de objetos do Delphi

Tempo, o maior desafio dos programadores! No mundo atual desenvolver aplicações com qualidade exige um tempo maior do que dispomos. Para resolver este tipo de problema o delphi nos oferece um grande número de ferramentas que tornam o processo de desenvolvimento de software mais rápido. Dentre elas podemos destacar o repositório de objetos muito útil para quem trabalha com aplicações vinculadas a bancos de dados. Ele permite que objetos herdem as propriedades e rotinas de outros que já existem. Tal característica é denominada de herança. Definimos um objeto como ancestral, “pai”, e depois criamos os objetos que irão herdar as características do ancestral, os “filhos”. A função mais importante do repositório é a possibilidade de ao modificar o ancestral todos os filhos recebem as alterações. O Ancestral Para definir um objeto como pai clique com o botão direito do mouse sobre o mesmo e no menu que surge selecione a opção “Add To Repository...”.
Irá surgir uma janela com os seguintes campos: - Forms: objetos que deseja adicionar ao repositório de objetos; - Title: define um título ao objeto que irá funcionar como ancestral; - Description: neste campo você poderá inserir uma descrição de seu objeto. - Page: guia da janela “New Items” ao qual o objeto será exibido; Obs.: caso digite um nome que não exista, o delphi irá criar uma nova guia com este nome automaticamente. - Author: nome do desenvolvedor; - Browse: seleciona um ícone para a exibição do objeto.
Janela do Add To Repository
Após preencher todos os campos basta clicar no botão “Ok” para gerar o ancestral. Os Filhos Para criar o objeto filho clique no menu file > New > other e selecione a guia onde o ancestral foi salvo.
Na parte inferior desta janela existem três opções: - Copy: cria uma cópia do ancestral, qualquer alteração no pai não afeta o filho. - Inherit: cria um objeto que herda as características do ancestral, neste caso qualquer mudança no pai acarreta alteração no filho. - Use: utiliza o próprio formulário ancestral. Esta opção é usada para modificar o ancestral.
Janela New Items
Após selecionar o objeto ancestral e uma das três características acima, basta clicar no botão “Ok” para utilizar o objeto filho com as características do pai ou alterar o próprio ancestral.

Video Aula