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

Curso de Delphi: 7.Consultas SQL