sexta-feira, 25 de novembro de 2022

Software de Controle Financeiro em Delphi com SQL Server

 


Sistema de controle financeiro, desenvolvido em Delphi, com o banco de dados SQL Server, usando o componente ADO, do próprio Delphi, para fazer conexão com o banco de dados, através do ODBC.

Tenho esse software a venda, com todos os fontes e componentes, por apenas R$ 29,90, quem tiver o interesse em adquirir, pode clicar no botão, no canto direito dessa tela, clicar no link abaixo.

O envio do link para download é imediato.

Clica aqui e adquira o seu


sexta-feira, 18 de novembro de 2022

Rotina de busca de endereço direto no site dos correios, informando apenas o CEP Em Delphi

 


Essa rotina busca o endereço, bairro, cidade e estado, direto do site dos correios, após informar o CEP.

Clique no link abaixo e compre os fontes prontos, só implementar no teu sistema, e ganhe rapidez no cadastro de clientes e fornecedores. 


Somente R$ 9,90.
Compre Aqui

segunda-feira, 21 de setembro de 2015

Como usar a propriedade Eof para verificar se estamos no último registro do TClientDataSet


Em algumas situações gostaríamos de verificar se já estamos no último registro do TClientDataSet, ou seja, estamos percorrendo todos os registros do dataset e queremos saber se já estamos no último. Para isso podemos usar a propriedade Eof da classe TClientDataSet. Esta propriedade retorna true se estivermos no último registro e false em caso contrário.

Veja um trecho de código no qual usamos um laço while para percorrer todos os registros de um TClientDataSet. Note o uso da propriedade Eof para finalizar as iterações do laço:

procedure TForm3.Button4Click(Sender: TObject);
begin
  // vamos percorrer todos os registros do TClientDataSet
  ClientDataSet1.First; // vamos para o primeiro registro
  // e agora disparamos um laço While
  while not ClientDataSet1.Eof do
    begin
      // vamos mostrar em um TMemo os valores do
      // campo id de cada registro
      Memo1.Lines.Add(ClientDataSet1.FieldByName('id').AsString);
      // vamos mover para o próximo registro
      ClientDataSet1.Next;
    end;
end;


A propriedade Eof é verdadeira quando:

a) Abrimos um dataset vazio. 

b) Efetuamos uma chamada ao método Last do dataset.

c) Chamamos o método Next do dataset e a chamada falha porque o registro atual já é o último registro no dataset.

d) Efetuamos uma chamada ao método SetRange em uma faixa de dados ou dataset vazio.

Como obter o número do registro atual em um TClientDataSet


Em algumas situações gostaríamos de obter o número do registro atual enquanto navegamos pelos registros de um TClientDataSet. Isso pode ser feito por meio da propriedade RecNo (implementada na classe TDataSet e reimplementada na classe TClientDataSet). O retorno da propriedade é sempre um valor inteiro representando o registro atual. Na implementação da classe TClientDataSet, esta propriedade retorna o valor -1 se o componente estiver no estado (State) dsInsert (um novo registro estiver sendo inserido).

Veja um trecho de código no qual usamos o evento OnClick de um botão para exibir o número do registro atual em um TClientDataSet: 

procedure TForm3.Button3Click(Sender: TObject);
var
  nRegistro: Integer;
begin
  // obtém o número do registro atual no TClientDataSet
  nRegistro := ClientDataSet1.RecNo;

  // mostra o resultado
  ShowMessage('O número do registro atual é: ' + IntToStr(nRegistro));
end;

Ao executar o código e clicar no botão você verá uma mensagem parecida com:

"O número do registro atual é: 5".

Esta dica foi escrita e testada no Delphi 2009.

Aprenda a usar a propriedade Active da classe TClientDataSet


A propriedade Active de um controle TClientDataSet pode ser definida em tempo de design (pelo Object Inspector) ou em tempo de execução. Se o valor for True os dados armazenados no TClientDataSet podem ser lidos e manipulados. Se o valor for False, o client dataset está fechado (closed) e não podemos acessar nem manipular os dados contidos nele.

Veja no trecho de código abaixo como definir o valor da propriedade Active em tempo de execução:

procedure TForm3.Button3Click(Sender: TObject);
begin
  // vamos ativar o client dataset
  ClientDataSet1.Active := True;

  // vamos testar se o client dataset foi mesmo ativado
  if ClientDataSet1.Active then
    ShowMessage('O ClientDataSet está ativo')
  else
    ShowMessage('O ClientDataSet  NÃO está ativo')
end;

Ao clicar no botão nós "ativamos" o client dataset e em seguida testamos o valor da propriedade Active para informar se o controle foi realmente ativado. É preciso ter muito cuidado. Tentar manipular os dados de um client dataset fechado pode resultar em uma exceção do tipo EDatabaseError com mensagens parecidas com:

Project Projeto.exe raised exception class EDatabaseError with message 'ClientDataSet1: Cannot perform this operation on a closed dataset'.

Ao definirmos o valor True para a propriedade Active as seguintes ações ocorrem:

1) O client dataset é preenchido com dados. Dependendo das propriedades do controle, estes dados podem vir de três formas diferentes: a) Do arquivo especificado na propriedade FileName; b) Do provider especificado na propriedade ProviderName ou por meio do método SetProvider. (algumas classes derivadas de TCustomClientDataSet possuem um componente interno que faz o papel do provider); c) Os dados que estavam ativos quando o client dataset foi desativado (somente se a aplicação foi executada durante um certo período depois que o dataset foi desativado).

2) O evento BeforeOpen é disparado. 

3) O valor dsBrowse é atribuído à propriedade State do dataset. 

4) Abre e posiciona um cursor no primeiro registro do conjunto de dados.

5) Dispara o evento AfterOpen. 

Se o client dataset nunca foi ativado, atribuir o valor True para a propriedade Active faz com que a estrutura (metadata) do client dataset seja definida. Esta estrutura é obtida juntamente com o pacote de dados a partir do provider ou armazenado em disco. Se não houver pacote de dados, tal estrutura é construída usando o valor atual da propriedade FieldDefs ou a partir dos componentes de campos persistentes listados na propriedade Fields.

Se um erro ocorrer durante a abertura do dataset, seu estado (State) é definido como dsInactive e o cursor de navegação é fechado.

Ao definirmos o valor False para a propriedade Active as seguintes ações ocorrem:

1) O evento BeforeClose é disparado. 

2) O valor para a propriedade State é definido como dsInactive. 

3) O cursor de navegação é fechado, salvando os dados atuais em disco se a propriedade FileName estiver definida e salvando o pacote de dados atual em cache de forma que o mesmo possa ser restaurado mais tarde quando o dataset for reaberto.

4) O evento AfterClose é disparado. 

Importante: Uma chamada ao método Open do TClientDataSet define a propriedade Active como True, enquanto uma chamada ao método Close a define como False.

Esta dica foi escrita e testada no Delphi 2009.

sexta-feira, 18 de setembro de 2015

Efetuando cálculos de porcentagem em Delphi


Cálculos de porcentagens estão presentes em boa parte das aplicações que desenvolvemos. Porém, há momentos em que a mente trava e não conseguimos lembrar com clareza como estes cálculos são feitos, principalmente em Delphi.

Esta anotação tem o objetivo de ser uma fonte de pesquisa para os momentos em que suas habilidades matemáticas insistirem em continuar ocultas.

Ex: 1 - Suponhamos que um produto que custe R$ 178,00 sofra um acréscimo de 15%. Qual o valor final do produto? Veja o código em Delphi: 

procedure TForm1.Button1Click(Sender: TObject);
var
  valor, percentual, valor_final: double;
begin
  valor := 178.00; // valor original
  percentual := 15.0 / 100.0; // 15%
  valor_final := valor + (percentual * valor);

  ShowMessage('O valor final do produto é: ' +
    FloatToStr(valor_final));

  // O resultado será 204,70
end;

Ex: 2 - Um produto, cujo valor original era de R$ 250,00, teve um desconto de 8%. Qual foi seu valor final? Veja o código em Delphi:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor, percentual, valor_final: double;
begin
  valor := 250.00; // valor original
  percentual := 8.0 / 100.0; // 8%
  valor_final := valor - (percentual * valor);

  ShowMessage('O valor final do produto é: ' +
    FloatToStr(valor_final));

  // O resultado será 230,00
end;

Ex: 3 - Em um concurso de perguntas e respostas, um jovem acertou 72 das 90 perguntas apresentadas. Qual foi a porcentagem de acertos? E a porcentagem de erros? Veja o código em Delphi: 

procedure TForm1.Button1Click(Sender: TObject);
var
  perguntas, acertos: double;
begin
  perguntas := 90.0;
  acertos := 72.0;

  ShowMessage('Porcentagem de acertos: ' +
    FloatToStr(((acertos / perguntas) * 100)) + '%');

  ShowMessage('Porcentagem de erros: ' +
    FloatToStr((((perguntas - acertos) / perguntas) * 100)) + '%');

  // Os resultados serão 80% e 20%
end;

Ex: 4 - Um aparelho de CD foi adquirido por R$ 300,00 e revendido por R$ 240,00. Qual foi a porcentagem de lucro na transação? Veja o código em Delphi:

procedure TForm1.Button1Click(Sender: TObject);
var
  v_ant, v_nov, p_lucro: double;
begin
  v_ant := 300.0; // valor anterior
  v_nov := 340.0; // valor novo
  p_lucro := 0.0; // porcentagem de lucro

  while(v_ant + ((p_lucro / 100.0) * v_ant) < v_nov) do
    begin
      p_lucro := p_lucro + 0.1;
    end;

  ShowMessage('A porcentagem de lucro foi de: ' +
    FloatToStr(p_lucro) + '%');

  // O resultado será 13,39
end;

Ex: 5 - Uma loja repassa 5% do lucro a seus vendedores. Se um produto custa R$ 70,00, qual o valor em reais repassado a um determinado vendedor? Veja o código em Delphi: 

procedure TForm1.Button1Click(Sender: TObject);
var
  valor, porcent, comissao: double;
begin
  valor := 70.0; // valor do produto
  porcent := 5.0 / 100.0; // 5%

  comissao := porcent * valor;

  ShowMessage('O valor repassado ao vendedor é: ' +
    FloatToStr(comissao));

  // O resultado será 3,5
end;

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

quinta-feira, 17 de setembro de 2015

Como efetuar uma conexão Delphi 7 + dbExpress + Firebird

*Fonte Arquivo de Códigos

Então você pretende desenvolver aplicações de bancos de dados usando o Delphi 7 + Firebird? O primeiro passo é aprender a fazer a conexão entre o Delphi e o banco de dados. Para esta dica estou usando o Delphi 7 e o Firebird 2.5. Usarei também os componentes da aba dbExpress. Para começar, certifique-se de que sua instalação do Delphi está funcionando corretamente. Verifique também se o Firebird está ativo e pronto para receber requisições.

Para efetuar a conexão, siga atentamente os passos a seguir:

a) Vá até a aba dbExpress e arraste um componente TSQLConnection para seu formulário. Em seguida ajuste o valor da propriedade ConnectionName para "IBConnection". Ajuste LoginPrompt para "False". Isso evitará que o programa exiba a tela de login para a inserção da senha a cada execução do programa.

b) Clique no botão ao lado da propriedade Params para exibir o Value List editor. Nesta janela vamos fornecer o nome e local da base de dados. Assim, ajuste o valor da propriedade Database para "C:\Firebird_2_5\dados\ESTUDOS.FDB" ou algo parecido no seu sistema. Ajuste o nome de usuário e senha se você não estiver usando os valores padrões. Clique Ok e feche o Value List editor.

c) Hora de testar a conexão. Para isso, ajuste a propriedade Connected do TSQLConnection para "True". Se tudo correu bem, a mudança do valor da propriedade ocorrerá sem qualquer problema. Se houver alguma mensagem de erro, refaça os passos anteriores.

Obtida a conexão com o banco de dados, é hora de disparar um comando SQL. Para isso arraste um componente TSQLDataSet e ajuste sua propriedade SQLConnection para o componente TSQLConnection. Arraste um componente TMemo para o formulário e, em seguida, coloque o código abaixo no evento Click de um botão:

procedure TForm1.Button1Click(Sender: TObject);
begin
  // vamos fechar o SQLDataSet
  SQLDataSet1.Close;

  // vamos definir o tipo de comando
  SQLDataSet1.CommandType := ctQuery;

  // vamos definir a query a ser executada
  SQLDataSet1.CommandText := 'SELECT * FROM USUARIOS';

  // vamos disparar o comando
  SQLDataSet1.Active := True;

  // e agora vamos percorrer os resultados obtidos
  Memo1.Clear;
  while not SQLDataSet1.Eof do
    begin
      // vamos mostrar os IDs e nomes dos usuários
      Memo1.Lines.Add(SQLDataSet1.Fields.Fields[0].AsString + ' - ' +
        SQLDataSet1.Fields.Fields[1].AsString);

      // vamos mover para o próximo registro
      SQLDataSet1.Next;
    end;
end;

Aqui eu disparei um comando SELECT contra um tabela chamada USUARIOS. O resultado da consulta foi algo parecido com:

1 - OSMAR J SILVA
2 - CARLOS DE SOUZA ROCHA

Como converter uma string em um valor numérico inteiro


Em algumas situações precisamos converter strings em valores numéricos do tipo inteiro. Isso acontece quando recebemos valores de caixas de texto e precisamos usuá-los em cálculos.

Vamos começar com a função StrToInt() da unit SysUtils. Esta função recebe uma string representando um valor inteiro válido e retorna um valor inteiro. Veja o exemplo:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor1, valor2, soma: Integer;
begin
  // vamos receber as strings dos TEdits e converter
  // seus valores para inteiros
  valor1 := StrToInt(Edit1.Text);
  valor2 := StrToInt(Edit2.Text);

  // vamos obter a soma dos dois valores
  soma := valor1 + valor2;

  // vamos exibir o resultado. Note o uso de IntToStr() para
  // converter o valor inteiro em string
  ShowMessage('A soma é: ' + IntToStr(soma));
end;

Note que, se a string sendo convertida possuir um valor inteiro inválido, uma exceção do tipo EConvertError será lançada. Podemos evitar isso usando a função TryStrToInt(). Esta função recebe dois argumentos: a string a ser convertida e a variável do tipo Integer que receberá o valor. O resultado será true se a conversão for feita com sucesso e false em caso contrário. Veja:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: Integer;
begin
  // vamos tentar converter o valor da caixa de texto
  // em um inteiro
  if TryStrToInt(Edit1.Text, valor) then
    ShowMessage('Conversão efetuada com sucesso.')
  else
    ShowMessage('Erro na conversão');
end;

Há ainda uma terceira possibilidade: usar a função StrToIntDef(). Esta função funciona exatamente da mesma forma que StrToInt(), exceto que agora, se houver um erro de conversão, um valor inteiro padrão será retornado. Veja:

procedure TForm1.Button1Click(Sender: TObject);
var
  valor: Integer;
begin
  // vamos converter o valor da caixa de texto
  // em um inteiro. Se a conversão não puder ser feita
  // o valor 10 será atribuído à varial valor
  valor := StrToIntDef(Edit1.Text, 10);

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

Caso você precise trabalhar com inteiros de 64 bits, poderá usar as funções StrToInt64(), StrToInt64Def() e TryStrToInt64().

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

quarta-feira, 16 de setembro de 2015

Aprenda a usar a variável global ShortDateFormat para controlar a formatação de datas

A variável global ShortDateFormat fornece a formatação curta usada, por padrão, na conversão de datas em strings. Esta variável é usada pelas funções DateToStr(), DateTimeToStr() e DateTimeToString(). Os caracteres de formatação usados são:

   y  = Ano com 2 dígitos 
  yy  = Ano com 2 dígitos 
yyyy  = Ano com 4 dígitos 
   m  = Número do mês do ano sem o 0 no início 
  mm  = Número do mês com 2 dígitos 
 mmm  = Mês usando nomes curtos (Jan) 
mmmm  = Mês usando nomes longos  (Janeiro) 
   d  = Número do dia sem o 0 no início 
  dd  = Número do dia com dois dígitos 
 ddd  = Dia usando nomes curtos (Dom) 
dddd  = Dia usando nomes longos  (Domingo) 

Veja o trecho de código abaixo:

procedure TForm1.Button1Click(Sender: TObject);
var
  data: TDateTime;
begin
  // vamos construir a data
  data := StrToDate('13/03/2009');

  // vamos exibir usando a formatação padrão de ShortDateFormat
  showMessage(DateToStr(data));

  // vamos alterar o padrão de formatação de ShortDateFormat
  ShortDateFormat := 'dd ''de'' mmmm ''de'' yyyy';

  // experimente também
  // ShortDateFormat := 'dd/mm/yyyy';

  // vamos exibir usando a nova formatação
  ShowMessage(DateToStr(data));
end;

Como a variável ShortDateFormat é indicada para uso global, é interessante você definir o formato customizado em apenas um lugar de seus códigos, de forma a reaproveitar a formatação nas demais partes de seus programas.

No Windows, a formatação inicial de ShowDateFormat vem de LOCALE_SSHORTDATE, uma constante da API do Windows.

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

Aprenda a usar o tipo de dados WORD da API do Windows em seus programas Delphi


Em várias ocasiões nós encontramos o tipo de dados WORD em códigos que interagem com a API do Windows. Desta forma, verificando a documentação do Windows descobrimos que este tipo está definido no header WinDef.h da seguinte forma:

typedef unsigned short WORD;

Em C/C++ um short possui 16 bits e o modificador unsigned informa que somente valores positivos são permitidos. Assim, sabemos que o tipo WORD pode guardar 16 bits (ou 2 bytes) de informação. Veja agora como podemos obter os valores máximo e mínimo de um WORD a partir de código Delphi:

procedure TForm3.Button2Click(Sender: TObject);
var
  maximo, minimo: WORD;
begin
  // vamos obter o valor máximo (65.535)
  maximo := High(WORD);

  // vamos obter o valor mínimo (0)
  minimo := Low(WORD);

  // vamos mostrar o resultado
  Memo1.Lines.Add('O valor máximo de um WORD é: ' +
    (IntToStr(maximo)));
  Memo1.Lines.Add('O valor mínimo de um WORD é: ' +
    (IntToStr(minimo)));
end;

Ao executar este código teremos o seguinte resultado:

O valor máximo de um WORD é: 65535
O valor mínimo de um WORD é: 0

Mas, o Delphi também possui um tipo Word. Qual a diferença entre o WORD (da API do Windows) e o Word do Delphi? Não há diferença. O tipo Word também é um inteiro de 16 bits não sinalizado cuja faixa de valores vai de 0 até 65.535. O fato de usarmos WORD em vez de Word em código que interage com a API do Windows é simplesmente para facilitar a tradução do código para outras linguagens que também possuem acesso direto à Win32 API.

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

Algumas funções da API do Windows mostram o tipo de dados LPTSTR. Qual o tipo compatível em Delphi?


Muitas vezes encontramos funções na API do Windows que possuem parâmetros do tipo LPTSTR. Veja um exemplo:

BOOL GetUserName(
  LPTSTR lpBuffer,
  LPDWORD lpnSize
);
Esta função é usada para obter o nome do usuário atualmente logado no sistema. Note que ela possui dois parâmetros:

lpBuffer - Um ponteiro para um buffer de caracteres que receberá o nome do usuário;

lpnSize - Este parâmetro informa, na entrada, o tamanho do buffer de caracteres e, na saída, informa a quantidade de caracteres copiados para o buffer.

Mas, como podemos usar esta função a partir do Delphi se não temos este tipo de dados (LPTSTR) em Delphi?

Para o tipo LPTSTR nós podemos fornecer uma string terminada em null (#0). E a melhor de forma de se fazer isso é declarando uma matriz de Char. Veja:

procedure TForm1.Button1Click(Sender: TObject);
var
  buffer: array[0..255] of Char; // um buffer de 256 caracteres
  tamanho: DWORD;
begin
  // vamos informar ao Windows o tamanho do buffer
  tamanho := 256;

  // vamos chamar a função da API do Windows
  if GetUserName(buffer, tamanho) then
    begin
      ShowMessage('O nome de usuário é: ' + buffer);
      // informa a quantidade de caracteres usados. Note que
      // o caractere de término da string também é informado
      ShowMessage('A função usou: ' + IntToStr(tamanho) +
        ' caracteres');
    end
  else
    ShowMessage('Não foi possível obter o nome do usuário');
end;
Um cuidado que devemos ter é nunca fornecer um buffer muito pequeno para as funções da API do Windows que esperam um ponteiro para strings do tipo LPTSTR. Experimente, por exemplo, fornecer uma matriz de apenas dois caracteres para a função GetUserName(). A menos que o nome de usuário no seu computador tenha apenas uma letra, a chamada à função falhará.

Em Delphi o tipo PChar é um ponteiro para uma string terminada em null. Podemos usá-la também, mas, neste caso, somos responsáveis por alocar memória para a string usando a procedure GetMem() e liberá-la explicitamente usando FreeMem(). Veja; 

procedure TForm1.Button1Click(Sender: TObject);
var
  buffer: PChar; // um buffer do tipo PChar
  tamanho: DWORD;
begin
  // vamos informar ao Windows o tamanho do buffer
  tamanho := 256;

  // vamos alocar a memória suficiente para receber o nome
  // do usuário
  GetMem(buffer, tamanho);

  // vamos chamar a função da API do Windows
  if GetUserName(buffer, tamanho) then
    begin
      ShowMessage('O nome de usuário é: ' + buffer);
      // informa a quantidade de caracteres usados. Note que
      // o caractere de término da string também é informado
      ShowMessage('A função usou: ' + IntToStr(tamanho) +
        ' caracteres');
    end
  else
    ShowMessage('Não foi possível obter o nome do usuário');

  // vamos liberar o buffer alocado dinamicamente
  FreeMem(buffer);
end;

Finalmente podemos declarar o buffer como String, usar a procedure SetLength() para ajustar seu tamanho e convertê-la para PChar antes de enviá-la à função GetUserName(). Veja como isso pode ser feito:

procedure TForm1.Button1Click(Sender: TObject);
var
  buffer: String; // um buffer que será convertido para PChar
  tamanho: DWORD;
begin
  // vamos informar ao Windows o tamanho do buffer
  tamanho := 256;

  // aqui há um truque interessante. como não vamos precisar
  // de 256 caracteres para guardar o nome de usuário e não podemos
  // correr o risco de enviar uma string muito pequena, a saída
  // é usar o retorno de GetUserName() para ajustar o tamanho
  // da string depois de enviá-la à função.

  // vamos ajustar o tamanho da string
  SetLength(buffer, tamanho);
  GetUserName(PChar(buffer), tamanho);
  // agora tamanho guarda a quantidade de caracteres usados na função
  SetLength(buffer, tamanho);  // comente esta linha para ver o resultado

  // se o valor de tamanho for 0, então a função falhou
  if tamanho > 0 then
    begin
    ShowMessage('O nome de usuário é: ' + buffer);
      // informa a quantidade de caracteres usados. Note que
      // o caractere de término da string também é informado
      ShowMessage('A função usou: ' + IntToStr(tamanho) +
        ' caracteres');
    end
  else
    ShowMessage('Não foi possível obter o nome do usuário');
end;
Para fins de compatibilidade, esta dica foi escrita usando Delphi 2009.

Como salvar uma imagem JPG em um campo BLOB do Firebird (usando dbExpress) e exibí-la de volta em um TImage

Nesta dica mostro como realizar uma tarefa um pouco mais complicada: como salvar uma imagem JPG (o mesmo pode ser feito para Bitmaps e GIFs com pequenas modificações) em um campo BLOB de uma tabela do Firebird (usando dbExpress) e exibí-la de volta em um TImage. O fato de estarmos usando dbExpress complica um pouco mais, visto que não podemos contar com um componente TDBImage para a exibição da imagem recuperada do banco de dados.

Vamos começar criando a tabela no banco de dados Firebird. Para este exemplo usei uma tabela com três campos somente. Veja o comando SQL DDL CREATE TABLE: 

CREATE TABLE PESSOAS (
  ID    INTEGER NOT NULL,
  NOME  VARCHAR(40),
  FOTO  BLOB SUB_TYPE 0 SEGMENT SIZE 80
);

Embora não esteja detalhado, o campo ID é auto-incremento. Tenha a certeza de criar o GENERATOR/SEQUENCE e o trigger necessários. Se estiver com dúvidas em relação a isso, pesquise minhas dicas sobre o assunto.

Uma vez criada a tabela, coloque um componente TSQLConnection (aba dbExpress) no formulário e efetue a conexão com a base de dados Firebird na qual você criou a tabela anterior. Agora coloque um componente TSQLDataSet (também na aba dbExpress) no formulário e ajuste sua propriedade Connection para o componente de conexão. Finalmente, coloque o código abaixo no evento Click de um botão: 

procedure TForm1.Button1Click(Sender: TObject);
var
  nome: string;
  foto: TFileStream;
begin
  if OpenPictureDialog1.Execute then
    begin
      // nome da pessoa
      nome := Edit1.Text;

      // foto da pessoa
      foto := TFileStream.Create(OpenPictureDialog1.FileName, fmOpenRead);

      // vamos definir o comando SQL a ser executado
      SQLDataSet1.CommandText := 'INSERT INTO PESSOAS(NOME, FOTO) VALUES(:nome, :foto)';
      SQLDataSet1.Params[0].Name := 'nome';
      SQLDataSet1.Params[0].Value := nome;
      SQLDataSet1.Params[1].Name := 'foto';
      SQLDataSet1.Params[1].LoadFromStream(foto, ftGraphic);

      // vamos executar o comando
      SQLDataSet1.ExecSQL(False);

      // vamos mostrar uma mensagem indicando o sucesso da operação
      ShowMessage('A imagem foi salva no banco de dados com sucesso.');
   end;
end;

Aqui a imagem JPG será selecionada a partir de um diálogo TOpenPictureDialog. Note também que o nome da pessoa vem de uma caixa de texto TEdit. Execute a aplicação, escolha uma imagem e salve-a na tabela do banco de dados.

A imagem foi salva com sucesso? Hora de exibí-la de volta em um componente TImage. Para isso coloque um componente TImage no formulário e cole o código abaixo no evento Click de um segundo botão: 

procedure TForm1.Button2Click(Sender: TObject);
var
  id: Integer; // id da pessoa
  foto: TStream;  // um stream para o conteúdo do campo BLOB
  imagem: TJPEGImage;  // a imagem JPG
begin
  // uses Jpeg

  // id da pessoa
  id := 1;

  // vamos definir o comando SQL a ser executado
  SQLDataSet1.Close;
  SQLDataSet1.CommandText := 'SELECT * FROM PESSOAS WHERE ID = :id';
  SQLDataSet1.Params[0].Name := 'id';
  SQLDataSet1.Params[0].Value := id;

  // vamos executar o comando
  SQLDataSet1.Open;

  // vamos obter um stream contendo o conteúdo do campo BLOB
  foto := SQLDataSet1.CreateBlobStream(SQLDataSet1.FieldByName('FOTO'), bmRead);

  // vamos criar uma instância de TJPEGImage
  imagem := TJPEGImage.Create;
  // vamos carregar a imagem a partir do stream TStream
  imagem.LoadFromStream(foto);

  // vamos exibir a imagem no Image1
  Image1.Picture.Assign(imagem);
end;

Aqui nós usamos o método CreateBlobStream() da classe TSQLDataSet para criar um stream a partir do campo BLOB da tabela PESSOAS e atribuí-lo à variável foto, do tipo TStream. Em seguida criamos um objeto da classe TJPEGImage, carregamos a imagem JPG a ser exibida a partir do stream foto e finalmente a exibimos no componente TImage. Não se esqueça de adicionar Jpeg á cláusula uses do seu formulário.

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.