quarta-feira, 12 de janeiro de 2011

Substituindo um arquivo INI por um documento XML.

Este código mostra como usar TXMLDocument para salvar e restaurar configurações em um documento XML. O método publico trabalha como um TIniFile. O código não precisa ser comentado porque é auto explicativo e pequeno. Foi testado apenas no Delphi 7.


unit uCiaXml;

interface

uses
Forms, SysUtils, Windows, XmlIntf, XMLDoc;

type
TXMLConfig = class
private
FModified: Boolean;
FFileName: string;
FXMLDoc: TXMLDocument;
FBackup: Boolean;
function GetVersion: string;
public
constructor Create(const FileName: string); overload;
constructor Create; overload;
destructor Destroy; override;
procedure Save;
function ReadString(const Section, Key, default: string): string;
procedure WriteString(const Section, Key, Value: string);
function ReadInteger(const Section, Key: string; default: Integer): Integer;
procedure WriteInteger(const Section, Key: string; Value: Integer);
function ReadBoolean(const Section, Key: string; default: Boolean): Boolean;
procedure WriteBoolean(const Section, Key: string; Value: Boolean);
property Backup: Boolean read FBackup write FBackup;
property Version: string read GetVersion;
end;

implementation

{ TXMLConfig }

constructor TXMLConfig.Create(const FileName: string);
begin
inherited Create;
FBackup := True;
FFileName := FileName;
FXMLDoc := TXMLDocument.Create(Application);
FXMLDoc.Options := [doNodeAutoIndent];
if FileExists(FFileName) then
FXMLDoc.LoadFromFile(FFileName)
else
begin
FXMLDoc.Active := True;
FXMLDoc.AddChild('Configuration');
end;
end;

constructor TXMLConfig.Create;
begin
Create(ChangeFileExt(Application.Exename, '_cfg.xml'));
end;

destructor TXMLConfig.Destroy;
begin
Save;
FXMLDoc.Destroy;
inherited;
end;

function TXMLConfig.GetVersion: string;
begin
Result := '1.00';
end;

function TXMLConfig.ReadBoolean(const Section, Key: string; default: Boolean): Boolean;
begin
Result := Boolean(ReadInteger(Section, Key, Integer(default)));
end;

function TXMLConfig.ReadInteger(const Section, Key: string; default: Integer): Integer;
begin
Result := StrToInt(ReadString(Section, Key, IntToStr(default)));
end;

function TXMLConfig.ReadString(const Section, Key, default: string): string;
var
Node: IXMLNode;
begin
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
if Assigned(Node) and Node.HasAttribute(Key) then
Result := Node.Attributes[Key]
else
Result := default;
end;

procedure TXMLConfig.Save;
begin
if not FModified then
Exit;
if FBackup then

CopyFile(PChar(FFileName), PChar(FFileName + '.bak'), False);
FXMLDoc.SaveToFile(FFileName);
FModified := False;
end;

procedure TXMLConfig.WriteBoolean(const Section, Key: string; Value: Boolean);
begin
WriteInteger(Section, Key, Integer(Value));
end;

procedure TXMLConfig.WriteInteger(const Section, Key: string; Value: Integer);
begin
WriteString(Section, Key, IntToStr(Value));
end;

procedure TXMLConfig.WriteString(const Section, Key, Value: string);
var
Node: IXMLNode;
begin
if ReadString(Section, Key, '') = Value then
Exit;
Node := FXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
if not Assigned(Node) then
Node := FXMLDoc.DocumentElement.AddChild(Section);
Node.Attributes[Key] := Value;
FModified := True;
end;

end.

Download de arquivos na WEB

Esta dica tem por objetivo mostrar como é fácil fazer o download de arquivos na WEB.

Declare na cláusula uses: URLMon

Esta função é responsável pelo download do arquivo na WEB.

function DownloadFile(Source, Dest: string): Boolean;
begin
try
   Result := UrlDownloadToFile(nil, PChar(source), PChar(Dest), 0, nil) = 0;
except
   Result := False;
end;
end;

Insira no evento OnClick de um botão o seguinte código:

procedure TForm1.Button1Click(Sender: TObject);
begin
if DownloadFile ('http://www.dicasdelphi.xpg.com.br/downloads/DicasDelphi.zip', 'c:\windows\desktop\dicasdelphi.zip') then
   ShowMessage('Download Concluído!')
else
   ShowMessage('Falha ao fazer o download!!')
end;

Enviando email com Delphi pelo componente NMSMTP

Nesta dica a seguir vamos enviar um email utilizando o componente NMSMTP do Delphi.

Crie um novo projeto e insira um componente do tipo TNMSMTP na aba FastNet da VCL do Delphi

Adicione ao formulário um objeto Button e coloque o codigo a seguir no evento OnClick do objeto.

procedure TForm1.Button1Click(Sender: TObject);
begin
NMSMTP1.Host := 'servidoremailsmtp.com';
NMSMTP1.UserID := 'nomedousuario'; // Nome do Usuário
NMSMTP1.Connect; // Conecta no servidor smtp

NMSMTP1.PostMessage.FromAddress := 'remetente@seudominio.com';
NMSMTP1.PostMessage.ToAddress.Text := 'destino@dominio.com';
NMSMTP1.PostMessage.Body.Text := 'Coloque aqui sua mensagem';
NMSMTP1.PostMessage.Subject := 'Assunto do Email';
NMSMTP1.SendMail; // Envia o email
end;

Com poucas linhas de código é possivel enviar um email pelo delhi através do componente NMSMTP.
Se você quiser sofisticar sua aplicação pode faze-la buscar valores do e-mail, corpo da mensagem e assunto de um banco de dados ou objetos tipo edit.

Abrir automaticamente seu navegador padrão e carregar a pagina determinada pelo link

1º Declare o procedure na seção PUBLIC da unit. 
   procedure JumpTo(const aAdress: String); 

2º Coloque a cláusula ShellAPI na uses no início da unit. 

procedure TForm1.JumpTo(const aAdress: String); 
var 
       buffer: String; 
begin 
       buffer := 'http://' + aAdress; 
       ShellExecute(Application.Handle, nil, PChar(buffer), nil, nil, SW_SHOWNORMAL); 
end; 

procedure TForm1.Label1Click(Sender: TObject); 
begin 
         JumpTo('www.geocities.com/SiliconValley/Way/1497'); 
end; 

terça-feira, 11 de janeiro de 2011

Imprimir com precisão Milimétrica

O objeto Canvas que está na classe Printer é uma ferramenta que ajuda muito a imprimir qualquer tipo de dados,
sejam eles texto ou gráficos. O problema é que a largura e a altura são determinadas em pixels, e esses valores
variam de acordo com a resolução da impressora. Para converter de milímetros para pixels, use as funções abaixo,
sendo que MMtoPixelX é para a resolução horizontal e MMtoPixelY é para a resolução vertical (porque na
impressora é possível uma resolução como 1440x720 dpi - 1440 dpi para a horizontal e 720 dpi para a vertical, por
exemplo):

function MMtoPixelX (MM : Integer) : Longint;
var
mmPointX : Real;
PageSize, OffSetUL : TPoint;
begin
mmPointX := Printer.PageWidth / GetDeviceCaps(Printer.Handle,HORZSIZE);


Escape (Printer.Handle,GETPRINTINGOFFSET,0,nil,@OffSetUL);
Escape (Printer.Handle,GETPHYSPAGESIZE,0,nil,@PageSize);
if MM > 0 then
Result := round ((MM * mmPointX) - OffSetUL.X)
else
Result := round (MM * mmPointX);
end;

function MMtoPixelY (MM : Integer) : Longint;
var
mmPointY : Real;
PageSize, OffSetUL : TPoint;
begin
mmPointY := Printer.PageHeight /
GetDeviceCaps(Printer.Handle,VERTSIZE);
Escape (Printer.Handle,GETPRINTINGOFFSET,0,nil,@OffSetUL);
Escape (Printer.Handle,GETPHYSPAGESIZE,0,nil,@PageSize);
if MM > 0 then
Result := round ((MM * mmPointY) - OffSetUL.Y)
else
Result := round (MM * mmPointY);
end;

Imprimir texto justificado na lx-300

A impressora Epson LX-300 dispõe de um comando que justifica o texto. Este recurso é interessante, pois com ele podemos continuar a enviar os comandos de formatação de caracteres como condensado, negrito, italico, expandido, etc.

Para o exemplo abaixo:
- Coloque um botão no form;
- Altere o evento OnClick deste botão como abaixo:

procedure TForm1.Button1Click(Sender: TObject);
const
cJustif = #27#97#51;
cEject = #12;

{ Tamanho da fonte }
c10cpi = #18;
c12cpi = #27#77;
c17cpi = #15;
cIExpandido = #14;
cFExpandido = #20;
{ Formatação da fonte }
cINegrito = #27#71;
cFNegrito = #27#72;
cIItalico = #27#52;
cFItalico = #27#53;
var
Texto: string;
F: TextFile;
begin
Texto := c10cpi +
'Este e um teste para impressora Epson LX 300. ' +
'O objetivo e imprimir texto justificado sem deixar ' +
'de usar formatacao, tais como: ' +
cINegrito + 'Negrito, ' + cFNegrito +
cIItalico + 'Italico, ' + cFItalico +
c17cpi + 'Condensado (17cpi), ' + c10cpi +
c12cpi + '12 cpi, ' + c10cpi +
cIExpandido + 'Expandido.' + cFExpandido +
' Este e apenas um exemplo, mas voce podera adapta-lo ' +
'a sua realidade conforme a necessidade.';

AssignFile(F, 'LPT1');
Rewrite(F);
try
WriteLn(F, cJustif, Texto);
WriteLn(F, cEject);
finally
CloseFile(F);
end;
end;

Trocar impressora padrão do Windows

Uma dúvida muito frequente em nossos mails são referentes a troca de impressoras em determinados relatórios. A rotina que apresentamos a seguir realiza essa troca:

procedure TForm1.FormShow(Sender: TObject);
var
i: integer;
begin
// Limpa a lista de impressoras mostradas
ListBoc1.Items.Clear;
// Atualiza listbox com nome das impressoras
for i := 1 to Printer.Printers.Count do
ListBox1.Items.Add(Printers[i - 1]);
end;
Para selecionar uma determinada impressora, basta atribuir um inteiro à Printer.PrinterIndex, como você verá a
seguir:
Printer.PrinterIndex := ListBox1.ItemIndex;

segunda-feira, 10 de janeiro de 2011

Enviando caracteres diretamente ao buffer da impressora

Ao trabalharmos com impressão, em certos casos desejamos alterar o comportamento da impressora.

Algumas opções, principalmente em impressoras matriciais, são obtidas através do envio dos chamados "códigos de escape" para a impressora (por exemplo, alterar espaçamento entre as linhas (#45), tipo de fonte (#18, #23), etc). Em versões 16-bit do Windows, isso não era complicado, mas agora, nas versões 32-bit, o acesso direto ao hardware não é mais possível.

Portanto, para enviarmos caracteres diretamente a impressora, devemos utilizar o "escape" chamado "PASSTHROUGH" do Windows e enviarmos a informação desejada diretamente.

Na documentação do Win32 SDK este escape é dado como obsoleto, mas enquanto utilizarmos impressoras matriciais que necessitem de "códigos escape" para certas funcionalidades, ele será necessário.

Ao utilizar impressoras Postscript tenha cuidado, pois nem sempre esta técnica irá funcionar. Em impressoras matriciais, você pode enviar qualquer tipo de caracteres que achar necessário.

Abaixo segue um código exemplificando o envio de uma string qualquer diretamente ao buffer da impressora:

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

uses Printers;

type
{ Tipo requerido pelo PASSTHROUGH }
TBufferImpressora = record
TamanhoBuffer: Word;
Buffer: array [0..255] of Char;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
       Buff: TBufferImpressora;
       TestePasstrough: Integer;
       strFoo: string;
begin
{ Primeiro devemos checar se o "escape" PASSTHROUGH é suportado. Para isso, executamos a função "Escape" passando o QUERYESCSUPPORT. Caso o driver suporte, ela irá retornar um valor maior que 0 }
       TestePasstrough := PASSTHROUGH;
       if Escape(Printer.Handle, QUERYESCSUPPORT, SizeOf(PASSTHROUGH), @TestePasstrough, nil) > 0 then
       begin
                   { Inicializamos o driver }
                   Printer.BeginDoc;
                   { Informação qualquer a enviar diretamente para a impressora }
                   strFoo := 'Passthrough string';
                   { Copia da string para a estrutura }
                   StrPCopy(Buff.Buffer, strFoo);
                   { Indicamos o tamanho da informação}
                   Buff.TamanhoBuffer := StrLen(Buff.Buffer);
                   { Enviamos o "escape" }
                   Escape(Printer.Canvas.Handle, PASSTHROUGH, 0, @Buff,nil);
                  { Descarregamos... }
                  Printer.EndDoc;
       end;
end;

end.

Enviando informações direto para a impressora

Muitas vezes torna-se necessário, ou até mesmo, imprescindível que você envie informações diretamente para a impressora, uma vez que a utilização da impressão típica do Windows é um pouco demorada e o uso do driver Genérico/Somente Texto não é muito confiável.

Uma boa solução para enviar informações diretamente para a impressora é usar o seguinte código:

Procedure TForm1.Button1Click(Sender: Object);
var
         Imp: TextFile;
begin
         AssignFile(Imp, 'LPT1');
         Rewrite(Imp);
         Write(Imp, 'Isto vai sair na impressora');
         CloseFile(Imp);
end;

Desta forma será possível, inclusive, utilizar os códigos de configuração da impressora. Para a impressora padrão Epson, por exemplo, você poderia utilizar algo assim:

Write(Imp, #27#69 + 'Teste' + #27#70); { impressão em negrito }
Write(Imp, #15 + 'Teste' + #18); { impressão no modo condensado }
Write(Imp, #12); { salto de página }

Conhecendo os Fundamentos do ICMS ST (Substituição Tributária)


Olá Amigos! Resolvi escrever sobre um assunto complicado para os programadores, principalmente os iniciantes! Lembro-me que quando comecei, logo de cara tinha que fazer um cálculo de Substituição Tributária em um software de emissão de notas fiscais
Os problemas apareceram quando resolvi perguntar ao contador do cliente. Aí sim descobri que quase ninguém domina esse assunto! Felizmente isso são águas passadas. Hoje resolvi escrever esse artigo para ajudar aqueles que estão passando por algo parecido.

Vou utilizar algumas nomenclaturas comuns para quem já está trabalhando com NFe (Nota Fiscal Eletrônica).

Base de cálculo (BC)

A Lei Complementar nº 87/96 em seu artigo 8º, ao tratar do regime de sujeição passiva por substituição, determina que a base de cálculo será o valor correspondente ao preço de venda a consumidor acrescido do valor do frete, IPI e demais despesas debitadas ao estabelecimento destinatário, bem como a parcela resultante da aplicação (sobre esse total) do percentual de valor agregado (margem de lucro). Esse percentual é estabelecido em cada caso de acordo com as peculiaridades de cada mercadoria.

BC = (Valor mercadoria + frete + IPI + outras despesas) x Margem de lucro

Margem de valor agregado

A margem de valor agregado será determinada com base em preços usualmente praticados no mercado, obtidos por levantamento, ainda que por amostragem ou através de informações e outros elementos fornecidos por entidades representativas dos setores, adotando-se a média ponderada dos preços coletados. A mercadoria submetida ao regime de substituição tributária em operação interestadual terá a margem de valor agregado estabelecida em Convênio ou Protocolo.

Esse campo o escritório de contabilidade deverá fornecer ao cliente. 

Forma para realizar o cálculo

Devemos pensar em dois pontos básicos: trabalhar com o ICMS da OPERAÇÃO PRÓPRIA e o ICMS DAS OPERAÇÕES SUBSEQUENTES. Assim Temos:

O ICMS da operação própria - realizará uma seqüência de operações matemáticas para chegar a um valor que será utilizado no próximo item.
O ICMS das operações subsequentes - realizará os cálculos necessários para chegar ao valor do ICMS – ST.

Vou exemplificar. Pense em uma operação realizada por um fabricante de brinquedos estabelecido no estado de São Paulo, vendendo à um cliente do mesmo estado. A venda é de R$ 1.000,00 e com IPI calculado a uma alíquota de 5%, teremos:

Nosso 1º passo será realizar o cálculo do ICMS de Operação Própria:
ICMS da operação própria = R$ 1.000,00 x 18% (SP para SP) = R$ 180,00*
* Devemos guardar esse resultado em uma variável para uso futuro

2º Passo, calcular a Base de Cálculo ST:
Base cálculo da ST = R$ 1.000,00 + R$ 50,00 (5% de IPI) + 52% (margem de valor agregado) = R$ 1.596,00

3º Passo, encontrar o valor do ICMS ST
R$ 1.596,00 x 18% (SP para SP) = R$ 287,28

O valor do imposto substituição será a diferença entre o calculado no 1º passo e o do 3º passo. Você se lembra daquela variável guardada no 1º passo? Pois bem, agora usaremos ela para realizar o cálculo da diferença.

R$ 287,28 – R$ 180,00 = R$ 107,28

Pronto, o valor do ICMS – ST é R$ 107,28

sexta-feira, 7 de janeiro de 2011

Conexão com Balanças - Entendo os Códigos Emitidos pela Balança


Como nesse artigo o objetivo é explicar como funcionam os códigos emitidos pela balanças eletrônicas, vou postar uma dúvida que eu peguei em um fórum de automação comercial que participo.

Pergunta:
"Gostaria de entender os Códigos Emitidos pelas Balanças Computadoras (Platina, Prix, etc)
Tipo todas elas emitem o Código com inicio 2 então no meu sistema já sei se o recebido tiver 2 no inicio isso indicado que é algo na balança. até ai tudo bem...
Porem não consegui entender os outros dígitos que estão junto...
Se não estou enganado o ultimo seria digito verificador outros seriam o Código do Produto e outros seriam o total do produto.
o Meu problema esta ai abstrair o restante...
Também sei que tem tamanhos de códigos diferentes alguns com 4 dígitos outros com 6 dígitos mas não consegui ligar muito as coisas não"
Resposta:
Pode haver algumas variações na etiqueta impressa. Essas variações podem ser:
A - 2 C C C C 0 T T T T T T DV
B - 2 C C C C 0 0 P P P P P DV
C - 2 C C C C C T T T T T T DV
D - 2 C C C C C 0 P P P P P DV
E - 2 C C C C C C P P P P P DV
Onde:
2 - Digito 2 sempre
C - Código do Produto
0 - Espaço, não utilizado
T - Valor Total a Pagar
P - Peso ou Quantidade
DV- Digito Verificador EAN-13
Obs: Estes modelos podem ser configurados no programa que acompanha as balanças.
Para que o seu sistema saiba qual o tipo do código de barras que será impresso na balança, ou seja, para que você saiba como tratar no seu sistema, temos que criar uma tela de configuração para armazenar as posições da etiqueta.
Veja na figura abaixo um exemplo que serve para configurarmos corretamente as variações que podem acontecer nas etiquetas.
Com isso tudo configurado, quando o caixa (funcionário), por exemplo, passar um código de barras de um produto no PDV, o mesmo vai saber em qual posição está o peso do produto, código, preço e etc.
O que poderíamos fazer é verificar se o código de barras começa com o digito 2. Se for, já sabemos que trata-se de um código vindo da balança. Agora só nos resta pegarmos as informações que a etiqueta traz.

Ex:
Codigo de balança -> 2 0 1 0 1 0 0 0 0 0   9  0  7
Posições          -> 1 2 3 4 5 6 7 8 9 10 11 12 13
1 - prefixo balança;
2 a 5 ou 7 - código produto;
8 a 12 - preço na etiqueta


Conclusão

Bom, esse artigo foi para explicar como funcionam os códigos de barras impressos pelas balanças eletrônicas. Nos próximos artigos vou apresentar o componente acbrBal, que é para Leitura de informações de Balanças eletrônicas (Filizola, Toledo, Urano, etc) e que faz parte do projeto open source Acbr.
Para realizar a comunicação serial o projeto acbr usa a classe SynaSer
Projeto: Ararat Synapse (http://www.ararat.cz/synapse/)

Sérgio de Castro Guedes 
Contato: sergio_rj45@yahoo.com.br 
Programador com experiência em banco de dados MSSQL, Firebird e 
Oracle. Moderador de Conteúdo do Fórum, Editor Técnico e Colunista do Portal Active Delphi.
Administrador do Projeto Open Source Sia Consult (Sistema Comercial ERP).
Membro do projeto Acbr (Automação Comercial Brasil) e Desenvolvedor da VAP Informática, umas das maiores empresas de software de Manaus AM.

Referencias
- André Ferreira de Moraes - Membro do Projeto Acbr (http://acbr.sourceforge.net)
- Fórum do Projeto ACbr (http://www.forumweb.com.br/foruns/index.php?showforum=465)

Protegendo seu sistema contra cópias ilegais


Apresentarei aqui uma técnica que utiliza o serial lógico de uma unidade de disco do computador, que apesar de poder ser modificada após uma formatação, por exemplo, já é um bom começo!
Bom, vamos lá. Tendo em vista a preocupação dos colegas com pirataria e cópias ilegais, desenvolvi um código que verifica o número de série de um determinado dispositivo conectado ao computador e faz uma comparação.
Abaixo há uma função que pega o número de serie do CD que esta na respectiva unidade. O sistema só irá rodar se aquele determinado CD estiver no drive. Tanto faz se vc colocar o CD na unidade D, E ou F, a função irá verificar cada unidade a procura do número de serie correto e caso não o ache retorna false. Apesar da idéia ser criada com base em um CD, pode ser adaptada para o uso com HD's.
Para testar o código, você precisará acrescenta rum label e um button em seu form. Em seguida, implementar a funçãotbVolSerial, a procedure VerificalSerialH e o evento onClick do botão, conforme abaixo:
// função que pega o numero serial do dispositivo 
function Tform2.tbVolSerial(const Drive: Char; Path: PChar): Cardinal; 
var 
  MaxCompLen, FileSysFlag, PrevErrorMode: Cardinal;
begin
  if Path = nil then 
    Path := PChar(Drive + ':');
  PrevErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
  try
    if not GetVolumeInformation(PChar(Path), nil, 0, @Result, MaxCompLen,
      FileSysFlag, nil, 0) then 
      Result := 0;
  finally 
    SetErrorMode(PrevErrorMode);
  end; 
end;
 
//Esta função faz a varredura em todos os dispositivos a
//procura do serial valido. retorna true ou false. 
procedure Tform2.VerificaSerialH(Driver: char); 
const 
  drive: array[0..25] of char = (
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
    'r', 's', 't', 'u', 'w', 'v', 'x', 'y', 'z'); 
var 
  j: integer;
  ini: TIniFile;
  SerialHardware, AdquireSerial: string;
  erro: Boolean;
begin
  if not FileExists('.serial.ini') then
  begin 
    AdquireSerial := IntToStr(tbVolSerial(Driver, nil));
    ini := TIniFile.Create('.serial.ini');
    ini.WriteString('serial', 'Hardware', AdquireSerial);
    ini.Free;
  end
  else
  begin 
    ini := TIniFile.Create('.serial.ini');
    SerialHardware := ini.ReadString('serial', 'Hardware', '');
    ini.free;
  end;
 
  for j := 0 to 25 do
  begin
    if (IntToStr(tbVolSerial(Drive[j], nil))) = SerialHardware then
    begin 
      Erro := false;
      Label1.Caption := 'Original';
      break;
    end
    else 
      Erro := true;
  end;
 
  if Erro then    Label1.Caption := 'Pirata' 
end;
 
procedure Tform2.Button1Click(Sender: TObject); 
begin 
  Label1.Caption := 'Este sistema é...';
  Label1.Repaint;
  VerificaSerialH('G'); 
end;

quinta-feira, 6 de janeiro de 2011

Convertendo a 1ª letra de um edit para maiúsculas

Esta dica é útil para ser utilizada no cadastramanto de nomes.

Se o operador do sistema esquecer de colocar a primeira letra de um nome em minúscula, automaticamente a letra ficará maiúscula.

Para que isto ocorra, coloque um objeto edit no formulário e no seu evento OnChange insira o seguinte código:

var
Variavel : Integer;

begin
With Edit1 do
if Text <> '' then
begin
OnChange := NIL;
Variavel := SelStart;
Text := UpperCase(Copy(Text,1,1))+LowerCase(Copy(Text,2,Length(Text)));
SelStart := Variavel;
OnChange := Edit1Change;
end;
end;

Como gerar senhas aleatórias

Segue abaixo rotina para gerar senhas aleatórias.

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
const
str='1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ';
max=6;
begin
Edit1.Text:='';
for i:=1 to max do
begin
   Edit1.Text:=Edit1.Text+str[random(length(str))+1];
end;
end.

Checagem de CEP por Estado

Verifica se um CEP é valido ou não, passando o Estado e o Cep como parâmetro.



function ChecaCEP(cCep:String ; cEstado:String): Boolean;
var
cCEP1 : Integer;
begin
cCep := copy(cCep,1,5) + copy(cCep,7,3);
cCEP1 := StrToInt(copy(cCep,1,3));
if Length(trim(cCep)) > 0 then
   begin
   if (StrToInt(cCep) <= 1000000.0) then
       begin
       MessageDlg('CEP tem que ser maior que [01000-000]',mtError,[mbOk],0);
       Result := False
       end
   else
   begin
     if Length(trim(copy(cCep,6,3))) < 3 then Result := False else
     if (cEstado = 'SP') and (cCEP1 >= 10 ) and (cCEP1 <= 199) then Result := True else
     if (cEstado = 'RJ') and (cCEP1 >= 200) and (cCEP1 <= 289) then Result := True else
     if (cEstado = 'ES') and (cCEP1 >= 290) and (cCEP1 <= 299) then Result := True else
     if (cEstado = 'MG') and (cCEP1 >= 300) and (cCEP1 <= 399) then Result := True else
     if (cEstado = 'BA') and (cCEP1 >= 400) and (cCEP1 <= 489) then Result := True else
     if (cEstado = 'SE') and (cCEP1 >= 490) and (cCEP1 <= 499) then Result := True else
     if (cEstado = 'PE') and (cCEP1 >= 500) and (cCEP1 <= 569) then Result := True else
     if (cEstado = 'AL') and (cCEP1 >= 570) and (cCEP1 <= 579) then Result := True else
     if (cEstado = 'PB') and (cCEP1 >= 580) and (cCEP1 <= 589) then Result := True else
     if (cEstado = 'RN') and (cCEP1 >= 590) and (cCEP1 <= 599) then Result := True else
     if (cEstado = 'CE') and (cCEP1 >= 600) and (cCEP1 <= 639) then Result := True else
     if (cEstado = 'PI') and (cCEP1 >= 640) and (cCEP1 <= 649) then Result := True else
     if (cEstado = 'MA') and (cCEP1 >= 650) and (cCEP1 <= 659) then Result := True else
     if (cEstado = 'PA') and (cCEP1 >= 660) and (cCEP1 <= 688) then Result := True else
     if (cEstado = 'AM') and ((cCEP1 >= 690) and (cCEP1 <= 692) or (cCEP1 >= 694) and 
(cCEP1 <= 698)) then Result := True else
     if (cEstado = 'AP') and (cCEP1 = 689) then Result := True else
     if (cEstado = 'RR') and (cCEP1 = 693) then Result := True else
     if (cEstado = 'AC') and (cCEP1 = 699) then Result := True else
     if ((cEstado = 'DF') or (cEstado = 'GO')) and (cCEP1 >= 700)and(cCEP1 <= 769)then 
Result := True else
     if (cEstado = 'TO') and (cCEP1 >= 770) and (cCEP1 <= 779) then Result := True else
     if (cEstado = 'MT') and (cCEP1 >= 780) and (cCEP1 <= 788) then Result := True else
     if (cEstado = 'MS') and (cCEP1 >= 790) and (cCEP1 <= 799) then Result := True else
     if (cEstado = 'RO') and (cCEP1 = 789) then Result := True else
     if (cEstado = 'PR') and (cCEP1 >= 800) and (cCEP1 <= 879) then Result := True else
     if (cEstado = 'SC') and (cCEP1 >= 880) and (cCEP1 <= 899) then Result := True else
     if (cEstado = 'RS') and (cCEP1 >= 900) and (cCEP1 <= 999) then Result := True else
Result := False
   end;
 end
else
   begin
   Result := True;
   end
end;

Controle sobre a digitação

Quando alguém esta  digitando  algum valor que posteriormente será utilizado para calculo alguns cuidados são necessários, esse procedimento  ValidaKey  deve ser ligado no OnChange do TDBEdit para checar qual foi a tecla digitada.

procedure ValidaKey(Const Sender:TObject; var key: char);
begin
       if not(key in ['0'..'9','.',',',#8,#13]) then key := #0;
       if key in [',','.'] then key := DecimalSeparator;
       if key = DecimalSeparator then
                  if pos(key,TEdit(Sender).Text) <> 0 then key := #0;
end;


       if not(key in ['0'..'9','.',',',#8,#13]) then key := #0;

Se algum numero, ponto, virgula, BackSpace ou Enter for digitado então pode passar normalmente, caso contrario a tecla pressionada é ignorada.

       if key in [',','.'] then key := DecimalSeparator;

Se ponto ou virgula, assume como separador decimal.

        if key = DecimalSeparator then
          if pos(key,TEdit(Sender).Text) <> 0 then key := #0;

O separador decimal so pode ser digitado uma unica vez, na tentativa de uma segunda digitação ignora-se o símbolo.

Observem que o mais importante aqui é o conceito utilizado, o fato de se interceptar os caracteres digitados pelo usuário e poder filtrar esses caracteres para evitar uma entrada de  dados inconsistente. O exemplo de numero e símbolos não é conclusivo, uma vez que o mesmo efeito poderia ter sido obtido com a aplicação de uma mascara.