sexta-feira, 28 de janeiro de 2011

Abreviar Nomes


Algumas vezes precisamos transformar, via programação, um nome como "Fulano Beltrano Ciclano" em "Fulano B. Ciclano". Veja nesta dica uma função para abreviar nomes completos e resolver casos como este.
Observação: É importante lembrar que o código ASCII #32 representa o caracter "espaço".

function AbreviarNome(Nome: String): String;
var
  Nomes: array[1..20] of string;
  i, TotalNomes: Integer;
begin
  Nome := Trim(Nome);
  Result := Nome;
  Nome := Nome + #32;
  i := Pos(#32, Nome);
  if i > 0 then
  begin
    TotalNomes := 0;
    while i > 0 do
    begin
      Inc(TotalNomes);
      Nomes[TotalNomes] := Copy(Nome, 1, i - 1);
      Delete(Nome, 1, i);
      i := Pos(#32, Nome);
    end;

    if TotalNomes > 2 then
    begin
      for i := 2 to TotalNomes - 1 do
        if Length(Nomes[i]) > 3 then
          Nomes[i] := Nomes[i][1] + '.';

      Result := '';
      for i := 1 to TotalNomes do
        Result := Result + Trim(Nomes[i]) + #32;

      Result := Trim(Result);
    end;
  end;
end;
Para testá-la, coloque em um form dois edits e um button, fazendo no onClick do button:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit2.Text := AbreviarNome(Edit1.Text);
end;

terça-feira, 25 de janeiro de 2011

Criando componente de data para Banco de Dados


Como percebemos em muitos fóruns, várias pessoas buscam componentes de data para Banco de Dados. Nesta matéria você vai aprender a criar o seu próprio componente para acesso a datas com banco de dados
Se você só desejar pegar o componente, segue abaixo a Unit correspondente ao Componente, que é derivado de TDateTimePicker. Mas se quer aprender e mais detalhes, logo mais abaixo terá as explicações.
unit DBDateTimePicker;

interface

uses
SysUtils, Classes, Controls, ComCtrls, Forms, Dialogs, Graphics, DBCtrls,DB, stdctrls; 

type
TDBDateTimePicker = class(TDateTimePicker)
private
  { Private declarations }
  FDataLink : TFieldDataLink;
  function GetDataField:String;
  procedure SetDataField(const Value : string);
  function GetDataSource:TDataSource;
  procedure SetDataSource(const Value : TDataSource);
  procedure DataChange(Sender:TObject);
  procedure UpdateData(Sender:TObject);
  procedure Change;override;
protected
  { Protected declarations }
public
  { Public declarations }
  constructor Create(AOwner:TComponent);override;
  destructor Destroy;override;
  property Field: TField read GetField;
published
  { Published declarations }
  property DataSource : TDataSource read GetDataSource Write SetDataSource;
  property DataField : String read GetDataField write SetDataField;
end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents("Fernando", [TDBDateTimePicker]);
end;

{ TDBDateTimePicker }

procedure TDBDateTimePicker.Change;
begin
  FDataLink.Modified;
  inherited Change;
  Try
    FDataLink.Edit;
    FDataLink.UpdateRecord;
  Except
  End;
end;

constructor TDBDateTimePicker.Create(AOwner: TComponent);
begin
  inherited;
  FDataLink := TFieldDataLink.Create;
  FDataLink.OnDataChange := DataChange;
  FDataLink.OnUpdateData := UpdateData;
  FDataLink.Control := self;
  Width := 100;
end;

procedure TDBDateTimePicker.DataChange(Sender: TObject);
begin
  Date := FDataLink.Field.AsDateTime;
end;

destructor TDBDateTimePicker.Destroy;
begin
  FDataLink.Free;
  inherited;
end;

function TDBDateTimePicker.GetDataField: String;
begin
  Result := FDataLink.FieldName;
end;

function TDBDateTimePicker.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;

procedure TDBDateTimePicker.SetDataField(const Value: string);
begin
  FDataLink.FieldName := Value;
end;

procedure TDBDateTimePicker.SetDataSource(const Value: TDataSource);
begin
  FDataLink.DataSource := Value;
end;

procedure TDBDateTimePicker.UpdateData(Sender: TObject);
begin
  FDataLink.Field.AsDateTime := FDataLink.Field.AsDateTime;
end;

end.

Detalhes:
Quem já conhece o desenvolvimento de componentes para Banco de Dados, pode achar que basta criar as propriedades comuns em banco de dados:

DataSource - Que identifica o objeto da classe TDataSource ao qual o componente está vinculado.
DataField - O nome do campo da tabela cujo valor do registro corrente será exibido e/ou editado pelo componente. 
Porém, como a Borland é maravilhosa, ela desenvolveu uma nova classe chamada TFieldDataLink, será desta que criaremos um componente para acessos a Dados. Esta classe possui duas propriedades principais:

DataSource - Que identificará o componente da classe TDataSource ao qual o nosso componente será vinculado.
FieldName - Que indentificará o nome do campo ao qual o nosso componente será vinculado.

Agora, ao invés de criarmos campos internos, basta usar as propriedades da classe TFieldDataLink (que precisa ser criado e destruído por nosso Componente).

Antes de começarmos, precisamos declarar certas Units:

dbctrls - onde se encotra a classe TFieldDataLink.
db - onde se encontra a classe TDataSource.
uses SysUtils, Classes, Controls, ComCtrls, Forms, Dialogs, Graphics, DBCtrls,DB, stdctrls;
Vamos lá.. 

Precisaremos então criar um objeto interno do tipo TFieldDataLink.

Na sessão private:
FDataLink : TFieldDataLink;
Agora precisamos definir o método de leitura e de escrita dos campos DataSource e DataField. Normalmente, Get Leitura, Set escrita.
-----DataSource
function GetDataSource : TDataSource;
procedure SetDataSource(Value : TDataSource);
-----DataField
function GetDataField : string;
procedure SetDataField(Value : string);
Vamos declarar as propriedades que aparecerão no Object Inspector. Na área Published declarar:
property DataSource : TDataSource read GetDataSource write SetDataSource;
property DataField : string read GetDataField write SetDataField;

Iremos agora implementar esses métodos pressionando CTRL+SHIFT+C
function TDBDateTimePicker.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;

procedure TDBDateTimePicker.SetDataSource(const Value: TDataSource);
begin
  FDataLink.DataSource := Value;
end;

function TDBDateTimePicker.GetDataField: String;
begin
  Result := FDataLink.FieldName;
end;

procedure TDBDateTimePicker.SetDataField(const Value: string);
begin
  FDataLink.FieldName := Value;
end;

Vamos definir o método de "Construção" e de "Destruição". Faremos assim, dentro de public:
destructor Destroy;override;
constructor Create(Aowner : TComponent);override;

Pressionando Novamente CTRL+SHIFT+C

Implementaremos esses métodos assim:
constructor TDBDateTimePicker.Create(AOwner: TComponent);
begin
  inherited;
  FDataLink := TFieldDataLink.Create;
end;

destructor TDBDateTimePicker.Destroy;
begin
  FDataLink.Free;
  inherited;
end;

Aparentemente nosso componente está funcionando. Mas somente se você desejar EXIBIR os dados. Se alterado o seu conteúdo, ele não sofrerá modificações, pois não há nenhum método para identificar esta modificação. Então vamos lá.

Na classe TFieldDataLink tem o evento OnDataChange, que é executado sempre que o valor armazenado for modificado.

Na área private:
procedure DataChange(Sender : TObject);
Implementamos com CTRL+SHIFT+C e completaremos da seguinte forma:
procedure TDBDateTimePicker.DataChange(Sender: TObject);
begin
  Date := FDataLink.Field.AsDateTime;
end;

Precisamor associá-lo ao evento OnDataChange de FDataLink, faremo isso no Create da seguinte forma:
FDataLink.OnDataChange := DataChange
Agora precisaremos criar um componente para refletir alterações feitas pelo próprio componente. O procedimento responsável por isso é o OnUpdateData do FDataLink, novamente na área Private:
procedure UpdateData(Sender : TObject).
Implementamos com CTRL+SHIFT+C e completaremos da seguinte forma:
procedure TDBDateTimePicker.UpdateData(Sender: TObject);
begin
  FDataLink.Field.AsDateTime := FDataLink.Field.AsDateTime;
end;

Precisamos associá-lo ao evento OnUpdateData de FDataLink. Faremos isso no Create da seguinte forma:
FDataLink.OnUpdateData := UpdateData;
Precisaremos ainda, criar o método change da classe-base de maneira que o valor armazenado no campo seja alterado sempre que o usuário alterar o texto exibido pelo componente

Na área private:
procedure Change;override;

Implementamos...

procedure TDBDateTimePicker.Change;
begin
  FDataLink.Modified;
  inherited Change;
  Try
    FDataLink.Edit;
    FDataLink.UpdateRecord;
  Except
  End;
end;

Stored Procedures, Triggers e Views


Conheça neste pequeno artigo os principais objetos de um SGBD, tendo em vista que o uso correto destes melhora a velocidade do banco, facilitando até a garantia da integridade entre as tabelas, sem que o programa precise se preocupar com isto

Stored Procedures (SPs) – Procedimentos Armazenados: são equivalentes às subrotinas da linguagem normal. Nelas podem ser inclusas estruturas de repetição e de decisão, executa cálculos, inserções e updates dentro do banco, além de poder ou não retornar datasets (conjunto de dados). Pode ser usado para confecção de relatórios que possuem vários parâmetros ou em rotinas que efetuam vários cálculos. A principal vantagem está na diminuição do tráfego pela rede, quando um comando SQL é mandado pela rede, será mandada toda a consulta e, no caso das SPs seria enviado pela rede apenas os parâmetros, além disso o motor do FB analisa se a expressão está OK, isto ocorre a cada requisição do comando SQL, já no uso de SPs sua otimização é feita no momento da criação, não precisando passar por um interpretador a cada requisição ao banco, ganhando muito em performance com relação às querys convencionais.

Triggers – Gatilhos: diferentemente das SPs as triggers não retornam datasets, porém tem uma característica muito importante: elas são acionadas automaticamente pela alteração da tabela à qual está vinculada. Qual a vantagem disto? As triggers podem ser utilizadas para garantir a integridade dos dados. Imagine que temos a tabela funcionários e a tabela histórico de salário, ao atualizar o salário de um funcionário temos que inserir os dados anteriores na tabela de histórico de salários. Com o uso de triggers isto acontece automaticamente sem que a aplicação precise se preocupar com isto.

Views – Visões: São úteis qando há realização de várias tabelas na mesma consulta. Uma view não é nada mais do que um “select” armazenado no banco, só que tem a vantagem de já estar otimizada, tendo as mesmas características das SPs neste quesito. No uso de views temos consultas com menor tempo de resposta, fazendo com que o Sistema fique mais leve.

NFe - Consumo Indevido do Ambiente de Autorização


O ano está acabando, mas o SEFAZ ainda está nos presentiando com novidades. O novo manual "Aplicação Cliente" Consumo Indevido do Ambiente de Autorização, traz algumas informações importantes que deverão ser levadas em consideração.
A obtenção da autorização de uso da NF-e é um processo que envolve diversos recursos de infraestrutura, hardware e software, tanto por parte da SEFAZ Autorizadora, quanto por parte das empresas. O mau funcionamento ou a indisponibilidade destes recursos pode prejudicar o processo de autorização da NF-e, com reflexos no processo de faturamento da empresa emissora da Nota Fiscal Eletrônica.
A alta disponibilidade é uma das premissas básicas do sistema da NF-e e o Sistema de Autorização de NF-e da SEFAZ foi construído para funcionar em regime de 24x7, no entanto existem diversos componentes do sistema e da infraestrutura que podem apresentar falhas e comprometer a disponibilidade dos serviços.
Por parte das SEFAZ, existem poucos Ambientes de Autorização de NF-e, cada um deles executando uma aplicação própria que de alguma forma tem sido depurada e aperfeiçoada pelo uso intensivo destes ambientes pelas empresas.
Por outro lado, existem milhares de "aplicações cliente" desenvolvidas pelas empresas, cujo comportamento indevido pode gerar um consumo excessivo de recursos do ambiente de autorização das SEFAZ, podendo inclusive vir a prejudicar o uso compartilhado deste ambiente.
Como exemplo maior do mau uso do ambiente de autorização, ressalta-se a falta de controle de algumas aplicações das empresas que entram em "loop", consumindo recursos de forma indevida, sobrecarregando principalmente o canal de comunicação com a Internet. Até agora, o Ambiente de Autorização da SEFAZ tem sido reforçado, com a ampliação de recursos de infraestrutura, mas esta prática não poderá ser mantida indefinidamente, principalmente quando é motivada para suportar o uso indevido do ambiente pela aplicação de algumas empresas.
Leia o manual no link: http://www.nfe.fazenda.gov.br/PORTAL/docs/Consumo_Indevido_Aplicacao_Cliente_v1.00.pdf

segunda-feira, 24 de janeiro de 2011

Texto Para Iniciantes

Introdução à Programação

Caso você já tenha uma base de programação pode pular esta parte, ou pode lê-la caso se sinta inseguro quanto ao seu conhecimento.
Bem, em primeiro lugar, o que este guia exige é uma noção de comandos básicos que todo (ou quase todo) tipo de linguagem exige.
Note que os exemplos serão baseados na programação Delphi, e não qualquer linguagem.

Variáveis

Variável é um nome conhecido por qualquer programador (ou pelo menos deveria ser), este nome significa um endereço na memória onde um certo valor fica guardado. Vejamos um exemplo: se você declara a variável i:

var i:integer; 

 ("var" é nome usado para declarar uma variável em Delphi, "integer" é o tipo de informação que ela deverá armazenar) daí você pode estabelecer um valor para i:

i := 12;  

este valor vai ficar "guardado na memória" para você poder usa-lo mais tarde, por exemplo, para fazer uma conta:

i := 4 * i;

Agora i vale 4 vezes 12 (48).

Loops

Se você já fez algum programa em uma linguagem qualquer deve se lembrar dos famosos FOR e WHILE (loop), caso contrário, vamos a uma introdução a estes comandos:
Em uma linguagem de programação, loop é um comando que faz com que um certo código seja executado enquanto uma certa condição for atendida, um exemplo o ajudará a entender melhor:

var i:integer; //(declara a variável i)
for i := 1 to 30 do
ShowMessage ('O VALOR DE "I" É: ' + IntToStr(I));

 
Este comando fará com que "PARA" (FOR) I = 1, ou seja, o valor inicial de i é 1, "ATÉ" (TO) 30 (inclusive) exiba uma mensagem (SHOWMESSAGE, é o comando de exibir mensagens) escrevendo o valor de i. Portanto serão exibidas 30 mensagens. O valor de i e incrementado automaticamente ao fim do loop. Veja:
for i := 1 to 30 do (i=1) => ShowMessage(...) => (retorna a origem) for i := 1 to 30 do (i=2) => ShowMessage (...) =>
(...)
for i := 1 to 30 do (i=30) => ShowMessage (...) => Fim do loop.

O comando While é semelhante, veja um exemplo de seu uso:

var k:integer; //(declara a variável k).
k := 0 //(define o valor de k como "0".
while k < 10 do
ShowMessage ('k é menor que 10');

 "QUANDO" (WHILE) k é menor que 10 exibe a mensagem "k é menor que 10" (a mensagem em Delphi realmente deve estar entre apóstrofos (aspas simples) e não aspas duplas (como em muitas linguagens)). No entanto este loop não deve ser usado desta forma, pois, ao contrário de "for", while NÃO incrementa automaticamente o número, portanto o loop nunca acabará, pois k é 0 e sempre será 0 (foi definido esse valor em "k := 0"). Portanto seria melhor fazer:

var k:integer; //(declara a variável k).
begin
k := 0 //(define o valor de k como "0". 
while k < 10 do
begin
ShowMessage ('k é menor que 10);
k := k + 1;
end;

 
Agora o valor de k será incrementado de 1 toda a vez que o loop "retornar", portanto depois de 10 mensagens o loop acabará (k vai de 0 até 9). Não se importe com o "begin" e "end" eles serão discutidos mais adiante.

Introdução a linguagem e migrando para Delphi

Variáveis

 Talvez programadores oriundos de outras linguagens tenham certa dificuldade para se acostumar com os padrões delphi. A declaração de variáveis e seu uso, provavelmente parecerá chato para programadores Visual Basic. Vamos a algumas regras práticas:

  1. Não é possível declarar variáveis em qualquer lugar, apenas no início do procedimento.

  2. Os tipos de dados Delphi não são compatíveis (como no VB), por exemplo, você não pode multiplicar a string "X" pela string "Y", mas sim transformá-las em números inteiros e depois multiplica-los, veja: Z := StrToInt(X) * StrToInt(Y);.

Nem mesmo números inteiros são compatíveis com reais.

Sinal de igual

 Não use o sinal de igual para atribuir valores (como em grande parte das linguagens) mas sim ":=" como na linha abaixo:

 i := 0;

 O sinal de igual é usado apenas para comparação como em comandos "If", veja:

 If i = 0 then
ShowMessage('O valor de i é 0');
else
ShowMessage('O valor de i não é 0';

 Note que não se usa o EndIf como no caso do Visual Basic, por exemplo... Mas pode-se usar o begin e end para determinar o início e o fim como em:

if i = 0 then
begin
ShowMessage('O valor de i é 0');
ShowMessage('Foi usado Begin e End porque foram utilizadas duas linhas');
end
else
ShowMessage('O valor de i não é 0';

 Quando se usa uma única linha não há necessidade de usar Begin e End.

IMPORTANTE

Você deve ter notado que em Delphi não se usam aspas duplas ("), mas aspas simples ('), ou apóstrofo, como preferir. Também é usado ponto e vírgula (;) no final de cada comando (mas não nos que terminam com comandos como If. Mas lembre-se que NÃO se deve usar ponto e vírgula antes de else.

 Outro motivo pelo qual no final de cada declaração usa-se o ponto e vírgula é para mostrar que acabou. Por esta razão pode-se continuar o comando na linha de baixo (menos partir strings ao meio), veja:

 Estaria CORRETO:

MessageDlg ('Esta é uma mensagem!',
mtinformation, [mbok], 0);

 Mas estaria INCORRETO:

MessageDlg ('Esta é uma
mensagem!', mtinformation, [mbok], 0);

 Se for necessário use:

MessageDlg ('Esta é uma' +
+ ' mensagem!', mtinformation, [mbok], 0);

Isso é correto.

Comentários

 Os comentários podem estar entre chaves:

{Este é um comentário que pode estar
em mais de uma linha}

 entre sinais de parênteses e asterisco, como o mostrado abaixo:

(* este é um comentário
que pode estar em mais de uma linha
até que seja colocado o sinal de asterisco e fecha parênteses *)

 Ou pode estar depois de duas barras, para comentários rápidos de apenas uma linha, veja:

// Este comentário não pode passar de uma linha...

Operadores

 Eles são:

* - Multiplicação aritmética.
/ - Divisão de números que obtém um número real (exemplo: 5/2 = 2.5).
div - Divisão de números que obtém um número inteiro (exemplo: 5/2 = 2).
+ - Adição.
- - Subtração.
= - Igual.
<> - Diferente.
> - Maior.
>= - Maior ou igual.
< - Menor.
<= - Menor ou igual.

 Exemplo:

Form1.Canvas.TextOut (1, 1, IntToStr((2 * 5) div 3));

 Form1: Nome do formulário;
Canvas: Propriedade (não apenas do formulário) relacionada com desenho. Neste caso ela é usada para escrever no formulário (com o TextOut), algo como o print do Visual Basic. Sua cor de fundo padrão é branca, mas é possível mudá-la acessando a propriedade brush. O primeiro parâmetro é o left, o segundo é o top e o terceiro é o texto a ser escrito.
IntToStr: Transforma um inteiro em caracteres (como já foi dito anteriormente, o Delphi não possui compatibilidade entre Integers e Strings, a não ser que sejam usadas Variants).

 Iniciantes:

Para quem ainda não está integrado com programação aqui vão alguns conceitos:
Parâmetros: São "valores extras", colocados entre parênteses para fornecer outras informações ao método (function ou procedure). No exemplo mostrado, a função precisa dos parâmetros inteiros (que foram determinado como 1 neste caso) para saber a que distância da margem esquerda e o topo, respectivamente;
Left: Valor inteiro que diz a distância até o canto esquerdo de um objeto;
Top: Valor inteiro que diz a distância até o topo de um objeto;


Dicas...

Usando funções externas (de DLLs)...

Usar funções externas, de uma ou mais DLLs é muito simples, basta declara-las da seguinte forma:

function NomeDaFuncao(Parâmetros: Tipo): TipoRetorno; stdcall; external 'NomeDaDLL';

Você pode ver o nome de uma função da DLL na Visualização Rápida do Windows (se esta estiver sido instalada), para isso encontre o arquivo DLL, clique nele com o botão direito do mouse e escolha visualização rápida.

Manipulando "Application"...

A classe TApplication proporciona muitas manipulações úteis do aplicativo como um todo. Por exemplo, caso você queira que quando um aplicativo for minimizado apareça a hora atual no título da barra de tarefas, e quando ele for restaurado não apareça, use o seguinte código no evento OnLoad do formulário, por exemplo:

Application.OnMinimize := ShowDate;
Application.OnRestore := NShowDate;
 
procedure ShowDate;
begin
TForm1.Timer1Timer(Sender);
Timer1.Enabled := True;
end;
 
procedure NShowDate;
begin
Timer1.Enabled := False;
Application.Title := 'Título do Aplicativo';
end;

Este exemplo considera que o aplicativo possua um relógio que atualiza de tempos em tempos (a cada 250 milésimos de segundo por exemplo). Este é desabilitado quando o formulário é restaurado.

Undo na caixa de texto (Memo)...

Use o seguinte código para Desfazer a última ação em uma caixa de Texto (Memo):

Memo1.Perform(EM_UNDO, 0, 0);

o valor retornado de Memo1.Perform(EM_CANUNDO, 0, 0) será diferente de zero se o comando de Desfazer estiver disponível.

Pegando a posição do cursor...

Use o seguinte código para ver a posição do cursor na tela, ele é muito útil quando o evento usado não possui como parâmetros "X" e "Y":

procedure GetPosition (var X; var Y);
var CPos: TPoint;
begin
GetCursorPos(CPos);
X := CPos.X;
Y := CPos.Y;
end;

Guia Inicial Rápido Para Otimização de Índices


Veja neste artigo a tradução de um post feito por Paul Beach em seu blog, que foi mencionado pelo site firebirdnews.org, mas cujos conceitos se aplicam a praticamente todos os SGBDs.
Abaixo, é apresentado um rápido guia inicial com cinco (na verdade seis) pontos para a otimização de índices, cortesia de Pavel Cisar.
1. Sempre defina TODAS as regras (constraints) de integridade: chaves primárias, estrangeiras e índices únicos. Isto será automaticamente utilizado na otimização de junções (joins).
2. Defina índices separados para CADA COLUNA que será utilizada em regras adicionais de suas consultas (ex: filtros em cláusulas WHERE), que não fazem parte do primeiro ponto (pk's, fk's e uniques).
3. Atualize as estatísticas de seus índices regularmente, visto que dados são inseridos / modificados / excluídos em sua base de dados. Uma boa regra geral é atualizar as estatísticas dentro de suas rotinas de manutenção (quando fizer backup, sweep, etc.), e/ou sempre que você inserir / alterar um quarto de todos os registros, uma vez que a tabela possua mais de 10.000 registros.
4. Uma vez tendo dados representativos do mundo real em seu banco de dados, você pode avaliar a usabilidade dos índices para eliminar aqueles que não ajudam suas instruções SQL (um índice insignificante apenas tornará lento seus inserts e updates!) e adicionar novos índices compostos ou de expressões, que aumentem a performance de instruções específicas.
5. Índices inúteis são normalmente aqueles com baixa seletividade (poucos valores distintos). Execute algumas consultas com filtros condicionais em colunas com baixa cardinalidade e verifique quando o otimizador usa o índice ou não. Se o índice de baixa seletividade é sempre ou frequentemente usado em outras condições de filtro, você pode melhorar a sua seletividade e consequentemente a sua usabilidade, criando um índice composto com as colunas que são usadas nestes outros filtros, ao invés de usar índices independentes em cada coluna.
6. Se você sempre / frequentemente usa um grupo de colunas para filtros, um índice composto nestas colunas pode melhorar a performance do comando, mas faça isso apenas se não estiver satisfeito com a performance que os índices em colunas individuais provêem.