quarta-feira, 2 de março de 2011

Técnicas de depuração em Delphi e Prevenção de Bug


Muitas vezes pegamos um sistema legado de outro programador para realizarmos implementação de novas funcionalidades ou corrigir eventuais "bugs". Neste caso você vai precisar depurá-lo para encontrar os "bugs". O Delphi oferece ótimas ferramentas de depuração e quando você sabe como usá-las, você vai economizar muito tempo para corrigir o "bug" e chegar no resultado desejado
Neste caso quero indicar um tutorial que encontrei e ajudou quando o assunto era depuração de programas.
Aqui está o conteúdo:

Project options - antes que você possa começar a utilizar as ferramentas depurador do Delphi, você tem que certificar-se de todas as configurações necessárias são definidas opções depurador .

Breakpoints - Quando pressionar a tecla F5 ou clicando na barra esquerda do seu editor você pode adicionar uma linha vermelha para a sua fonte. Esta linha de origem terão um ponto de interrupção. Ao executar o programa, a execução irá parar quando ele passa a linha de origem. Agora você pode seguir em sua origem, usando algumas teclas de função.

Call stack - a janela Call Stack exibe as chamadas de função que o trouxe para a sua localização atual no programa e os argumentos passados para cada chamada de função.

Local variables - essa janela vai mostrar todas as variáveis locais e o seu valor atual no atual função ou procedimento.

Watches - você adicionar um Watches para controlar os valores das variáveis do programa ou expressões como você passar por cima ou em código de rastreamento.

Idéias para criar os seus próprios recursos de depuração Prevenção Bug Try-Finally Gotchas Try-Except Gotchas

Criando um gerador de senhas


Veja nesta dica um código simples mas bastante útil, que gera senhas aleatórias podendo conter somente numeros, somente letras ou letras e números. O autor também aborda um pouco do comando try..except. Confira!
Primeiramente, vamos ao tutorial: insira em um form um Edit, abaixo dele um RadioGroup e depois outro Edit. Nesse RadioGroup, procure pela propriedade Items no Object Inspector e adicione o seguinte:

Somente números Somente letras Letras e números

Após isso, adicione dois Buttons. No primeiro mude a propriedade Caption para "Gerar" e o segundo "Limpar". No OnClick do botao "Gerar" coloque o seguinte código:

procedure TForm1.Button1Click(Sender: TObject);
const
  letras = 'abcdefghijklmnopqrstuvxwyzABCDEFGHIJKLMNOPQRSTUVXWYZ';
  numeros = '1234567890';
  letrasnumeros = letras + numeros;
var
  i: integer;
begin
  try
    Edit2.Clear;
    for i := 1 to StrToInt(Edit1.Text) do
    begin
      if RadioGroup1.ItemIndex = 0 then
        Edit2.Text := Edit2.Text + numeros[random(length(numeros)) + 1]
      else if RadioGroup1.ItemIndex = 1 then
        Edit2.Text := Edit2.Text + letras[random(length(letras)) + 1]
      else if RadioGroup1.ItemIndex = 2 then
        Edit2.Text := Edit2.Text + letrasnumeros[random(length(letrasnumeros)) + 1];
    end;
  except
    showmessage('Insira somente números no primeiro Edit');
  end;
end;
Explicando

Criamos uma variavel i, do tipo inteira, que irá receber a quantidade de caracteres que o usuário quiser para a sua senha. Por isso convertemos o valor do Edit1.Text de String para Inteiro (StrToInt) dentro do for. Criamos também três constantes, adicionando a cada uma respectivamente as letras, números ou as duas juntas.

O comando "Try" funciona da seguinte maneira: falamos para o Delphi tentar executar esse código e, caso ele não conseguir, podemos utilizar o Except para apresentar, por exemplo, algumas mensagens de erro do que pôde acontecer. No exemplo, deve ser informado no Edit1 a quantidade de caracteres da senha e, caso a pessoa coloque letras ao invés de números, a função StrToInt não conseguirá ser executada. Com o Except, conseguimos informar ao usuário este problema e tiramos a mensagem de erro que o delphi emitiria, em inglês.

No segundo botão, coloque apenas:

procedure TForm1.Button2Click(Sender: TObject);
begin
  Edit2.Clear;
end;
Após isso efetue a seguinte alteração no seu Delphi : em Tool>Options, procure por Language Execeptions e desmarque "Notify on Language Execeptions". Isto fará com que o compilador do Delphi não interrompa o programa com as mensagens do depurador e deixe a mensagem ir diretamente ao programa.

Nesse momento, compile e rode sua aplicação, informe um número no primeiro edit, selecione um método de geração e veja a senha gerada no segundo edit. É o nosso código em funcionamento!

Pesquisa fonética no MySQL

Fonte: www.activedelphi.com.br

Olá pessoal! Há algum tempo atrás precisei fazer uma consulta por fonema em meu banco de dados e não achei muita coisa na internet, mas descobri que o MySQL a partir da versão 3 acrescentou uma função chamada soundex, que outros bancos até já utilizam, como o Oracle, por exemplo. Nesta dica mostrarei uma consulta simples, que pode ser implementada em qualquer linguagem de programação, pois é um código SQL.
Primeiramente vamos criar um banco no mysql:

shell>mysql –useuusario –psuasenha
mysql>create database fonema;
Query OK, 1 row affected (0.01 sec)
Agora vamos selecionar para uso o banco que acabamos de criar:

mysql>use fonema;
Database changed
Criando nossa tabela de teste:

mysql>create table fonetica (
cod INTEGER NOT NULL AUTO_INCREMENT,
nome VARCHAR(60) NOT NULL,
PRIMARY KEY (cod)
)
ENGINE = InnoDB;
Query OK, 0 rows affected (0.08 sec)
Vamos inserir alguns dados nesta tabela. No comando abaixo, dois nomes somente:

mysql>insert into fonetica (nome) values (“JAIME ADRIANO”),(“JAYME ADRIANO”);
Query OK, 2 rows affected (0.09 sec)
Records: 2 Duplicates: 0 Warnings: 0
Agora vamos a nossa consulta:

mysql>select * from fonetica where SOUNDEX(nome) like
    ->CONCAT(SOUNDEX(“JAIME ADRIANO”),”%”);
+-----+---------------+
 cod    nome
+-----+---------------+
 6      JAIME ADRIANO
 7      JAYME ADRIANO
+-----+---------------+
2 rows in set (0.00 sec)
Perceba que o banco retornou Jaime com i e com y, que foneticamente são pronunciados da mesma forma. Faça um teste ao contrario, colocando o nome JAYME na consulta, com y, e verá que ele também retornará os dois nomes com a mesma fonética.

Espero ter ajudado e daí por diante é com vocês! Façam as implementações e melhorias e postem aqui para ajudar outras pessoas. Esta dica foi extraida do meu blog, achei interessante postar aqui!

segunda-feira, 28 de fevereiro de 2011

Mudar a letra da unidade usando WMI e Delphi

Fonte: www.activedelphi.com.br

Veja nesta dica uma aplicação console com o código fonte de exemplo para se alterar a letra de unidade de disco (volume) através do WMI. A chave é usar a classe Win32_Volume e alterar a propriedade DriverLetter. Esta propriedade é de leitura e escrita, sendo assim, podemos atualiza-la diretamente e então chamar o método Put_ do objeto SWbemObject.
Para rodar o programa e fazer os testes, solicite no Delphi uma nova "Console Application", apague todo o seu conteúdo e coloque o código abaixo:

program ChangeVolumeLetter_WMI;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils,
  ActiveX,
  ComObj;
 
procedure  ChangeDriveLetter(OldDrive, NewDrive:Char);
var
  FSWbemLocator : OLEVariant;
  FWMIService   : OLEVariant;
  FWbemObjectSet: OLEVariant;
  FWbemObject   : OLEVariant;
  oEnum         : IEnumvariant;
  iValue        : LongWord;
begin;
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  FWbemObjectSet:= FWMIService.ExecQuery(
    Format('SELECT * FROM Win32_Volume Where DriveLetter=%s',
           [QuotedStr(OldDrive+':')]),
    'WQL',0);
  oEnum         := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
    //Define a nova letra
    FWbemObject.DriveLetter:=NewDrive+':';
    //Aplica as mudanças
    FWbemObject.Put_();
  end;
end;
 
begin
 try
    CoInitialize(nil);
    try
      //Mudará a letra da unidade E para Z
      ChangeDriveLetter('E','Z');
      Readln;
    finally
      CoUninitialize;
    end;
 except
    on E:Exception do
    begin
        Writeln(E.Classname, ':', E.Message);
        Readln;
    end;
  end;
end.
Aí é só rodar e conferir a letra da unidade modificada, neste exemplo, alterando a unidade E para Z.

Algumas explicações na internet (em inglês):

WMI - Windows Management Instrumentation
Win32_Volume
Método Put_
SWbemObject

sexta-feira, 25 de fevereiro de 2011

Relatório em PDF usando o Delphi 2006


Olá pessoal! Essa dica é pra quem quer exportar seus relatório feitos no QuickReport para arquivos PDF, usando o Delphi 2006 ou superior.
Segue abaixo o código utilizado:
procedure TQRStandardPreview.btnExportarClick(Sender: TObject);
var
  PDFFilt : TQRPDFDocumentFilter;
  FileExt, dir : string;
  I : integer;
begin
  dir := ExtractFilePath( Application.ExeName );
  FileExt := QRPreview.QRPrinter.Title;
  FileExt := FileExt + '.pdf';
  PDFFilt := TQRPDFDocumentFilter.Create( FileExt );
  try
    PDFFilt.AddFontMap( 'WebDings:ZapfDingBats' );
    PDFFilt.TextOnTop := true;
    PDFFilt.LeftMargin := 0;
    PDFFilt.TopMargin := 0;
    PDFFilt.CompressionOn := False;
    PDFFilt.Concatenating := True;
    QRPreview.QRPrinter.ExportToFilter( PDFFilt );
    PDFFilt.EndConcat;
  finally
    PDFFilt.Free;
  end;
end;
Lembrando que devemos acrenscentar na seção uses a unit "QRPDFFilt"

quarta-feira, 23 de fevereiro de 2011

Validando endereços de e-mail


Veja nesta dica uma função que apresenta como validar um endereço de e-mail, evitando que sejam informados dados incorretos nos cadastros.

Segue a implementação:

function ValidaEmail(sEmail: string): boolean;
const
  // Caracteres válidos
  ATOM_CHARS = [#33..#255] - ['(', ')', '<', '>', \@\, ',', ';', ':',
                              '\', '/', '"', '.', '[', ']', #127];

  // Caracteres válidos em uma cadeia
  QUOTED_STRING_CHARS = [#0..#255] - ['"', #13, '\'];

  // Caracteres válidos em um subdominio
  LETTERS = ['A'..'Z', 'a'..'z'];
  LETTERS_DIGITS = ['0'..'9', 'A'..'Z', 'a'..'z'];
  SUBDOMAIN_CHARS = ['-', '0'..'9', 'A'..'Z', 'a'..'z'];

type
  States = (STATE_BEGIN, STATE_ATOM, STATE_QTEXT, STATE_QCHAR,
    STATE_QUOTE, STATE_LOCAL_PERIOD, STATE_EXPECTING_SUBDOMAIN,
    STATE_SUBDOMAIN, STATE_HYPHEN);
var
  State: States;
  i, n, iSubdomains: integer;
  c: char;
begin
  State := STATE_BEGIN;
  n := Length(sEmail);
  i := 1;
  iSubdomains := 1;
  while (i <= n) do
  begin
    c := sEmail[i];
    case State of
      STATE_BEGIN:
        if c in atom_chars then
          State := STATE_ATOM
        else if c = '"' then
          State := STATE_QTEXT
        else
          break;
      STATE_ATOM:
        if c = \@\ then
          State := STATE_EXPECTING_SUBDOMAIN
        else if c = '.' then
          State := STATE_LOCAL_PERIOD
        else if not (c in atom_chars) then
          break;
      STATE_QTEXT:
        if c = '\' then
          State := STATE_QCHAR
        else if c = '"' then
          State := STATE_QUOTE
        else if not (c in quoted_string_chars) then
          break;
      STATE_QCHAR:
        State := STATE_QTEXT;
      STATE_QUOTE:
        if c = \@\ then
          State := STATE_EXPECTING_SUBDOMAIN
        else if c = '.' then
          State := STATE_LOCAL_PERIOD
        else
          break;
      STATE_LOCAL_PERIOD:
        if c in atom_chars then
          State := STATE_ATOM
        else if c = '"' then
          State := STATE_QTEXT
        else
          break;
      STATE_EXPECTING_SUBDOMAIN:
        if c in letters then
          State := STATE_SUBDOMAIN
        else
          break;
      STATE_SUBDOMAIN:
        if c = '.' then
        begin
          Inc(iSubdomains);
          State := STATE_EXPECTING_SUBDOMAIN
        end
        else if c = '-' then
          State := STATE_HYPHEN
        else if not (c in letters_digits) then
          break;
      STATE_HYPHEN:
        if c in letters_digits then
          State := STATE_SUBDOMAIN
        else if c <> '-' then
          break;
    end;
    Inc(i);
  end;

  if i <= n then
    Result := False
  else
    Result := (State = STATE_SUBDOMAIN) and (iSubdomains >= 2);

  //se sEmail esta vazio retorna true
  if sEmail = '' then
    Result := true;
end;

Para testar, adicione a um novo formulário um Edit e um Button, programando no evento onClick deste último:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if ValidaEmail(Edit1.Text) then
    ShowMessage('Ok! E-mail válido!')
  else
    ShowMessage('E-mail inválido!');
end;

Agora rode o programa e faça os testes digitando vários endereços de e-mail do Edit1 e clicando sobre o botão.

terça-feira, 22 de fevereiro de 2011

Automação de Queries

Fonte: www.activedelphi.com.br

Desenvolvendo um sistema para uma clínica escola de psicologia, identifiquei que, apesar de o sistema estar bem avançado, estava cheio de códigos de manipulação de query repetidos, e por isso resolvi mudar esta situação. A solução, você confere abaixo
Os códigos eram todos parecidos, como abaixo:

  with dm.query do
  begin
    close;
    sql.Clear;
    sql.Add('select * from tabela where campo = valor');
    open;
  end;

Então fiz uma procedure que com uma linha faz tudo isso:

class procedure Tdm.qrcon(componente: Tadoquery; tabela, campo, valor: string; 
  operacao: integer);
begin
  case operacao of
    //seleciona tudo
    1: with componente do
      begin
        close;
        sql.Clear;
        sql.Add('select * from ' + tabela);
        open;
      end;
    2: with componente do
      begin
        close;
        sql.Clear;
        sql.Add('select * from ' + tabela + ' where ' + campo + 
                ' = ' + quotedstr(valor));
        open;
      end;
    3: with componente do
       begin
        close;
        sql.Clear;
        sql.Add('delete from ' + tabela + ' where ' + campo + ' = ' + valor);
        execsql;
       end;
  else
    MessageBox(0, 'Erro de parametro de consulta.' + #13#10 + 
                  '          Contate o CPD.', 
                  'Erro de parametro de consulta.', MB_ICONSTOP or MB_OK);
  end;
end;

Curso de Delphi: 7.Consultas SQL