sábado, 12 de fevereiro de 2011

Gerando imagem para validação de números.


Gerando imagem para validação de números
Hoje em dia está sendo muito usado a geração de imagens para confirmação de alguma ação. Um exemplo disse é o email da uol, onde você tem uma opção de solicitar a confirmação do envio.
Bom, segue uma função que faz isso:

Primeiro adicione no seu form os componentes TButton, TImage e TEdit.

unit Unit1;
  interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type
  TForm1 = class(TForm)
  Image1: TImage;
  Button1: TButton;
  Edit1: TEdit;
  procedure Button1Click(Sender: TObject);
  procedure FormShow(Sender: TObject);
private
  { Private declarations }
public
 { Public declarations }
  function GeraImagem(Img: TImage): string;
end;
 
var
  Form1: TForm1;
  validapost : string;
implementation
{$R *.dfm}
{ TForm1 }
function TForm1.GeraImagem(Img: TImage): string;
  const
    f: array [0..4] of string =  ('Courier New', 'Impact', 'Times New Roman', 'Verdana', 'Arial');
    s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    C : ARRAY [0..14] OF tcOLOR = (clAqua, clBlack, clBlue, clFuchsia, clGray, clGreen, clLime, clMaroon, clNavy, clOlive, clPurple, clRed, clSilver, clTeal, clYellow);
 
var
  i, x, y : integer;
  r : string;
begin
  randomize;
  Img.Width := 160;
  Img.Height := 60;
  for i := 0 to 3 do
  r := r + s[Random(length(s)-1)+1];
  with Img.Picture.Bitmap do
  begin
    width := Img.Width;
    Height := Img.Height;
    Canvas.Brush.Color := $00EFEFEF;
    Canvas.FillRect(Img.ClientRect);
    for i := 0 to 3 do
    begin
      Canvas.Font.Size := random(20) + 20;
      Canvas.Font.Name := f[High(f)];
      Canvas.Font.Color := c[random(High(c))];
      Canvas.TextOut(i*40,0,r[i+1]);
    end;
    for i := 0 to 2 do
    begin
      Canvas.Pen.Color := c[random(High(c))];
      Canvas.Pen.Width := 2;
      canvas.MoveTo(random(Width),0);
      Canvas.LineTo(random(Width),Height);
      Canvas.Pen.Width := 1;
      x := random(Width-10);
      y := random(Height-10);
      Canvas.Rectangle(x,y,x+10,y+10);
    end;
  end;
  Result := r;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  if (Edit1.Text = validapost) then
    Application.MessageBox('Parabéns, muito bem','Sucesso',
  MB_OK + MB_ICONINFORMATION);
  FormShow(self);
end;
 
procedure TForm1.FormShow(Sender: TObject);
begin
  validapost := GeraImagem(Image1);
end;
 
end.

terça-feira, 8 de fevereiro de 2011

Chave Estrangeira (Foreign Key) com DBExpress e ClientDataSet


Com o uso de DBExpress não existe mais a hipótese de campos Lookup para se trazer um determinado campo de uma chave estrangeira, como fazíamos antigamente. Isso porque para criarmos um campo Lookup, precisaríamos deixar a tabela aberta por completo na memória para que os outros datasets pudessem buscar a informação nela através do campo Lookup, e isto sai completamente dos conceitos do ClientDataSet...
    Para resolver este problema, usa-se JOINs em instruções SQL, que "performaticamente" falando, são mais rápidos, porém, um pouco mais trabalhoso, no sentido em que, ao digitarmos os dados para um ClientDataSet, estes ficam na memória e o Join não é executado no BD, até que o dado seja gravado. Dessa maneira, ao informarmos o ID da chave estrangeira não veríamos o campo que desejamos até que este registro seja gravado. Porém, pode-se “forçar” a busca deste campo através de uma função que você pode mais abaixo.

    Um cenário interessante para podermos exemplificar é um cadastro de venda, onde na tabela de vendas existe uma chave estrangeira da tabela de clientes para se gravar o ID do cliente que esta efetuando aquela compra. Se estivermos fazendo uma consulta, automaticamente o JOIN faz o seu papel e retorna o NOME deste cliente, se a SQL for algo do tipo:
SELECT
  V.CODVENDA,
  V.DATA,
  V.CODCLIENTE,
  C.NOME AS NOME_CLIENTE
FROM
  VENDAS V
     INNER JOIN CLIENTES C ON V.CODCLIENTE = C.CODCLIENTE

    Porém, ao inserir um novo registro o JOIN não é executado como já comentamos, pois os dados não estão no banco ainda, somente em Cache. Resolvendo isso, a função:

function GetFieldByID(var SQLConn: TSQLConnection;
                                   Table, ResultField, IDField: String;
                                   ID: integer): string;
var qry: TSQLQuery;
      SQL: String;
begin
  Result := '';
  SQL:='SELECT ' + ResultField + ' FROM ' + Table + ' WHERE '+ 
  IDField + '=' + IntToStr(ID);
  qry := nil;
  try
    SQLConn.Execute(SQL, nil, @qry);
    if Assigned(qry) then
      Result := qry.FieldByName(ResultField).AsString;
  finally
    qry.Free;
  end;
end;

Entendendo a Função

    Passamos para a função qual o SQLConnection (SQLConn) responsável pela execução da qry e também informamos em qual Tabela (Table) ela deverá buscar, através de qual campo (IDField) e qual ela irá trazer (ResultField), além é claro do ID que estamos procurando.
    A função monta então a SQL e a executa no SQLConnection especificado. Este por sua vez, retorna um ResultSet que fica armazenado na variável qry (que é um TSQLQuery). Se o SQLConnection não retornar o ResultSet é porque a SQL não retornou nada caso contrario (if Assigned(qry)), retorna para o Result da função o valor do campo pesquisado com a SQL montada.

    Para usá-la, no evento OnValidate do campo CODCLIENTE basta fazer:

cdsVendas.FieldByName('NOME_CLIENTE').AsString := GetFieldByID(SQLConnection1,'CLIENTES','NOME','CODCLIENTE',Sender.AsInteger);

    Você também pode tratar o campo verificando se a função retornou algum valor, e se não, gerar uma exceção avisando que o código não foi encontrado, por exemplo:

Var str: string;
begin
  str:=GetFieldByID(SQLConnection1,'CLIENTES','NOME','CODCLIENTE',Sender.AsInteger);
  if str<>'' then
    cdsProdutor.FieldByName('RAZAOS').AsString := str
  else
  begin
    MessageDlg('Código Não Encontrado!', mtWarning, [mbOK], 0);
    Abort;
  end;
end;

    A vantagem de se usar esta função, é que muda-se pouco de seu uso para outros campos, por exemplo, se quiséssemos saber o nome do vendedor supondo que este também esteja previsto na SQL através de um JOIN, seria:

cdsVendas.FieldByName('NOME_VENDEDOR').AsString :=  GetFieldByID(SQLConnection1,'VENDEDORES','NOME','CODVENDEDOR',Sender.AsInteger);

domingo, 6 de fevereiro de 2011

Chega de Showmessage!!!

Se você pensa..."Que Mensagem para validação de campos é muito chato!". Vai encontrar uma maneira bem simples de fugir deste terror.
O que veremos neste artigo é ao invés de mandarmos uma mensagem para o usuário, que é muito chato, você poder fazer o usuário se interagir com o sistema, veja...
Para este Artigo vamos precisar criamor uma Procedure.
Dei o Nome desta Procedure de TrocaCor com a sintaxe abaixo

Procedure TrocaCor(Campo : TWinControl ; CorTrocada , CorMeio, CorFinal : TColor ; Tempo : Cardinal );

O intuito desta rotina é o Seguinte:

- no lugar de mandarmos uma mensagem, faremos com que o campo "pisque", e que receba o foco depois deste "pisca-pisca"

o Parâmetro Campo, é do Tipo WinControl , pois poderá ser um TEdit, TComboBox , TListBox e Etc...(que recebam foco).

Os Parâmetro de Cores:
-CorTrocada
-CorMeio
-CorFinal

São do Tipo TColor, pois são elas as responsáveis de fornecedor o efeito de "piscar".

E a última, Tempo, serve para executar em qual período de Tempo;

vamos Lá Entao:

Implemente esta procedure com CTRL + SHIFT + C, e vamos aos códigos:

if (Campo is TEdit) Then
Begin
  (Campo as TEdit ).Color := CorTrocada;
  (Campo as TEdit).Update;
  Sleep(Tempo);
  (Campo as TEdit).Color := CorMeio;
  (Campo as TEdit).Update;
  Sleep(Tempo);
  (Campo as TEdit).Color := CorTrocada;
  (Campo as TEdit).Update;
  Sleep(Tempo);
  (Campo as TEdit).Color := CorFinal;
  (Campo as TEdit).SetFocus;
End //TEdit
else if (Campo is TComboBox) Then
Begin
  (Campo as TComboBox ).Color := CorTrocada;
  (Campo as TComboBox).Update;
  Sleep(Tempo);
  (Campo as TComboBox).Color := CorMeio;
  (Campo as TComboBox).Update;
  Sleep(Tempo);
  (Campo as TComboBox).Color := CorTrocada;
  (Campo as TComboBox).Update;
  Sleep(Tempo);
  (Campo as TComboBox).Color := CorFinal;
  (Campo as TComboBox).SetFocus;
  End;//TComboBox
End;

Bom, no caso acima eu imaginei que os campos fossem somente de dois tipos, TEdit e TComboBox, mas você poderá ir além disso, ou mais além ainda. Criar uma variável onde armazene a classe e economizar nos códigos...;)

Vamos usá-la Agora:
Coloque um botão no Formulário, um Edit e um ComboBox

E no envento OnClick do Botão Digite:
if Edit1.Text = 'Edit1' Then
Begin
  TrocaCor(Edit1 , clRed, clBlue, clBlack , 50);
  Exit;
End;

Entendendo, o código acima testará se o conteúdo do Edit1 for = Edit1
se Sim ele Executa nossa procedure e sai da Rotina. num intervalo de 50 milisegundos

Lembrando que quanto menor o número mais rápido será a piscagem....

Questões de segurança em banco de dados


Uma das principais preocupações nos dias de hoje é com a segurança das informações que estão armazenadas nos bancos de dados dos sistemas dos nossos clientes.
Para tanto, os desenvolvedores gastam muito tempo com o desenvolvimento de mecanismos que protejam estas informações, como senhas de acesso, níveis de segurança nos programas e políticas de usuários nos bancos de dados.

O que muitos analistas ou desenvolvedores não sabem ou não levam em consideração, é a segurança, não do sistema, não do banco de dados como um servidor, mas dos ARQUIVOS que compões este banco de dados.

Em muitas vezes, enquanto enumerava os benefícios que meu sistema traria a empresa, caso ele substituísse o sistema em uso, eu mostrava esta fragilidade, disfarçada em fortes esquemas de proteção via software.

No início, eram as tabelas PARADOX. Elas, aparentemente, podiam proteger os dados utilizando uma senha "embutida" diretamente nas tabelas. O sistema, contendo entrincados meios de autenticar os usuários, "abriam" estas tabelas com a senha pré-definida.

A principal falha deste método reside no fato de que a senha está em algum ponto no executável, e com um editor de arquivos que mostre hexadecimal, poderá ser encontrada.

Os programadores, motivados pela perspicácia dos invasores, resolveram codificar a senha, mas a necessidade de se obter informações sempre é mais forte, e os invasores começaram a ver que:

"A corrente parte sempre em seu elo mais fraco"

Como os programas estavam cada vez mais protegidos, as atenções se  voltaram para os bancos de dados. Afinal, o objetivo é roubar a informação e não invadir o programa.

Recuperar dados de um sistema não é a coisa mais difícil do mundo quando o programador se apoia somente na segurança do sistema operacional e do servidor de banco de dados. No caso do PARADOX, eu lembro quando recebi um desafio de pegar os dados de uma pessoa em um sistema de cadastro que possuía vários métodos de segurança.
O sistema realmente era bem montado, com senha e políticas de segurança, e o banco continha senha.
Um pouco de tempo na internet e eu consegui acessar todos os dados, com um programa de quebra senhas de tabelas PARADOX, o que mostrou que este tipo de banco de dados não é muito seguro se não for bem estruturado.

Para efeito de didática, eu disponibilizo o programinha em meu site.
Clique aqui para baixar...

Por favor, não o use em bancos de dados de terceiros.

Na empresa em que trabalhei, os programadores (e analistas) tinham o péssimo hábito de trabalhar com o Interbase da pior forma possível:

Eles colocavam uma máquina para ser o servidor do Interbase, até aí tudo bem.
Depois, acreditem, compartilhavam a pasta onde estava o banco de dados GDB usando o compartilhamento de pastas do Windows. Em seguida, as estações que rodavam o programa, acessavam o banco de dados através do mapeamento de pastas da Microsoft, criando um drive para a pasta compartilhada do servidor e acessando o GDB usando o protocolo local.

Eu considero isto a maior heresia de todos os tempos em se tratando de Interbase...
Me perdoem os programadores que lerem este artigo e adotam esta doutrina.

Não fossem todos os problemas com o banco de dados que esta prática causa, ela afeta diretamente a segurança do banco, visto que o Interbase protege os dados a nível de servidor, ou seja, toda a segurança do interbase se baseia na pemissa de que o cliente não acessará o arquivo diretamente, mas sim através da engine do servidor,
que aplicará os métodos de segurança elaborados pelo DBA (users e roles).

Tudo isso significa que, o banco de dados, na forma de arquivo, não possui capacidade para se proteger. Caso o arquivo GDB seja copiado para outro servidor, o SYSDBA poderá acessar os dados da mesma forma (ou usuários com os mesmos nomes). Então, basta instalar um servidor Interbase com a senha padrão do SYSDBA e colocar lá o GDB que se quer invadir.

Obviamente, se o GDB está em uma pasta compartilhada, não será necessário colocar senhas nos programas nem no banco de dados, pois serão inúteis...

Uma outra prática muito usada pelos programadores, talvez por desconhecer o uso correto da conexão IB, é usar o formato \\\Pasta\Arquivo.GDB como DatabaseName do IBDataBase.
Este formato também força o cliente a conectar-se ao banco em modo LOCAL, visto que esta é uma convenção de nomes de rede para compartilhamento de pastas, o que indica que o servidor não estará sendo usado.
Neste caso, o formato correto seria: ::\Caminho\Arquivo.GDB
Sendo "DRIVE" e "caminho" fazendo referência ao sistema de arquivos do SERVIDOR.
Este método é muito eficiente e permite que o IB seja conectado até através da internet, pois dispensa o uso do NetBios.

A primeira vista, soluções simples poderão ser adotadas para proteger os dados e dar um pouco mais de trabalho para a pessoa que desejar roubar informações.

A principal premissa a se assumir é:
"Meu servidor sempre estará exposto de alguma forma"

No caso do PARADOX, eu desaconselho o uso. Nada contra o banco de dados, mas eu não acho que ele tenha sido criado para sistemas que estão em produção. Comparando com os servidores SQL atuais de baixo custo (e até grátis), ele não é a melhor solução.

No caso do Interbase, é obvio que o GDB jamais poderá cair em mãos erradas.
Para evitar, ou diminuir o risco, o ideal é, acima de tudo, utilizar o protocolo de rede para acessar o servidor.

Uma aproximação mais eficiente seria utilizar camadas de acesso ao servidor.
Este método só traria vantagens para o usuário e para o programador.
Para melhorar ainda mais a segurança, a rede em que está localizado o servidor poderia ser diferente da rede onde estão os usuários (não fisicamente, mas logicamente).

Um computador com duas placas de rede (e dois endereços IP) poderia conter a camada de acesso, que é visível aos usuários. Esta camada receberia os usuários por uma interface de rede e se comunicaria com o servidor pela outra. Esta abordagem tornaria o servidor simplesmente inacessível diretamente aos usuários, pois ele estaria em uma faixa de IP incompatível com a rede deles.

Caso o programador não tenha acesso aos métodos descritos, seria ideal utilizar a criptografia para proteger os dados. Escrevi alguns artigos na revista (foram matéria de capa das edições 14 e 20) e alguns artigos no site que descrevem como melhorar a segurança dos dados sem confiar esta tarefa ao servidor ou a máquina onde o servidor foi instalado.

Seguem os links destes artigos:

http://www.activedelphi.com.br/modules.php?op=modload&name=News&file=article&sid=236 
http://www.activedelphi.com.br/modules.php?op=modload&name=News&file=article&sid=145
http://www.activedelphi.com.br/modules.php?op=modload&name=News&file=article&sid=127
http://www.activedelphi.com.br/modules.php?op=modload&name=News&file=article&sid=123

Uma outra saída, e talvez a mais eficiente, seria manter o nível de paranóia acima do normal (indicado como seguro pelos médicos) e criptografar tudo o que ver pela frente.
Isto inclui todos os dados do banco nas tabelas e também o tráfego na rede!
Eu já ultrapassei a barreira da sanidade ao fazer isso, como um bom gestor de segurança da informação...

Caso o leitor queira chegar a estas fronteiras, faça o download do servidor de SQL que estou aprimorando (sim, é um derivado do FlashFiler da TurboPower). Este servidor de SQL tem todos os componentes para o Delphi e com a vantagem de criptografar tudo o que é armazenado nas tabelas e também criptografar o que é transmitido entre o servidor e os clientes.
A desvantagem é que será uma má notícia para o DBA quando ele descobrir que não lembra da senha do banco ao retornar de férias...

quarta-feira, 2 de fevereiro de 2011

Gaste tempo e depois ganhe mais ainda ao ler este artigo


Algumas idéias citadas abaixo ajudarão profissionais que trabalham com banco de dados a serem mais produtivos e atingir metas firmadas no acordo de nível de serviços (SLAs)
Não paramos e não podemos parar, desde o momento em que acordamos até a hora de se deitar. O mundo está cada vez mais competitivo, lutando por sobrevivência, e podemos afirmar que certamente neste momento há alguém estudando e aprendendo novas tecnologias ou tentando inventar um novo “Google”, por exemplo. Ninguém tem tempo a perder, ao ler este artigo você está gastando ele, mas espero que após a leitura lhe ajude a ganhar outros tantos que lhe dará tempo e uma vida mais calma.

A rotina de quem trabalha com dados é incessante, a infinidade de lugares, formatos e tamanhos, no qual é obrigado a controlar para manter simples conjuntos de bytes em algo compreensível é importante, faz com que se gaste muito tempo criando e executando rotinas estressantes que exigem muita habilidade e conhecimentos técnicos.


Hoje em dia os Databases Administrators(DBAs) são obrigados a gerenciar ambientes complexos que podem envolver diferentes plataformas de banco de dados, nas quais dependem de uma série de tarefas e rotinas, que precisam ser aprendidas em horas e dominadas em dias para serem aplicadas em todas as instâncias. Além disso tem a necessidade de aprender a utilizar a ferramenta de gestão de cada fabricante, que aplicam conceitos diferentes e tornam o aprendizado ainda mais demorado.


Uma forma de resolver estes problemas e também é uma dica que ofereço, é escolher uma ferramenta que permita gerenciar de maneira igual diferentes tipos de banco de dados, permitindo que o DBA domine uma única ferramenta e o seu aprendizado já seja inserido e replicado em qualquer plataforma de banco de dados, direcionando a preocupação do DBA em resolver o problema rápido, sem intervenção das peculiaridades de uma plataforma.


Ao pensarmos em modelagem, muitos a utilizam na fase de criação da estrutura do banco de dados e após a produção da aplicação abandonam o modelo, deixando obsoleto e sem manutenção. Desta maneira começam a surgir as famosas “gambiarras” para manter o sistema em funcionamento, mas de forma “sofrível”.


A modelagem não deve ser apenas utilizada na fase de criação da aplicação, ao integrar a ferramenta de modelagem no banco de dados, possibilitará ainda controle de todo o ciclo de vida e das mudanças, que forem realizadas e propagadas de maneira mais rápida, contribuindo também para uma documentação atualizada e sempre disponível de forma automática.


Outro conselho é escolher uma ferramenta de modelagem que propicie a empresa trabalhar de forma articulada e centralizada, permitindo que analistas de negócios façam o levantamento de requisitos e necessidades de seus usuários, reduzindo o mal entendimento e possibilitando que áreas especialistas em captação de informação possam trabalhar de maneira integrada e automatizada com DBAs e arquitetos de dados. Isso tudo porque ao realizar o modelo conceitual que foi gerado a partir de uma necessidade de negócio será permitido a geração do modelo do banco de dados lógico e físico já direcionado ao usuário, evitando desperdício de esforço aplicado em retrabalho.


Ao termos um modelo atualizado e em uso podemos, ir mais além e, oferecer aos desenvolvedores acesso ao dicionário de dados padronizado seguindo templates pré-fabricados para serem reutilizados pelos desenvolvedores, evitando que eles “reinventem a roda”. Ao sugerir e criar alternativas ou até mesmo novos objetos para armazenar dados, o desenvolvimento de software tem conseguido ser satisfatório seguindo implementações como Gang of Four (GoF) e UML patterns ,do mesmo modo a construção de um banco de dados não precisa ser feito de maneira diferente.


Arquitetos podem disponibilizar para os desenvolvedores estruturas e associações que necessitarão ser reutilizadas com frequência como dados cadastrais de clientes ou produtos, indicando os campos obrigatórios e tipos de dados utilizados, o ganho de tempo estará na constante reutilização e na transformação dos dados para serem movidos ou carregados via ETL.


Boas práticas de mercado são ótimas para serem lidas, nos ajudam a entender como o mercado trabalha e para onde estamos caminhando. Entretanto sabemos que muitas vezes a cultura e até mesmo a dificuldade em adotar uma ou outra técnica acabam dependendo de diversos fatores, mas ao mesmo tempo em que você ou sua empresa não adota ou não se adapta ao mundo de hoje, serão obrigados a viver o mundo de ontem, no qual a tecnologia e seus concorrentes não fazem questão de lembrar.

Função FormatDateTime


FormatDateTime é uma função que retorna uma string de acordo com o formato passado como 1º parametro, tendo como base o 2º parametro que é a data. Veja nesta dica todos os detalhes e exemplos de uso desta função
Ela está presente na unit SysUtils (Delphi 7), com a seguinte implementação:
function FormatDateTime(const Format: string; DateTime: TDateTime): string;
begin 
  DateTimeToString(Result, Format, DateTime); 
end;
Segue um exemplo de uso, para ser colocado no evento onClick de um button, por exemplo:
begin 
  ShowMessage(FormatDateTime('dd/mm/yyyy', (Now + 1))); 
end;
Se hoje for 17/12/2010, este código resultará em uma mensagem contendo:
‘18/12/2010'.
Uma das grandes facilidade que a função nos traz é durante a interação com um banco de dados. Exemplo para o mySQL:

begin 
  MyQuery.SQL.Text := Format( 
    'SELECT * FROM `log` WHERE `date` BETWEEN ''%s'' AND ''%s''', 
    [ 
      // Data inicial 
      FormatDateTime('yyyy-mm-dd', (Now)),
      // Data final 
      FormatDateTime('yyyy-mm-dd', (Now + 1)) 
    ]); 
end;
Veja agora a tabela com os formatos possíveis e seus respectivos resultados, considerando a data e hora "02/09/2008 07:04:01":
Sintaxe Finalidade Resultado
FormatDateTime('c', Now) Resulta na Data e hora com o formato ShortDateFormat + LongTimeFormat. (Se for exatamente meia-noite não irá mostrar a hora) 02/09/2008 07:04:01
FormatDateTime('d', Now) Resulta no valor número que representa o Dia do mês ( sem 0 na frente ) 2
FormatDateTime('dd', Now) Resulta no valor número que representa o Dia do mês ( com 0 na frente [00] ) 02
FormatDateTime('ddd', Now) Resulta na abraviação do nome do dia da semana ter
FormatDateTime('dddd', Now) Resulta no nome do dia da semana terça-feira
FormatDateTime('ddddd', Now) Resulta na data formatada usando ShortDateFormat 02/09/2008
FormatDateTime('dddddd', Now) Resulta na data formatada usando LongDateFormat terça-feira, 2 de setembro de 2008
FormatDateTime('m', Now) Resulta no valor número que representa o mês ( sem 0 na frente ) 9
FormatDateTime('mm', Now) Resulta no valor número que representa o mês ( com 0 na frente [00] ) 09
FormatDateTime('mmm', Now) Resulta na abreviação do nome do mês set
FormatDateTime('mmm', Now) Resulta no nome do mês setembro
FormatDateTime('y', Now) Resulta no ano em dois digitos 08
FormatDateTime('yyyy', Now) Resulta no ano em quatro digitos 2008
FormatDateTime('h', Now) Resulta nas horas ( sem 0 na frente ) 7
FormatDateTime('hh', Now) Resulta nas horas ( com 0 na frente [00] ) 07
FormatDateTime('n', Now) Resulta nos minutos ( sem 0 na frente ) 4
FormatDateTime('nn', Now) Resulta nos minutos ( com 0 na frente [00] ) 04
FormatDateTime('s', Now) Resulta nos segundos ( sem 0 na frente ) 1
FormatDateTime('ss', Now) Resulta nos segundos ( com 0 na frente [00] ) 01
FormatDateTime('z', Now) Resulta nos milisegundos ( sem 0 na frente ) 31
FormatDateTime('zzz', Now) Resulta nos milisegundos ( com 0 na frente [000] ) 031
FormatDateTime('t', Now) Resulta na hora formatada usando ShortTimeFormat 07:04
FormatDateTime('tt', Now) Resulta na hora formatada usando LongTimeFormat 07:04:01
FormatDateTime('am/pm', Now) Reajusta a hora resultada para horários de 12 horas (manha e tarde)



segunda-feira, 31 de janeiro de 2011

Programa - Simulação de Lucro Com Rendimento Mensal


Galera Delphiana! Bom, esta dica que escrevo é muito simples e se trata de um simulador de rendimento de aplicação financeira mensalmente.
O arquivo do projeto encontra-se compactado e disponivel para download aqui (7,64 KB).
Dentro dele, estão todos os códigos desenvolvidos, que não são nada complexos.

Curso de Delphi: 7.Consultas SQL