quarta-feira, 16 de setembro de 2015

Saiba mais sobre o dbExpress e como usar esta arquitetura em suas aplicações Delphi envolvendo banco de dados


Uma das características mais significativas do Delphi é seu suporte para os mais diferentes bancos de dados usando diferentes tecnologias de acesso: BDE, dbExpress, InterBase Express, ADO, Borland Data Providers for .NET, etc. Nesta dica abordarei o dbExpress devido à sua forte aceitação no mercado.

Durante as versões iniciais do Delphi houve tentativas de se criar uma API comum para o acesso a vários e diferentes bancos de dados. No entanto, todas as soluções apresentaram um ou mais problemas. Algumas abordagens se tornaram demasiadas complexas, lentas e dificil de distribuir. Outras apresentavam problemas relacionados à complexidade de se escrever os drivers para os bancos de dados, tornando-as limitadas em funcionalidade, lentas e cheias de bugs.

O dbExpress (apresentado pela primeira vez no Delphi 6) supera todos estes problemas ao combinar a abordagem de fornecer uma API comum para vários bancos de dados com a arquitetura provide/resolve da Borland para gerenciar o processo de edição e atualização de dados. 

A arquitetura dbExpress

O dbExpress (anteriormente chamado de DBXpress) foi desenvolvida para atingir os seguintes objetivos:

a) Minimizar o tamanho e uso de recursos do sistema.
b) Maximizar a velocidade.
c) Fornecer suporte cross-platform (independente de plataforma).
d) Fornecer fácil distribuição.
e) Facilitar o desenvolvimento de drivers.
f) Fornecer ao desenvolvedor um maior controle sobre o uso de memória e tráfego de rede.

Os drivers do dbExpress são pequenos e rápidos porque eles fornecem uma funcionalidade muito limitada. Cada driver é implementado como uma DLL única na plataforma Windows e como um único objeto compartilhado na plataforma Linux. Um driver dbExpress implementa cinco interfaces que suportam a obtenção de metadados, a execução de instruções SQL e stored procedures e o retorno de um cursor unidirecional somente leitura para um conjunto de resultados (result set). Contudo, quando usado em conjunto com os componentes DataSetProvider e ClientDataSet para implementar a estratégia de acesso de dados provide/resolve, o dbExpress nos oferede um sistema completo de alta concorrência e de alta performance para o desenvolvimento de aplicações que lidam com bancos de dados SQL.

Os componentes do dbExpress são:

TSQLConnection - Define uma conexão com um banco de dados, similar ao TDatabase.

TSQLDataSet - Representa um conjunto de dados unidirecional de propósito geral que executa a instrução SQL definida na propriedade CommandText. O valor desta propriedade pode ser uma instrução SELECT que retorna um conjunto de dados, uma instrução SQL que não retorna dados ou executa uma stored procedure.

TSQLQuery - Suporta instruções SQL a serem executadas e que retornam um conjunto de dados unidirecional ou atualizam dados ou esquemas de banco de dados.

TSQLStoredProc - Executa uma stored procedure. Se houver um conjunto de dados como retorno este será unidirecional.

TSQLTable - Fornece acesso unidirecional a uma tabela da base de dados.

TSQLMonitor - Usado para interceptar e exibir mensagens transferidas entre um TSQLConnection e o banco de dados.

TSimpleClientDataSet - Combina um TSQLDataSet e TDataSetProvider em um mesmo componente para suportar dados em cache de memória.

terça-feira, 15 de setembro de 2015

Como obter uma substring de uma string

*Fonte Arquivo de Códigos

Em algumas situações precisamos obter uma substring de uma string. Em Delphi isso pode ser feito por meio da função AnsiMidStr(). Esta função requer a string a partir da qual a substring será obtida, a posição inicial da substring (começando em 1) e a quantidade de caracteres que comporâo a substring. O retorno será uma nova string contendo a substring obtida. Veja o exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
  frase, substring: string;
begin
  frase := 'Programar em Delphi é muito bom';

  // vamos obter a substring "Delphi"
  substring := AnsiMidStr(frase, 14, 6);

  // vamos exibir o resultado
  ShowMessage('Resultado: ' + substring);
end;

Não se esqueça de adicionar a unit StrUtils no uses do seu formulário.

Para questões de compatibilidade, esta dica foi escrita usando Delphi 2009.

Programação orientada a objetos em Delphi: Classes, objetos, métodos e variáveis de instância


A melhor forma de entender a programação orientada a objetos é começar com uma analogia simples. Suponha que você queira dirigir um carro e fazê-lo ir mais rápido pressionado o acelerador. O que deve acontecer antes que você seja capaz de fazer isso? Bem, antes que você possa dirigir um carro, alguém tem que projetá-lo. Um carro geralmente começa com desenhos feitos pelos engenheiros responsáveis por tal tarefa, tal qual a planta de uma casa. Tais desenhos incluem o projeto de um acelerador que possibilita ao carro ir mais rápido. O pedal do acelerador "oculta" os mecanismos complexos responsáveis por fazer o carro ir mais rápido, da mesma forma que o pedal de freio "oculta" os mecanismos que fazem o carro ir mais devagar e o volante "oculta" os mecanismos que fazem com que o carro possa virar para a direita ou esquerda. Isso permite que pessoas com pequeno ou nenhum conhecimento de motores possam facilmente dirigir um carro.

Infelizmente, não é possível dirigir o projeto de um carro. Antes que possamos dirigí-lo, o carro deve ser construído a partir do projeto que o descreve. Um carro já finalizado tem um pedal de aceleração de verdade, que faz com que o carro vá mais rápido. Ainda assim, é preciso que o motorista pressione o pedal. O carro não acelerará por conta própria.

Agora vamos usar nosso exemplo do carro para introduzir alguns conceitos de programação importantes à programação orientada a objetos. A execução de uma determinada tarefa em um programa exige um método. O método descreve os mecanismos que, na verdade, executam a tarefa. O método oculta tais mecanismos do usuário, da mesma forma que o pedal de aceleração de um carro oculta do motorista os mecanismos complexos que fazem com que um carro vá mais rápido. Em Delphi, começamos criando uma unidade de programa chamada classe para abrigar um método, da mesma forma que o projeto de um carro abriga o design do pedal de acelerador. Em uma classe fornecemos um ou mais métodos que são projetados para executar as tarefas da classe. Por exemplo, a classe que representa uma conta bancária poderia conter muitos métodos, incluindo um método para depositar dinheiro na conta, outro para retirar dinheiro, um terceiro para verificar o saldo, e assim por diante.

Da mesma forma que não podemos dirigir o projeto de um carro, nós não podemos "dirigir" uma classe. Da mesma forma que alguém teve que construir um carro a partir de seu projeto antes que pudessémos dirigí-lo, devemos construir um objeto de uma classe antes de conseguirmos executar as tarefas descritas nela.

Quando dirigimos um carro, o pressionamento do acelerador envia uma mensagem ao carro informando-o da tarefa a ser executada (neste caso informando-o de que queremos ir mais rápido). Da mesma forma, enviamos mensagens aos objetos de uma classe. Cada mensagem é uma chamada de método e informa ao objeto qual ou quais tarefas devem ser executadas.

Até aqui nós usamos a analogia do carro para introduzir classes, objetos e métodos. Já é hora de saber que um carro possui atributos (propriedades) tais como cor, o número de portas, a quantidade de gasolina em seu tanque, a velocidade atual, etc. Tais atributos são representados como parte do projeto do carro. Quando o estamos dirigindo, estes atributos estão sempre associados ao carro que estamos usando, e cada carro construído a partir do projeto sofrerá variações nos valores destes atributos em um determinado momento. Da mesma forma, um objeto tem atributos associados a ele quando o usamos em um programa. Estes atributos são definidos na classe a partir da qual o objeto é instanciado (criado) e são chamados de variáveis de instância da classe.

Veremos agora como definir uma classe em Delphi e usar um objeto desta classe em um programa. Para isso siga atentamente os passos abaixo:

1) Vá em File -> New -> Unit - Delphi. Isso vai gerar uma nova unit parecida com:

unit Unit2;

interface

implementation

end.

2) Salve esta unit com o nome de Cliente.pas e altere o seu código para:

unit Cliente;

interface

type
  TCliente = class
    private
      Nome: string;

    public
      // uma procedure que permite definir o nome do cliente
      procedure DefinirNome(Nome: String);
      // uma função que permite obter o nome do cliente
      function ObterNome: String;
  end;

implementation

procedure TCliente.DefinirNome(Nome: String);
begin
  // atribui ao membro Nome o valor recebido como argumento
  Self.Nome := Nome;
end;

function TCliente.ObterNome;
begin
  // retorna o valor do membro Nome
  Result := Self.Nome;
end;

end.

Note que esta classe possui um membro de instância privado chamado Nome e dois métodos públicos: uma procedure que recebe um valor e o atribui ao membro Nome e uma função que retorna o valor deste mesmo membro. Vamos agora criar um objeto desta classe a partir de outro formulário.

3) Em um outro formuário da aplicação, vá em File -> Use Unit e inclua a unit Cliente (uses Cliente;). Em seguida coloque o código abaixo no evento Click de um botão:

procedure TForm1.Button1Click(Sender: TObject);
var
  c: TCliente;
begin
  // vamos criar um objeto da classe Cliente
  c := TCliente.Create;

  // vamos definir o nome do cliente
  c.DefinirNome('Osmar J. Silva');

  // vamos obter o nome do cliente
  ShowMessage('O nome do cliente é: ' + c.ObterNome);
end;

Execute o programa e veja o resultado. Funcionou como esperado? Bem-vindo à programação orientada a objetos usando Delphi.

Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

Formatando datas e horas em Delphi usando a função FormatDateTime()


Em algumas situações precisamos formatar um TDateTime e exibir seus valores de data e hora em formatos mais amigáveis ao usuário. Para isso o Delphi nos fornece a função FormatDateTime(), presente na unit SysUtils. Esta função recebe uma string de formatação e um TDateTime e retorna uma string contendo a data e hora formatadas. Veja um exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
  data: TDateTime;
  formatada: string;
begin
  // vamos obter a data de hoje
  data := Now;

  // vamos formatar
  formatada := FormatDateTime('dddd, dd "de" mmmm "de" yyyy',
    data);

  // vamos exibir o resultado
  ShowMessage(formatada);
end;

Aqui a data será exibida em um formato semelhante à "sexta-feira, 22 de outubro de 2008", ou seja, o formato de data longa do Windows.

Para tirar o máximo proveito da função FormatDateTime(), é importante conhecer os caracteres de formatação permitidos na função. Veja:

c - Exibe a data usando o formato dado pela variável global ShortDateFormat, seguida pelas horas usando o formato dado pelo variável global LongTimeFormat. As horas não serão exibidas se o valor das horas indicarem meia-noite.

d - Exibe o dia como um número não precedido de zero (1-31).

dd - Exibe o dia como um número precedido de zero (01-31).

ddd - Exibe o dia como uma abreviação (Dom-Sáb) usando as strings fornecidas pela variável global ShortDayNames.

dddd - Exibe o dia com o nome completo (Domingo-Sábado) usando as strings dadas pela variável global LongDayNames.

ddddd - Exibe a data usando o formato dado pela variável global ShortDateFormat.

dddddd - Exibe a data usando o formato dado pela variável global LongDateFormat.

e - (Windows somente) - Exibe o ano na era/período atual como um número não precedido por zero (somente os locales Japanese, Korean e Taiwanese).

ee - (Windows somente) - Exibe o ano na era/período atual como um número precedido por zero (somente os locales Japanese, Korean e Taiwanese).

g - (Windows somente) - Exibe a era/período atual como uma abreviação (somente os locales Japanese e Taiwanese).

gg - (Windows somente) - Exibe a era/período atual com um nome completo (somente os locales Japanese e Taiwanese).

m - Exibe o mês como um número não precedido por zero (1-12). Se o especificador m seguir imediatamente um especificador h ou hh, os minutos, e não é mês, são exibidos.

mm - Exibe o mês como um número precedido por zero (01-12). Se o especificador m seguir imediatamente um especificador h ou hh, os minutos, e não é mês, são exibidos.

mmm - Exibe o mês como uma abreviação (Jan-Dez) usando as string dadas pela variável global ShortMonthNames.

mmmm - Exibe o mês com um nome completo (Janeiro-Dezembro) usando as strings dadas pela variável global LongMonthNames.

yy - Exibe o ano com dois dígitos (00-99).

yyyy - Exibe o ano com quatro dígitos (0000-9999).

h - Exibe a hora não precedida por zero (0-23).

hh - Exibe a hora precedida por zero (00-23).

n - Exibe os minutos não precedidos por zero (0-59).

nn - Exibe os minutos precedidos por zero (00-59).

s - Exibe os segundos não precedidos por zero (0-59).

ss - Exibe os segundos precedidos por zero (00-59).

z - Exibe os milisegundos não precedidos por zero (0-999).

zzz - Exibe os milisegundos precedidos por zero (000-999).

t - Exibe as horas usando o formato dado pela variável global ShortTimeFormat.

tt - Exibe as horas usando o formato dado pela variável global LongTimeFormat.

am/pm - Usa o relógio de 12 horas para os especificadores h ou h precedentes e exibe "am" para as horas antes do meio-dia e "pm" para as horas depois do meio-dia. O especificador am/pm pode ser em letras minúsculas, maiúsculas ou uma combinação destas.

a/p - Usa o relógio de 12 horas para os especificadores h ou h precedentes e exibe "a" para as horas antes do meio-dia e "p" para as horas depois do meio-dia. O especificador a/p pode ser em letras minúsculas, maiúsculas ou uma combinação destas.

ampm - Usa o relógio de 12 horas para os especificadores h ou hh e exibe o conteúdo da variável global TimeAMString para qualquer hora antes do meio-dia e o conteúdo de TimePMString para as horas depois do meio-dia.

/ - Exibe o caractere de separador de datas dado pela variável global DateSeparator.

: - Exibe o caractere de separador de horas dado pela variável global TimeSeparator.

'xx'/"xx" - Caracteres em aspas simples ou duplas não são formatados.

Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

segunda-feira, 14 de setembro de 2015

Como usar a função FormatFloat() para formatar valores de ponto-flutuante em Delphi


A função FormatFloat() é muito útil quando queremos formatar valores de ponto-flutuante (valores que possuem a parte fracionária) em Delphi. Esta função recebe um padrão de formatação e o valor a ser formatado e retorna uma string. Veja um exemplo no qual formatamos o valor de PI com 2 casas decimais:

procedure TForm1.Button1Click(Sender: TObject);
var
  resultado: string;
begin
  // vamos formatar o valor de PI com 2 casas decimais
  resultado := FormatFloat('#.00', PI);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

O resultado será exibido como 3,14. Note que aqui nós informamos o ponto como separador decimal. No entanto, o Delphi busca o separador decimal na variável global DecimalSeparator, usada para facilitar a internacionalização, visto que este valor é obtido a partir das configurações regionais do Windows.

Para tirar o máximo proveito da função FormatFloat(), é necessário conhecer os especificadores de formato:

0 - Marcador de dígito. Se o valor a ser formatado tiver um dígito na posição ocupada por "0" na string de formatação, então este dígito é copiado para a string resultante. Do contrário, um "0" é guardado nesta posição na string resultante. Veja, por exemplo, como podemos formatar um valor sempre com 5 posições antes da vírgula:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: double;
  resultado: string;
begin
  valor := 4.50;

  // vamos formatar o valor com 5 posições antes da vírgula
  resultado := FormatFloat('00000.00', valor);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

# - Marcador de dígito. Se o valor a ser formatado tiver um dígito na posição ocupada por "0" na string de formatação, então este dígito é copiado para a string resultante. Do contrário, nada é guardado nesta posição na string resultante.

. - O primeiro caractere "." encontrado na string de formatação determina a posição do separador decimal na string resultante. Quaisquer caracteres "." encontrados após o primeiro "." serão ignorados. O caractere do separador decimal é determinado pela variável global DecimalSeparator ou seu equivalente TFormatSettings.

, - Separador de milhares. Se a string de formatação tiver um ou mais caracteres ".", o resultado terá separadores de milhares entre cada grupo de três dígitos à esquerda do ponto decimal. A posição e quantidade de "." não afeta o resultado, exceto para informar que os separadores de milhares são necessários. O caractere do separador decimal é determinado pela variável global ThousandSeparator ou seu equivalente TFormatSettings. Veja um exemplo no qual exibimos o valor 43765,15 com o separador de milhar:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: double;
  resultado: string;
begin
  valor := 43765.15;

  // vamos formatar o valor usando o separador de milhares
  resultado := FormatFloat(',.00', valor);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

E+ - Notação científica. Se qualquer uma das strings 'E+', 'E-', 'e+' ou 'e-' estiver contida na string de formatação, o valor será formatado usando notação científica. Um grupo de até quatro caracteres "0" poderá ser inserido após 'E+', 'E-', 'e+', ou 'e-' para determinar o número máximo de dígitos no expoente. O 'E+' e 'e+' provocará um sinal de positivo para a formatação de números positivos e um sinal de negativo para a formatação de números negativos. O 'E-' e 'e-' provocará um sinal negativo apenas para expoentes negativos.
'xx'/"xx" - Caracteres em asplas simples ou duplas são exibidos sem formatação.

; - Usado para separar seções para números positivos, negativos e zeros na string de formatação. Usamos isso quando queremos que valores positivos, negativos ou zerados sejam formatados de forma diferente.

Veja um último exemplo, desta vez formatando um valor em moeda brasileira (durante a autoria desta dica, a moeda usada é reais):

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: double;
  resultado: string;
begin
  valor := 43765.15;

  // vamos formatar o valor usando o separador de milhares
  // e a moeda brasileira: reais
  resultado := FormatFloat('"R$ ",.00', valor);

  // vamos exibir o resultado
  ShowMessage(resultado);
end;

Aprenda a usar arrays (matrizes ou vetores) em Delphi


Em programação de computadores, um array, também conhecido como vector (para arrays uni-dimensionais) ou matriz (para arrays bi-dimensionais), é uma das mais simples estruturas de dados. Os arrays mantêm uma série de elementos de dados, geralmente do mesmo tamanho e tipo de dados. Elementos individuais são acessados por sua posição no array. A posição é dada por um índice, também chamado de subscrição. O índice geralmente utiliza uma seqüência de números inteiros, (ao contrário de um array associativo) mas o índex pode ter qualquer valor ordinal. Alguns arrays são multi-dimensionais, significando que eles são indexados por um número fixo de números inteiros, por exemplo, por um seqüência (ou sucessão) finita de quatro números inteiros. Geralmente, arrays uni- e bi-dimensionais são os mais comuns.

Os arrays podem ser considerados como as estruturas de dado mais simples que é possível imaginar. Têm a vantagem de que os seus elementos são acessíveis de forma rápida, mas têm uma notável limitação: são de tamanho fixo, mas podem ser incrementados ou diminuídos com determinados algoritmos, geralmente envolvendo a cópia de elementos de um array para outro e reinicializando o original com a nova dimensão. Os vetores podem ser implementados desta forma.

Em Delphi um array é declarado da seguinte forma:

var
  valores: array[1..10] of Integer;

Aqui nós temos um array chamado valores que contém 10 elementos do tipo Integer. Estes elementos podem ser acessados por índices que variarão de 1 a 10, ou seja, podemos acessar o 5º elemento da seguinte forma:

procedure TForm1.Button1Click(Sender: TObject);
var
  valores: array[1..10] of Integer;
begin
  valores[5] := 20;
end;

Este tipo de array que ora criamos é chamado de array estático, em contraposição aos arrays dinâmicos, os quais podem ter seus tamanhos redimensionados durante a execução do programa.

A forma mais prática de se trabalhar com arrays em Delphi é usando laços. Veja:

procedure TForm1.Button1Click(Sender: TObject);
var
  valores: array[1..5] of Integer;
  i, soma: Integer;
begin
  // vamos preencher o array com os valores de 1 a 5
  for i := 1 to 5 do
    begin
      valores[i] := i;
    end;

  // vamos percorrer o array novamente e obter a soma dos
  // valores de seus elementos
  soma := 0;
  for i := 1 to 5 do
    begin
      soma := soma + valores[i];
    end;

  // vamos exibir o resultado
  ShowMessage('A soma dos valores é: ' + IntToStr(soma));
end;

Aqui nós declaramos um array de 5 elementos do tipo Integer e inicializamos seus elementos com os valores de 1 a 5. Em seguida percorremos todo o array novamente para obter a soma dos valores dos elementos.

É possível também declarar e já inicializar um array. Veja:

procedure TForm1.Button1Click(Sender: TObject);
const
  valores: array[1..5] of Integer = (3, 2, 6, 12, 9);
var
  i, soma: Integer;
begin
  // vamos percorrer o array novamente e obter a soma dos
  // valores de seus elementos
  soma := 0;
  for i := 1 to 5 do
    begin
      soma := soma + valores[i];
    end;

  // vamos exibir o resultado
  ShowMessage('A soma dos valores é: ' + IntToStr(soma));
end;

Note que aqui eu declarei o array como uma constante. Isso aconteceu porque o Delphi não permite que inicializemos variáveis locais ([DCC Error] Unit1.pas(32): E2195 Cannot initialize local variables). Caso você realmente precise do array como variável e não constante, e deseje inicializá-lo juntamente com a declaração, mova-o para a seção interface do formulário ou classe.

Para finalizar, veja que é possível criar arrays de todos os tipos em Delphi. Veja no trecho de código abaixo como usamos um array de Char para guardar uma palavra e exibí-la normal e depois invertida:

procedure TForm1.Button1Click(Sender: TObject);
const
  letras: array[1..5] of Char = ('O', 's', 'm', 'a', 'r');
var
  i: Integer;
  resultado: String;
begin
  resultado := '';

  // vamos exibir a palavra na forma normal
  for i := 1 to 5 do
    resultado := resultado + letras[i];

  // exibe o resultado
  ShowMessage(resultado);

  // vamos exibir a palavra invertida
  resultado := '';
  for i := 5 downto 1 do
    resultado := resultado + letras[i];

  // exibe o resultado
  ShowMessage(resultado);
end;

Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

Aprenda a executar comandos SQL usando o método ExecSQL() da classe TSQLDataSet


O método ExecSQL() da classe TSQLDataSet é usado quando queremos executar comandos SQL que não retornam um conjunto de dados. Este comando pode ser INSERT, UPDATE, DELETE, CREATE TABLE, etc, exceto SELECT.

Veja a assinatura deste método:

function ExecSQL(ExecDirect: Boolean = False): Integer; override;

ExecDirect é usado para indicar que a query não precisa ser preparada antes de ser executada. Este parâmetro pode ser definido como True se o comando não incluir nenhum parâmetro. Se o valor for False, a query será preparada antes de ser executada.

Vamos ver um exemplo? Veja um trecho de código no qual usamos o método ExecSQL() para disparar um comando SQL UPDATE. Note que aqui estamos usando um comando SQL preparado (pré-compilado):

procedure TForm3.Button1Click(Sender: TObject);
var
  nome: string;
  id: integer;
begin
  nome := 'OSMAR J. SILVA';
  id := 2; // id do registro a ser atualizado

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.CommandText := 'UPDATE contatos SET nome = :nome WHERE id = :id';
  SQLDataSet1.Params[0].Name := 'nome';
  SQLDataSet1.Params[0].Value := nome;
  SQLDataSet1.Params[1].Name := 'id';
  SQLDataSet1.Params[1].Value := id;

  // como o comando é preparado, vamos definir o valor
  // False para o parâmetro ExecDirect
  SQLDataSet1.ExecSQL(False);

  // vamos mostrar uma mensagem indicando o sucesso da operação
  ShowMessage('Comando SQL executado com sucesso.');
end;

É importante observar que o método ExecSQL() retorna o número de linhas afetadas pelo comando. O valor retornado se torna o valor da propriedade RowsAffected. Veja como modificar o código anterior para retornar a quantidade de linhas afetadas:

procedure TForm3.Button1Click(Sender: TObject);
var
  nome: string;
  id: integer;
  linhasAfetadas: integer;
begin
  nome := 'OSMAR J. SILVA';
  id := 2; // id do registro a ser atualizado

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.CommandText := 'UPDATE contatos SET nome = :nome WHERE id = :id';
  SQLDataSet1.Params[0].Name := 'nome';
  SQLDataSet1.Params[0].Value := nome;
  SQLDataSet1.Params[1].Name := 'id';
  SQLDataSet1.Params[1].Value := id;

  // como o comando é preparado, vamos definir o valor
  // False para o parâmetro ExecDirect
  linhasAfetadas := SQLDataSet1.ExecSQL(False);

  // vamos mostrar uma mensagem indicando o sucesso da operação
  ShowMessage('Comando SQL executado com sucesso. ' +
    IntToStr(linhasAfetadas) + ' linhas afetadas.');
end;

Lembre-se que não podemos usar ExecSQL() com comandos que retornam dados. Estes comandos incluem todos os comandos do tipo ctTable, queries SELECT e stored procedures que retornam um cursor. Quando o comando retornar dados, devemos usar o método Open ou definir a propriedade Active do SQLDataSet como True.

Criando Editor de Textos no Delphi 7

Como fazer um Injetor DLL no Delphi 7

quinta-feira, 20 de agosto de 2015

Adicionar o evento OnClick no DBGrid

Problema:

Meu programa precisa processar algo quando o usuário clicar no DBGrid em um determinado form. O problema é que o DBGrid não possui o evento OnClick. É possível adicionar este evento no DBGrid?

Solução:

É possível sim. Afinal é muito simples. Siga os passos abaixo para resolver seu problema:

- Monte seu form normalmente, colocando o DBGrid e demais componentes;

- Vá na seção "private" da unit e declare a procedure abaixo:

private
  procedure DBGridClick(Sender: TObject);
- Logo após a palavra "implementation", escreva a procedure:

implementation
{$R *.DFM}

procedure TForm1.DBGridClick(Sender: TObject);
begin
  ShowMessage('Clicou no DBGrid.');
end;
- Coloque as instruções abaixo no evento OnCreate do Form:

procedure TForm1.FormCreate(Sender: TObject);
begin
  DBGrid1.ControlStyle :=
  DBGrid1.ControlStyle + [csClickEvents];
  TForm(DBGrid1).OnClick := DBGridClick;
end;
- E pronto. Execute e teste.

Observações
O segredo principal desta dica está OnCreate do Form. A primeira instrução ativa o evento OnClick. A segunda instrução acessa o manipulador do evento OnClick. Para isto precisamos tratar o DBGrid como se fosse Form, pois o evento OnClick está declarado como protegido (protected) na classe TDBGrid. 

segunda-feira, 17 de agosto de 2015

Consultando entre datas utilizando SQL

Coloque no formulário dois componentes TDateTimePicker, um TDbgrid e um TButton. Ligue seu TDbgrid a tabela do teu banco que queres aplicar a consulta, e no  evento onclic do compoenente TButton adicione o código abaixo.

If DateTimePicker2.Date < DateTimePicker1.Date Then
begin
       ShowMessage('Intervalo de datas inválido, a data inicial é maior que a data final!');
       DateTimePicker2.Date := DateTimePicker1.Date;
end
Else
begin
     Inicio := DateToStr(DateTimePicker1.Date);
     Final := DateToStr(DateTimePicker2.Date);
     Query1.Close;
     Query1.SQL.Clear;
     //Campos utilizados somente para exemplo. Utilize os campos que achar necessário apresentação
     //em seu Dbgrid
     Query1.SQL.Text := 'SELECT Nome,Empresa,FoneRes,FoneCom,Mala FROM Contatos
     WHERE Data >=:pInicial and Data<=:pFinal ORDER BY Nome';
     Query1.ParamByName('pInicial').AsDateTime := StrToDate(Inicio);
     Query1.ParamByName('pFinal').AsDateTime := StrToDate(Final);
     Query1.Prepare;
     Query1.Open;
     DBGrid.SetFocus;
end;
Label3.Caption := 'Total de contatos: ' + IntToStr(Query1.RecordCount) ;
  

Consulta SQL que usa a data do sistema

Problema:

Preciso fazer uma consulta com SQL que me retorne todos os registros em que o valor de um campo do tipo data seja igual ou anterior à dada do sistema. Como fazer?

Solução:

Query.Close;
Query.SQL.Text := 'select * from Tabela where CampoData <= :Hoje';
Query.ParamByName('Hoje').AsDate := Date;
Query.Open;

Bloco PL/SQL para inserção de dados

Pergunta 
Criar um bloco pl/sql que insira um novo dep na tabela s_dept 

- use a sequencia s_dept_id para o campo id da tabela 

- solicite ao usuario o nome do dep 

- insira valores nulos p/ o campo region_id 

Resposta 
-> no banco de dados... 
create or replace 
procedure insere_departamento (v_nome char) is 
v_id number; 
begin 
  SELECT sequenciaID.NEXTVAL INTO v_id FROM DUAL; 
  insert into tabela (id,dep,region_id) 
  values (v_id,v_nome,null); 
end insere_departamento; 

-> no delphi..

- coloque o objeto TStoredProc dentro do formulario que ira disparar esta procedure; 
- no evento que voce quiser que dispare coloque o seguinte codigo: 
 var 
  v_nome : String[50]; 
  begin 
{caso vc queira informar o nome do departamento atraves de uma caixa de dialogo} 
  V_nome := inputbox('Informe o nome do departamento.','Depto:',''); 
  .Params[0].AsString := v_nome; 
{caso vc queira buscar o nome atraves de um TEdit já preenchido} 
  .Params[0].AsString := .Text; 
  .ExecProc; 
  end; 

Inserindo uma Imagem no Formulário

A dica abaixo apresenta o código para implementação da função para inserir uma imagem no fundo do formulário. 

A função permite que se especifique as coordenadas da imagem e qual o arquivo que contém a imagem.

Através do componente TBitMap é possível criar uma figura dinamicamente e especificar qual será a imagem, através do método LoadFromFile.

Para desenhar a imagem usa-se o componente Tcanvas, através do método Draw, que desenha um gráfico nas coordenadas especificadas.

Código Completo:

declara após o type junto aos outros procedimentos!

Procedure Desenha(figura:String;H,V:Integer);

Procedure TForm1.Desenha(figura:String;H,V:Integer);
Var 
Imagem :TBitMap;
begin 
Imagem := TBitMap.Create;
Try
Imagem.LoadFromFile(Figura); 
Canvas.Draw(H,V,Imagem); 
Except 
ShowMessage(' Arquivo não foi localizado !'); 
end;
end;
ExemploQuando o botão for clicado, uma imagem será inserida no formulário, nas coordenadas (10,20);

procedure TForm1.Button1Click(Sender: TObject);
begin 
Desenha('c:\windows\bolhas.bmp',10,20);
end;

Como desenhar um Bitmap num form

var
Form1: TForm1;
Bmp: TBitmap;
implementation
{$R *.DFM}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Bmp:=TBitmap.Create;
  Bmp.Loadfromfile('c:\windows\nuvens.bmp');
end;

procedure TForm1.TForm1.FormPaint(Sender: TObject);
begin
  Canvas.Draw(50,50,Bmp);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Bmp.Free;
end; 

segunda-feira, 3 de agosto de 2015

Formatação de Casas Decimais no TEdit

Esse comando formata para decimal os números do componente TEDIT.
Crie um novo projeto, coloque no TForm, um componente TEDIT e um componente TBUTTON. No evento onclick do componente TBUTTON adicione o código abaixo:

procedure TForm1.Button1Click(Sender: TObject); 
var
     num : integer; 
begin 
     num:=12450; 
     Edit1.text:=formatfloat('###,###,##0.00', num) 
end;

Como posso rolar um form com pgUp e pgDn

Questão. Como posso fazer funções de rolagem num componente TForm usando comandos de teclado? Por exemplo, rolar pra cima e pra baixo quando pressionar PgUp ou PgDown. Existe algum método simples de fazer isso?

Resposta. O rolamento do form é completo fazendo-se uma modificação na posição das propriedades VertScrollbar ou HorzScrollbar do form. Como mostrado no código a seguir:

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
const
PageDelta = 10;
begin
  With VertScrollbar do
  if Key = VK_NEXT then
  Position := Position + PageDelta
  else if Key = VK_PRIOR then
  Position := Position - PageDelta;
end;
  

sábado, 1 de agosto de 2015

Capturar a data da BIOS ( Basic Input Output System ) do computador

Insira um objeto do tipo Button com a propriedade name definica como Button1 e um objeto do tipo Label com a propriedade definida como Label1.

procedure TForm1.Button1Click(Sender: TObject); 
begin
  Label1.Caption := 'Data da Bios: '+String(PChar(Ptr($FFFF5))); 
end; 

Como retornar a uma lista os campos indexados de um tabela

procedure TForm1.Button1Click(Sender: TObject);
var
      i : integer;
begin
     Table1.IndexDefs.Update;
     ListBox1.Items.add
    ('******** Índice Primário ********');
    for i:=0 to Table1.IndexDefs.Count-1 do
    begin
          if Table1.IndexDefs.Items[i].Options = [ixPrimary..ixUnique] then
          ListBox1.Items.add(Table1.IndexDefs.Items[I].Fields)
    else
         begin
              ListBox1.Items.add('');
              ListBox1.Items.add
              ('**** Índice Secundário ****');
              Listbox1.Items.Add(Table1.IndexDefs.Items[I].Name); 
          end;
     end; 
end;
  

Como filtrar registros de uma tabela pelo mês de um campo data

Você pode usar a função DecodeDate( ) no evento onFilterRecord de um componente TTable.

Ex.:

// não se esqueça de mudar a propriedade Filtered para True;
// isto fará com que o evento onFilterRecord seja disparado.

procedure TForm1.Table1FilterRecord(DataSet: TDataSet; var Accept: Boolean);
var
  Dia, Mes, Ano: word;
begin
  Accept := false;
  DecodeDate(Table1['Competencia'],Ano,Mes,Dia);
  if Mes=MesFiltrado then
  Accept := True;
end;
Obs.: Você pode usar este mesmo código para filtrar por Ano ou por Dia, basta utilizar a comparação adequada no bloco if ... then

Como diminuir o tempo de abertura do TTable e TQuery

Operação feita quando é executado o método Open do componente TTable ou TQuery, que produz a compilação e execução do comando select. Quando esse método é executado através do componente TTable, o Delphi realiza uma série de outros comandos SQLs para buscar informações do catálogo da tabela necessárias para as operações de seleção e atualização. Essa busca pode ser otimizada através da opção ENABLE SCHEMA CACHE do BDE, fazendo com que essas informações sejam lidas apenas uma vez durante a execução da aplicação. Quando o primeiro acesso é feito, o BDE armazena as informações em um arquivo e qualquer nova necessidade de abertura da mesma tabela não necessita buscar novamente os elementos do catálogo.

Por outro lado, utilizando-se o componente TQuery, pode-se desviar dessa busca desde que não se utilize a propriedade Request Live que torna o "result set" da "query" atualizável automaticamente pelo Delphi. Se o valor da propriedade Request Live for TRUE e o SELECT utilizado obedecer as restrições para que o Delphi consiga atualizar o "result set", as mesmas buscas utilizadas para o componente TTable terão que ser feitas. 

Concluindo, para que a busca de elementos do catálogo não seja feita é necessário utilizar o componente TQuery e controlar as atualizações manualmente ou através de componentes do tipo TUpdateSQL.