quinta-feira, 30 de dezembro de 2010

Tabela Ascii

Dec
Hex
Char
Dec
Hex
Char
Dec
Hex
Char
Dec
Hex
Char
0
0
NUL
32
20
.
64
40
@
96
60
`
1
1
SOH
33
21
!
65
41
A
97
61
a
2
2
STX
34
22
"
66
42
B
98
62
b
3
3
ETX
35
23
#
67
43
C
99
63
c
4
4
EOT
36
24
$
68
44
D
100
64
d
5
5
ENQ
37
25
%
69
45
E
101
65
e
6
6
ACK
38
26
&
70
46
F
102
66
f
7
7
BEL
39
27
'
71
47
G
103
67
g
8
8
BS
40
28
(
72
48
H
104
68
h
9
9
TAB
41
29
)
73
49
I
105
69
i
10
A
LF
42
2A
*
74
4A
J
106
6A
j
11
B
VT
43
2B
+
75
4B
K
107
6B
k
12
C
FF
44
2C
,
76
4C
L
108
6C
l
13
D
CR
45
2D
-
77
4D
M
109
6D
m
14
E
SO
46
2E
.
78
4E
N
110
6E
n
15
F
SI
47
2F
/
79
4F
O
111
6F
o
16
10
DLE
48
30
0
80
50
P
112
70
p
17
11
DC1
49
31
1
81
51
Q
113
71
q
18
12
DC2
50
32
2
82
52
R
114
72
r
19
13
DC3
51
33
3
83
53
S
115
73
s
20
14
DC4
52
34
4
84
54
T
116
74
t
21
15
NAK
53
35
5
85
55
U
117
75
u
22
16
SYN
54
36
6
86
56
V
118
76
v
23
17
ETB
55
37
7
87
57
W
119
77
w
24
18
CAN
56
38
8
88
58
X
120
78
x
25
19
EM
57
39
9
89
59
Y
121
79
y
26
1A
SUB
58
3A
:
90
5A
Z
122
7A
z
27
1B
ESC
59
3B
;
91
5B
[
123
7B
{
28
1C
FS
60
3C
<
92
5C
\
124
7C
|
29
1D
GS
61
3D
=
93
5D
]
125
7D
{
30
1E
RS
62
3E
>
94
5E
^
126
7E
~
31
1F
US
63
3F
?
95
5F
_
127
7F
DEL

quarta-feira, 29 de dezembro de 2010

Cuidados ao usar o OnExit

É comum fazermos uso do evento OnExit quando queremos validar o conteúdo de um Edit. E essa pode ser uma boa prática quando necessitamos verificar o que foi digitado apenas quando o usuário terminar de fazer a entrada de dados, como, por exemplo, um Edit que vai receber o CPF ou CNPJ.
Ao colocarmos um código qualquer no evento OnExit ele sempre será executado quando o usuário sair do Edit, o que acontece quando ele pressiona a tecla TAB, clica com o mouse em um outro Edit ou pressiona um botão OK, por exemplo.
No entanto, existem algumas situações especiais em que o evento OnExit não é gerado. Quer um exemplo? Você está no Edit e, ao invés de clicar no botão OK, você pressiona as teclas ALT + O (considerando que o botão OK tem a tecla O como atalho). É como se você tivesse pressionado o botão OK, porém, sem perder o foco que está no Edit. Só mais um exemplo: Os botões do tipo SpeedButton não recebem foco, então, mesmo que clique com o mouse sobre um SpeedButton, o foco continuará no Edit e, conseqüentemente, o evento OnExit não será gerado.

E a solução?

A solução para esse pequeno inconveniente é simples. Basta você colocar o seguinte código no evento OnClick do botão.

procedure TForm1.Button1Click(Sender: TObject);

begin

ActiveControl := nil;

...

end;

Suponhamos que você possua 2 Edits em um formulário. Supondo também que você queira dar alguma informação ao usuário da aplicação logo depois que ele sair do Edit1 você faz:

procedure TForm1.Edit1Exit(Sender: TObject);

begin

    MessageDlg('Mensagem...', mtInformation, [mbOk], 0);

end;


A princípio está tudo ok, ou melhor, parece estar tudo ok.

Se você altera o foco para o outro Edit através do pressionamento da tecla TAB, tudo bem. Mas experimente alterar o foco clicando com o mouse sobre o Edit2. Neste segundo caso a mensagem será exibida normalmente. Mas ao fechar o dialogo onde aparece a mensagem, o foco simplesmente se perde. Para setar o foco no Edit2 é necessário clicar novamente sobre ele.

Isso não teria problema nenhum até que seu usuário experimente esta situação. Nada que ele digitar será acatado.

Mas existe uma maneira fácil de resolver o problema. Basta você cancelar o foco e forçar uma reentrada no componente Edit2. Como fazer isso? Veja o código:

procedure TForm1.Edit1Exit(Sender: TObject);

begin

   MessageDlg('Mensagem...', mtInformation, [mbOk], 0);

   // cancela o foco e força novamente a entrada

   ActiveControl := nil;

   PostMessage(Edit2.Handle, WM_SETFOCUS, 0, 0);

   Edit2.SetFocus;

end;

Porém, você nunca terá certeza se o usuário clicou no Edit2. Então temos que criar uma rotina genérica que leva o foco para qualquer outro controle:

procedure TForm1.Edit1Exit(Sender: TObject);

var

   Ctrl: TWinControl;

begin

   MessageDlg('Mensagem...', mtInformation, [mbOk], 0);

   // cancela o foco e força novamente a entrada

   Ctrl := ActiveControl;

   ActiveControl := nil;

   PostMessage(TWinControl(Ctrl).Handle, WM_SETFOCUS, 0, 0);

   TWinControl(Ctrl).SetFocus;

end;

Observe que antes de cancelar o foco com ActiveControl := nil, salvamos qual é o controle que detém o foco fazendo Ctrl := ActiveControl.

Depois enviamos uma mensagem ao controle que detinha o foco, forçando-o a receber o foco novamente.

Rave - Imprimindo Gráficos (Chart)

Uma coisa muito comum nos sistemas, são os relatórios com gráficos estatísticos, os famosos Charts.

Antigamente eu usava o QuickReport e o ReportBuilder, porém relatórios com gráficos só precisei fazer no QuickReport e não tive muitas dificuldade, pois ele já tem um componente que facilita a vida.

Mas, como agora larguei o QuickReport e estou usando somente o Rave, houve então a necessidade de saber como fazer relatórios nele com gráficos.

Comecei então a fuçar no Rave e percebi que não existia nenhum componente que facilitasse a vida. Então fiz algumas pesquisas na internet para saber se não existiam componentes de terceiros, mas infelizmente não achei nenhum, porém nessas pesquisas, achei duas soluções para o caso :

1 – Salvar o conteúdo de um TCustomChart em um BMP e imprimir esse BMP no Rave
2 – Usar o método WriteChartData disponível na unit RPTChart

Esta última solução é a indicada pela Nevrona.

Fiz o teste com as duas soluções e as duas foram satisfatórias, porém gostei mais da última solução, pois como disse, é indicada pela própria Nevrona e não aparenta ser uma "gambiarra" :-) como a primeira solução.

Depois desta pesquisa, resolvi escrever este artigo para demonstrar como não é um bicho de sete cabeças fazer isso funcionar.

Então vamos lá...

Antes de iniciarmos, gostaria de explicar como a "coisa funciona", para depois partirmos para prática.

O método WriteChartData, "escreve" o conteúdo de um TCustomChart dentro de um campo do tipo Graphic. Então, a princípio, nosso gráfico será montado no TChart ou TDBChart do Delphi, e depois disso, iremos utilizar o WriteChartData para fazer com que o conteúdo do gráfico seja impresso, desenhado dentro do nosso relatório.

Agora vamos colocar em prática esta teoria...

Irei utilizar um RVCustomConnection, pois não preciso estar conectado a um DataSet para gerar o gráfico no Rave, só preciso de alguém que me disponibilize um campo para poder usá-lo na impressão, então o RVCustomConnection é o ideal para isso. Para quem não sabe para que serve o RVCustomConnection, vale a pena começar a mexer nele, pois é muito interessante.

Agora é serio, chega de teoria e vamos para prática...:-)

1 - Insira os seguintes componentes no Form:
TRVProject
TRVCustomConnection
TRVSystem
TChart

2 – Na clausula uses, insira a unit RPTChart. É esta unit que nos disponibilizará o método WriteChartData

3 - Ajuste a propriedade Engine do RaveProject, apontando para o RVSystem.

4 - Ajuste o Chart, de forma que represente algum gráfico, só para podermos visualizar o resultado final.

5 – Agora iremos ajustar dois eventos do componente RVCustomConnection:

OnGetCols:
Este evento é chamado quando o Rave necessita extrair os meta-data dos campos. É aqui que criaremos nosso campo do tipo graphic. Para isso, coloque o seguinte código neste evento:

with Connection do
begin
WriteField('CampoChart', dtGraphic, 0, '', '');
end;

 

OnGetRow:
Este evento é chamado quando o Rave necessita extrair os valores dos campos do registro atual. É aqui que iremos alimentar o valor do campo que criamos acima. Para isso, coloque o seguinte código neste evento:

WriteChartData(Connection, Chart1);

 

Chart1 é o nome do TChart que inserimos no Form.

A parte de codificação já está pronta, agora vamos para parte visual.

6 – Entre no RaveDesigner

7 – Crie uma Region e dentro desta Region crie uma banda simples.

8 – Dentro da Band1(que acabou de ser criada), insira o componente MetaFile, que está na palheta Standard do Rave.

9 – Crie uma DataView, da mesma forma que se fosse criar uma outra qualquer, a diferença é que os dados agora virão de um RVCustomConnection.

10 - Após ter criado, perceba que na TreeView o DataView1 está disponível, porém se clicar no sinal de mais do DataView1 para exibir os campos, perceberá que o campo que criamos via código(CampoChart) não está disponível, só tem um campo, que é o que vem de brinde, mas não use-o. Para que o nosso campo possa ser criado, o evento OnGetCols terá que ser chamado, e como fazer isso em tempo de projeto ?

O segredo é : O RaveDesigner tem que estar aberto juntamente com a aplicação e depois chamar o Refresh do DataView.

Então vamos lá...

11 - Execute a aplicação e volte para o RaveDesigner, mas não feche a aplicação ainda.

12 – Selecione o DataView1 lá na TreeView e clique com o botão direito do mouse sobre o DataView1. Aparecerá um item chamado Refresh, basta clicar nele e...bingo :-). Pronto, o campo que criamos via código irá aparecer na lista. Quando clicar pela primeira vez no Refresh, vai aparecer uma mensagem, é uma alerta de que um campo será excluído, isso ocorre pois quando criamos a DataView, já veio aquele campo de brinde, mas como não criamos ele no OnGetCols, então a mensagem alertará de que o mesmo será excluído.

13 – Agora selecione o componente MetaFile que foi inserindo em Band1 e altere duas propriedades dele:

DataField : CampoChart (nome do campo que criamos)
DataView : DataView1 (nome da dataview criada)

Pronto...Pode executar a aplicação e fazer o teste.

Caso queira fazer o teste no próprio preview do RaveDesigner, basta deixar a aplicação aberta, caso contrário, se a aplicação não estiver aberta e você chamar o preview do RaveDesigner, receberá de presente um errinho básico, o famoso "Acess violation..." :-)

Lembre-se, o exemplo que fizemos foi com um TChart, o mesmo poderá ser feito com um TDBChart.

Outro detalhe, utilizamos um RVCustomConnection, mas poderíamos utilizar um RVDataSetConnection sem problemas, porém neste caso, só fique atento com o seguinte:

No evento OnGetCols, antes de criar o campo, chame o método DoGetCols do Connection que vem como parâmetro neste evento. Isso deve ser feito para que primeiro sejam criadas as colunas do DataSet que está associado e depois sim poder criar as suas colunas.

E no evento OnGetRow, antes de chamar o WriteChartData, chame o método DoGetRow do Connection que vem como parâmetro neste evento. Isso deve ser feito para que primeiro seja alimentando os campos do DataSet que está associado e depois sim poder alimentar seus campos criados manualmente.

Espero que um dia possa surgir um componente para utilizarmos no Rave, pois assim ficará muito mais fácil, mas enquanto isso não acontece, temos esta solução

terça-feira, 28 de dezembro de 2010

Usuário e senha do DBA do MySql

Para Windows = ODBC (Maíusculo e sem senha) – usuário root e sem senha

Para Linux = root (Minúsculo e sem senha)

Detalhe importante: O DBA pode ser acessado somente via localhost (máquina local). Depois do primeiro acesso SQL, mude os Rights se quiser acessar de outro micro na rede (mas aconselho a não fazer isso, olha a segurança!!!!!).

 

Alguns comandos básicos para Firebird

Corrigindo problemas de instalação do Borland Data Provider For FireBird:

Em alguns casos, o Borland Data Provider For Firebird têm apresentado problemas de instalação, abaixo segue algumas dicas para tentar auxiliar na resolução dos mesmos:

Verificar se o D8 está atualizado com Update Pack#2;

Se o BDP For Firebird foi instalado 'antes' do D8 ter sido atualizado,desinstalar, atualizar o D8 e após isso instalar o BDP For Firebird novamente;

Efetuar testes diretamente via 'Data Explorer' a fim de verificar se a conexão ocorre sem problemas;

Copiar o arquivo 'FirebirdSql.Data.Bdp' para a pasta

C:\Arquivos de programas\Arquivos comuns\Borland Shared\BDS\Shared\Assemblies\2.0

5. No projeto, acesse 'Project Manager' | 'References' e adicione a referência ao 'Firebirdsql.Data.Bdp'


Listar as tabelas e views do banco de dados (Firebird):

SELECT RDB$RELATION_NAME FROM RDB$RELATIONS;

Listar as tabelas do banco de dados (Firebird):

SELECT RDB$RELATION_NAME FROM RDB$RELATIONS
WHERE RDB$VIEW_BLR IS NULL;


Listar as views do banco de dados (Firebird):

SELECT RDB$RELATION_NAME FROM RDB$RELATIONS
WHERE NOT RDB$VIEW_BLR IS NULL;


Obter o valor de um generator:

Para obter o valor de um generator use a função GEN_ID do InterBase/FireBird. 

A sintaxe é: 
GEN_ID(NomeDoGenerator, Incremento);

Exemplos

GEN_ID(Gen_Cliente_Codigo, 1);
GEN_ID(Gen_Cliente_Codigo, 0);

Reiniciar a contagem de um generator:

Para re-iniciar a contagem de um generator execute o comando abaixo.
SET GENERATOR TO X;

Excluir generator (Firebird):

DROP GENERATOR NOME_DO_GENERATOR;

Trocar o tipo de um campo (FireBird):

ALTER TABLE <Table1> ALTER <Campo> TYPE <Tipo do Campo>

Excluir código-fonte de stored procedure (Interbase/FireBird):

UPDATE RDB$PROCEDURES SET RDB$PROCEDURE_SOURCE = 'deletado';

Usando um For Select dentro da StoredProcedure no FireBird/Interbase:

create procedure SP_RETORNO(PCOD INTEGER)
returns (COD INTEGER, NOME VARCHAR(30),
VALOR NUMERIC(15,4))

as
begin
for select CODIGO, NOME from CLIENTES
where CODIGO = :PCOD
into :COD, :NOME do
begin

   select VALOR from VALORES
   where CODIGO = :COD
   into :VALOR;
   if ((VALOR IS NULL) or (VALOR = 0)) then
   VALOR = 1;
   suspend;

end;
end

Como traduzir as mensagens do Delphi

Boa tarde,
Abaixo uma dica valiosa de como traduzir as mensagens que o delphi retorna, após identificar uma operação ilegal.
O arquivo das mensagens que você deverá traduzir está em \Arquivos de Programas\ Borland\ Delphixx\ Source\ Vcl\ Consts.pas.
Traduza as mensagens normalmente. Depois de alterar o arquivo, eu salvo uma cópia na pasta \bin e na pasta \lib. O programa já funciona com os alertas traduzidos.
Você deverá traduzir também o arquivo DBConsts.pas que contém as mensagens relativas a componentes database.

segunda-feira, 20 de dezembro de 2010

Cálculo do Dígito Verificador da Chave de Acesso do CT-e

Fonte:  www.activedelphi.com.br

Antes de demonstrar como gerar o digito verificador, vamos entender do que é composta a chave de acesso.
A Chave de Acesso do Conhecimento de Transporte Eletrônico é representada por uma seqüência de 44 caracteres numéricos, representados da seguinte forma:
Código da UF - Código da UF do emitente do Documento Fiscal (Tamanho 2 caracteres)
Ano e Mês da Emissão (AAMM) - Ano e Mês de emissão do CT-e (Tamanho 4 caracteres)
CNPJ - CNPJ do emitente (Tamanho 14 caracteres)
Modelo - Modelo do Documento Fiscal (Tamanho 2 caracteres)
Série - Série do Documento Fiscal (Tamanho 3 caracteres)
Numero do CTe - Número do Documento Fiscal (Tamanho 9 caracteres)
Código Numérico - Código Numérico que compõe a Chave de Acesso (Tamanho 9 caracteres)
Digito - Dígito Verificador da Chave de Acesso (Tamanho 1 caractere)

O Cálculo
O dígito verificador da chave de acesso do CT-e é baseado em um cálculo do módulo 11. O módulo 11 de um número é calculado multiplicando-se cada algarismo pela seqüência de multiplicadores 2,3,4,5,6,7,8,9,2,3, ... posicionados da direita para a esquerda.
A somatória dos resultados das ponderações dos algarismos é dividida por 11 e o DV (dígito verificador) será a diferença entre o divisor (11) e o resto da divisão:
DV = 11 - (resto da divisão)
Quando o resto da divisão for 0 (zero) ou 1 (um), o DV deverá ser igual a 0 (zero).
Vamos exemplificar toda essa teoria no Delphi.
Primeiro devemos desenhar o formulário. Nesse exemplo estou utilizando dois edit’s para exemplificar melhor o funcionamento, porém em seu projeto poderá realizar tudo no mesmo Edit. Coloquei também um botão para acionar o evento do cálculo quando clicar. Veja como ficou a interface na figura 1:
 O primeiro Edit vamos chamá-lo de edtChave. O segundo Edit, de edtDV.
No edtChave, vamos informar uma chave de exemplo, retirada da página 74 do Manual de Integração – Contribuinte Padrões Técnicos de Comunicação.

Chave Exemplo: 5206043300991100250655012000000780026730161. O dígito verificador dessa chave deverá ser igual à “5”
Agora vamos ao código do botão.  O algoritmo foi montada de forma bem primária para facilitar o entendimento, mas lembre-se que você pode usar arrays para facilitar:
procedure TForm1.btnGerarDigitoClick(Sender: TObject);
Var
  // Essas serão as variáveis responsáveis por armazenar cada numero da chave
  V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17,
    V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, V30, V31, V32,
    V33, V34, V35, V36, V37, V38, V39, V40, V41, V42, V43: Real;
 
  // as variáveis abaixo serão responsáveis por armazenar os resultados
  //das multiplicações
  R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17,
    R18, R19, R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32,
    R33, R34, R35, R36, R37, R38, R39, R40, R41, R42, R43: Real;
 
  // Utilizaremos as variáveis abaixo para formulação do resultado
  Soma, Divisao, Resultado: Real;
  SomaI: integer;
begin
  // Através do código abaixo, vamos separar os valores com a “função Copy”
  //da chave de acesso
  V1 := StrToFloat(Copy(edtChaveAcesso.Text, 1, 1));
  V2 := StrToFloat(Copy(edtChaveAcesso.Text, 2, 1));
  V3 := StrToFloat(Copy(edtChaveAcesso.Text, 3, 1));
  V4 := StrToFloat(Copy(edtChaveAcesso.Text, 4, 1));
  V5 := StrToFloat(Copy(edtChaveAcesso.Text, 5, 1));
  V6 := StrToFloat(Copy(edtChaveAcesso.Text, 6, 1));
  V7 := StrToFloat(Copy(edtChaveAcesso.Text, 7, 1));
  V8 := StrToFloat(Copy(edtChaveAcesso.Text, 8, 1));
  V9 := StrToFloat(Copy(edtChaveAcesso.Text, 9, 1));
  V10 := StrToFloat(Copy(edtChaveAcesso.Text, 10, 1));
  V11 := StrToFloat(Copy(edtChaveAcesso.Text, 11, 1));
  V12 := StrToFloat(Copy(edtChaveAcesso.Text, 12, 1));
  V13 := StrToFloat(Copy(edtChaveAcesso.Text, 13, 1));
  V14 := StrToFloat(Copy(edtChaveAcesso.Text, 14, 1));
  V15 := StrToFloat(Copy(edtChaveAcesso.Text, 15, 1));
  V16 := StrToFloat(Copy(edtChaveAcesso.Text, 16, 1));
  V17 := StrToFloat(Copy(edtChaveAcesso.Text, 17, 1));
  V18 := StrToFloat(Copy(edtChaveAcesso.Text, 18, 1));
  V19 := StrToFloat(Copy(edtChaveAcesso.Text, 19, 1));
  V20 := StrToFloat(Copy(edtChaveAcesso.Text, 20, 1));
  V21 := StrToFloat(Copy(edtChaveAcesso.Text, 21, 1));
  V22 := StrToFloat(Copy(edtChaveAcesso.Text, 22, 1));
  V23 := StrToFloat(Copy(edtChaveAcesso.Text, 23, 1));
  V24 := StrToFloat(Copy(edtChaveAcesso.Text, 24, 1));
  V25 := StrToFloat(Copy(edtChaveAcesso.Text, 25, 1));
  V26 := StrToFloat(Copy(edtChaveAcesso.Text, 26, 1));
  V27 := StrToFloat(Copy(edtChaveAcesso.Text, 27, 1));
  V28 := StrToFloat(Copy(edtChaveAcesso.Text, 28, 1));
  V29 := StrToFloat(Copy(edtChaveAcesso.Text, 29, 1));
  V30 := StrToFloat(Copy(edtChaveAcesso.Text, 30, 1));
  V31 := StrToFloat(Copy(edtChaveAcesso.Text, 31, 1));
  V32 := StrToFloat(Copy(edtChaveAcesso.Text, 32, 1));
  V33 := StrToFloat(Copy(edtChaveAcesso.Text, 33, 1));
  V34 := StrToFloat(Copy(edtChaveAcesso.Text, 34, 1));
  V35 := StrToFloat(Copy(edtChaveAcesso.Text, 35, 1));
  V36 := StrToFloat(Copy(edtChaveAcesso.Text, 36, 1));
  V37 := StrToFloat(Copy(edtChaveAcesso.Text, 37, 1));
  V38 := StrToFloat(Copy(edtChaveAcesso.Text, 38, 1));
  V39 := StrToFloat(Copy(edtChaveAcesso.Text, 39, 1));
  V40 := StrToFloat(Copy(edtChaveAcesso.Text, 40, 1));
  V41 := StrToFloat(Copy(edtChaveAcesso.Text, 41, 1));
  V42 := StrToFloat(Copy(edtChaveAcesso.Text, 42, 1));
  V43 := StrToFloat(Copy(edtChaveAcesso.Text, 43, 1));
 
  // Conforme explicado anteriormente neste artigo, faremos a multiplicação
  // por  2,3,4,....9
  R43 := V43 * 2;
  R42 := V42 * 3;
  R41 := V41 * 4;
  R40 := V40 * 5;
  R39 := V39 * 6;
  R38 := V38 * 7;
  R37 := V37 * 8;
  R36 := V36 * 9;
  R35 := V35 * 2;
  R34 := V34 * 3;
  R33 := V33 * 4;
  R32 := V32 * 5;
  R31 := V31 * 6;
  R30 := V30 * 7;
  R29 := V29 * 8;
  R28 := V28 * 9;
  R27 := V27 * 2;
  R26 := V26 * 3;
  R25 := V25 * 4;
  R24 := V24 * 5;
  R23 := V23 * 6;
  R22 := V22 * 7;
  R21 := V21 * 8;
  R20 := V20 * 9;
  R19 := V19 * 2;
  R18 := V18 * 3;
  R17 := V17 * 4;
  R16 := V16 * 5;
  R15 := V15 * 6;
  R14 := V14 * 7;
  R13 := V13 * 8;
  R12 := V12 * 9;
  R11 := V11 * 2;
  R10 := V10 * 3;
  R9 := V9 * 4;
  R8 := V8 * 5;
  R7 := V7 * 6;
  R6 := V6 * 7;
  R5 := V5 * 8;
  R4 := V4 * 9;
  R3 := V3 * 2;
  R2 := V2 * 3;
  R1 := V1 * 4;
 
  // Somaremos os valores obtidos dos resultados das multiplicações
  Soma := R1 + R2 + R3 + R4 + R5 + R6 + R7 + R8 + R9 + R10 + R11 + R12 + R13 +
    R14 + R15 + R16 + R17 + R18 + R19 + R20 + R21 + R22 + R23 + R24 + R25 +
    R26 + R27 + R28 + R29 + R30 + R31 + R32 + R33 + R34 + R35 + R36 + R37 +
    R38 + R39 + R40 + R41 + R42 + R43;
 
  SomaI := Trunc(Soma);
  Divisao := (SomaI mod 11);
  Resultado := 11 - Divisao;
 
  // Compara se o resultado é igual a 1 (Se for deverá ser = 0)
  if Resultado = 1 then
    edtDV.Text := '0'
  else
    edtDV.Text := FloatToStr(Resultado);
end;
Pronto!! Agora é só adaptar o algoritmo ao seu projeto. Para customizar e reduzir o tamanho do código, você poderá utilizar arrays para alimentação das variáveis e multiplicação dos resultados.

quarta-feira, 3 de novembro de 2010

Trabalhando com horas

Se você esta querendo fazer um acumulador de horas, você pode criar dois acumuladores, um para horas, e, outro para minutos.

 

Exemplo:

 

Type

TypeHora:Array[1..2] of interger;

 

Procedure Acumula:TypeHora;

Var

Hora,minuto:Integer;

Begin

  Hora:=Hora+StrToInt(Copy(DateTimeToStr(Time()),1,2));

  Minuto:=Minuto+StrToInt(Copy(DataTimeToStr(Time()),4,5));

  If Minuto >= 60 Then Begin

      Hora:=Hora+1;

      Minuto:=0;

  end;

  Acumula[1]:=Hora;

  Acumula[2]:=Minuto;

End;

Desta forma voce pode armazemar por exemplo o numero de horas que uma pessoa trabalhou durante o mes...

Validar datas

try

   StrToDate(Edit1.Text); //--Entre parenteses informar a data a ser validada.

except

   on EConvertError do

   ShowMessage ('Data Inválida!');

end;

Obtendo o extenso do mês passado por parâmetro

Function MesExtenso (xMes : Variant) : string;

Var

  Dia, Mes, Ano : Word;

begin

  Mes := 0;

  Case VarType (xMes) of

  VarDate : DecodeDate (xMes, Ano, Mes, Dia);

  VarString :

  Try

   Mes := StrToInt (xMes);  

  Except

  End;

  else

  Try

   Mes := Round (xMes);

  Except

  End;

end;

 case Mes of

 1: Result := 'Janeiro';

 2: Result := 'Fevereiro';

 3: Result := 'Março';

 4: Result := 'Abril';

 5: Result := 'Maio';

 6: Result := 'Junho';

 7: Result := 'Julho';

 8: Result := 'Agosto';

 9: Result := 'Setembro';

 10: Result := 'Outubro';

 11: Result := 'Novembro';

 12: Result := 'Dezembro';

 else

  Result := '';

 end;

end;

 

Obtendo o próximo dia útil caso a data informada caia em um fim de semana

Function ProximoDiaUtil (dData : TDateTime) : TDateTime;

begin

    if DayOfWeek(dData) = 7 then

         dData := dData + 2

    else

    if DayOfWeek(dData) = 1 then

         dData := dData + 1;

    ProximoDiaUtil := dData;

end;

 

Quantos fins de semana já se passaram no corrente ano

A função abaixo retorna quantos finais de semana já se passaram no ano corrente:

 

function WeekNum(const TDT:TDateTime) : Word;

var

                Y,M,D:Word;

                dtTmp:TDateTime;

begin

                DecodeDate(TDT,Y,M,D);

                dtTmp := EnCodeDate(Y,1,1);

                Result := (Trunc(TDT-dtTmp)+(DayOfWeek(dtTmp)-1)) DIV 7;

                if Result = 0 then begin

                       Result := 51

                end

                else

                begin

                       Result := Result-1;

                end;

End;

segunda-feira, 18 de outubro de 2010

Conceito de Banco de Dados

Bancos de Dados
Conceitos Importantes
O gerenciamento de bancos de dados é essencial para o desenvolvimento comercial, e para criar um banco de dados eficiente é necessário o conhecimento prévio de modelagem de bancos de dados relacionais. Conceitos como banco de dados, tabelas, campos, registros, índices, chaves, relacionamentos, normalização, dentre outros são pré-requisitos básicos para o desenvolvimento desse conteúdo.
Modelo de Dados
É essencial planejar o banco de dados antes de implementar. Um dos métodos que você pode utilizar é o DER, como no exemplo não normalizado mostrado logo abaixo.

imagem1
Borland Database Engine
A BDE fornece a capacidade de acesso padronizado a banco de dados para Delphi, C++ Builder e outros ambientes de programação da Borland, oferecendo um grande conjunto de funções para auxiliar no desenvolvimento de aplicações Desktop e Cliente/Servidor.
Os controladores da BDE podem ser usados para acessar bases de dados dBase, Paradox, Access, FoxPro, Interbase, Oracle, Sybase e MS-SQL Server, DB2, Informix, além de um controlador de acesso a arquivos texto. Você também pode utilizar fontes de dados ODBC, podendo acessar qualquer base de dados compatível.
As funções que compõe uma API da BDE são usadas internamente pelos componentes de acesso a dados do Delphi e muito raramente você teria que usá-las diretamente, mas isso é totalmente possível. A referência completa das funções da BDE, com exemplos em Delphi, está no BDE API Help na pasta do Delphi no Menu Iniciar.
Arquitetura de Acesso
O acesso e manipulação de um banco de dados por um programa Delphi é realizado como mostrado abaixo, note que a aplicação não acessa os dados diretamente, mas usa sempre a BDE.

imagem2
Assim, para uma aplicação de bancos de dados funcionar, é preciso que a BDE esteja instalada na máquina, não bastando apenas o arquivo executável.
Criação do Banco de Dados
Para criar um banco de dados novo, normalmente, é necessário dispor de alguma ferramenta do próprio banco de dados, como o Access, mas se a base de dados for Paradox, ou dBase, você pode usar o Database Desktop, um utilitário que vem com o Delphi e permite a criação desses tipos de bancos de dados.
Database Desktop
Fornece uma interface simples e completa para configuração, definição e manipulação de tabelas de bancos de dados Paradox e dBase. Além disso na Opção Tools/Alias Manager você pode configurar seu banco de dados, como será lembrado logo adiante.
Tabelas Paradox
Para criar tabelas Paradox, siga os passos abaixo. Você deve salvar as tabelas de um mesmo banco de dados na mesma pasta, pois o Paradox trata a pasta onde estão as tabelas como sendo o banco de dados.
Clique em File/New/Table
Escolha o tipo da nova tabela, Paradox 7
Aparece uma janela para que você defina a estrutura de campos, índices e demais opções necessárias na criação da tabela
Em Field Name, você escolhe o nome do campo, com até 25 caracteres
Em Type, o Tipo do campo, com a barra de espaço ou o botão direito do mouse você pode escolher o tipo a partir de uma lista
Size é o tamanho do campo, usado somente em alguns tipos de campos
Key especifica os campos que farão parte da chave primária, que não pode se repetir e deve ser composta pelos primeiros campos da tabela
Table Properties
Em Table Properties você define os vários aspectos de configuração da tabela. Muitas dessas opções podem ser implementadas no Delphi e vários programadores preferem não usá-las no Database Desktop.
Opção Descrição
Validity Checks Validações para os campos, como obrigatoriedade, valor mínimo e máximo
Table Lookup Indica que o valor atribuído a um determinado campo tem que estar gravado em outra tabela
Secondary Indexes Cria índices secundários
Referential Integrity Cria integridade referencial, geralmente utilizada em relacionamentos de 1 para N.
Password Security Permite a criação de senhas, protegendo a tabela de acesso não autorizado
Table Language Especificar o driver de língua utilizado pela tabela, geralmente é o Pdox ANSI Intl850
Dependent Tables Mostra todas as tabela dependentes através da integridade referencial
Tipos de Campos
Os principais tipos de campos são mostrados abaixo, mas existem outros além desses. Os tamanhos marcados com asterisco indicam que o campo pode guardar tamanhos maiores que os informados, o que ultrapassar o tamanho será guardado em um arquivo externo com a extensão MB.
Tipo Descrição Faixa Tamanho
A Alfanumérico 1-255
N Numérico ± 10 308
$ Monetário
S Short Integer ± 32767
I Long Integer ± 2147483648
D Data
T Hora
@ Data e Hora de modificação
M Memo 1-240*
G Gráfico 1-240*
L Lógico True/False
+ Autoincremental 1-2147483648
Configuração
Para configurar o acesso a um banco de dados, você tem várias opções, criar um Alias, usar o componente TDatabase ou os dois juntos.
Aliases
Um Alias é um nome lógico, um atalho para um banco de dados. Todo o trabalho do Delphi com um banco de dados pode ser feito baseado no Alias, de forma que para mudar de banco de dados, só é necessário mudar o Alias. Para criar um Alias você pode usar Database Explorer, o BDE Administrator ou o próprio Database Desktop.
Database Explorer
Pode aparecer com os nomes Database Explorer ou SQL Explorer. Nele você pode manipular os Aliases, navegar pelas estruturas dos bancos de dados, alterar os dados das tabelas e executar comandos SQL.
Para criar um Alias selecione o item Databases, clique em Object/New, escolha o tipo do banco de dados, ou Standard para dBase, Paradox e arquivos texto, depois digite um nome do Alias, esse nome será usado pelo Delphi quando você quiser acessar o banco de dados, finalmente defina as propriedades do banco de dados na seção Definition, cada banco de dados terá suas próprias definições.
BDE Administrator
Com o BDE Administrator você pode alterar a configuração da BDE, por exemplo em Configuration/System/Init você tem a propriedade Local Share que deve ser setada para True, quando você quiser que a base de dados seja compartilhada em uma rede. Além disso, você pode criar Aliases, como no Database Explorer.
TDatabase
Esse componente permite a manipulação de um banco de dados, através de um Alias da BDE ou a criação de um Alias local, somente visível dentro da aplicação, esse componente também permite o gerenciamento de transações, garantindo uma integridade maior no projeto. Por essas e outras razões o uso do componente Database é altamente recomendado como opção para criação de Aliases.
Propriedades Descrição
AliasName Nome do Alias do banco de dados, usado quando você criar um Alias da BDE
Connected Define se a conexão com o banco de dados está ativa
DatabaseName Nome do Alias local a ser usado pelos outros componentes do Delphi
DataSetCount Número de DataSets (Tabelas) abertos no banco de dados
DataSets Lista com os DataSets abertos
DriverName Driver usado para criar um Alias local, automaticamente cancela a propriedade AliasName
InTransaction Define se o Database está em transação
KeepConnection Define se a conexão com o banco de dados será mantida, mesmo sem DataSets abertos
LoginPrompt Define se será mostrado o quadro de login padrão da BDE
Params Parâmetros do banco de dados, com itens semelhantes à seção Definition do Database Explorer
TransIsolation         Nível de isolamento da transação, define como uma transação irá enxergar outra
Métodos Descrição
Close Encerra a conexão com o banco de dados, todos os DataSets serão fechados
CloseDataSets Fecha todos os DataSets abertos, mas a conexão não é encerrada
Commit Grava alterações feitas durante a transação
Open Abre a conexão com o banco de dados
Rollback Anula todas as alterações feitas durante a transação
StartTransaction Inicia uma transação
Eventos Descrição
OnLogin Evento usado quando você quiser escrever seu próprio método de conexão com o banco de dados
Para acessar uma base de dados Access, você poderia usar os valores mostrados na descrição textual a seguir.
AliasName = 'Northwind'
DatabaseName = 'Dados'
LoginPrompt = False
KeepConnection = True
Params.Strings = (
'DATABASE NAME=C:\Meus Documentos\NorthWind.mdb'
'USER NAME=paulo'
'OPEN MODE=READ/WRITE'
'LANGDRIVER=intl850'
'PASSWORD=elvis')
Para ajudar a preencher os parâmetros de um Database, clique duas vezes sobre o componente e clique em Defaults, todos os parâmetros defaults serão apresentados.
Para acessar uma base Paradox, use as propriedades abaixo, note que para o Paradox, a única informação realmente significante é o Path, a pasta onde estão as tabelas.
AliasName = 'DBDEMOS'
DatabaseName = 'Dados'
LoginPrompt = False
KeepConnection = True
Params.Strings = (
'PATH=d:\Borland\Delphi 3\Demos\Data'
'ENABLE BCD=FALSE'
'DEFAULT DRIVER=PARADOX')
Após a criação do Alias da BDE ou do Alias local, usando o componente TDatabase, o banco de dados está configurado e pronto para ser usado.
Database Form Wizard
Após a configuração do banco de dados, a maneira mais rápida, de se fazer uma janela de manutenção de dados é através do Form Wizard no menu Database. Ao chegar no Wizard são feitas uma série de perguntas que podem resultar em uma janela simples ou Mestre/Detalhe. O acesso ao banco de dados pode ser feito através de componentes TTable ou através de SQL, com o componente TQuery, usaremos o componente TTable. Todos os campos selecionados aparecem na janela permitindo entrada de dados através de componentes do tipo TDBEdit. Cada DBEdit recebe um Label baseado no nome do campo na tabela selecionada. Na Janela é incluído também um componente para permitir a navegação e a manutenção dos dados, um DBNavigator. O componente utilizado para fazer a ligação entre os componentes visuais e o TTable é um TDataSource. Geralmente os componentes TTable e TDataSource são inseridos em DataModules, que são a base para a criação de classes de dados. Sempre Após usar o Wizard, lembre-se de mudar os nomes dos componentes, para que fiquem mais claros.
Form Passo a Passo
O diagrama abaixo mostra como o Wizard fez a ligação entre os componentes, onde os quadrados são componentes e as elipses, propriedades.

imagem3
Para concluir, acompanhe abaixo os passos realizados pelo Wizard e tente você mesmo criar seu próprio Form.
Inclua um novo DataModule
Adicione ao DataModule um Table e um DataSource
No Table Coloque em DatabaseName o nome do Alias criado pela propriedade DatabaseName do Database e em TableName, o nome da tabela
No evento OnCreate do DataModule, chame o método Open do componente Table
No DataSource coloque em DataSet o nome do componente TTable
No Form, para definir a interface com o usuário, use os componentes de controle de dados que estão na página DataControls, basicamente DBEdit e DBNavigator
Para poder acessar os dados, coloque a Unit onde está o DataModule no uses da Unit do Form
Em todos os componentes DataControls, escolha na propriedade DataSource, o componente DataSource criado no DataModule
Em alguns controles, como no DBEdit, deve ser especificado também o campo da tabela, na propriedade DataField
Seguindo esses passos, o Form estará pronto para usar. Mais adiante, veremos uma forma mais rápida de se criar um Form de manutenção, mas o mais importante é compreender os passos mostrados acima, com todos os componentes e propriedades envolvidas. Vamos detalhar agora cada um dos componentes envolvidos nesse processo, para compreendermos melhor o que está acontecendo.
TDataModule
Um DataModule é como se fosse um Form invisível, onde iremos inserir os componentes de acesso a dados, como o Table e o Datasource. Por serem também classes, os DataModules permitem a fácil implementação de modelos de objetos, permitindo herança, criação de métodos, dentre outros aspectos. Para inserir um DataModule em um projeto, escolha New DataModule do menu File. Os DataModules não gastam recursos do sistema, servem apenas para conter os componentes de acesso a dados e criar, assim, uma classe persistente.
TTable
Componente usado para acessar uma tabela em um banco de dados. Esse componente é o mais importante quando acessamos bases de dados Desktop. Muitas dos itens mostrados abaixo estão definidos na classe TDataSet, ancestral do TTable.
Propriedades Descrição
Active Define se a tabela esta aberta ou fechada
BOF Informa se está no início da tabela
CanModify Define se a aplicação pode inserir, deletar ou alterar registros
DatabaseName Nome do banco de dados onde está a tabela, deve ser escolhido um Alias, que pode ser local
EOF Informa se está no fim da tabela
Exclusive Define se a tabela pode ser compartilhada por outro usuário
FieldCount Número de campos da tabela
FieldDefs Lista com a Definição dos campos da tabela
Fields Lista de objetos do tipo TField, que representam os campos da tabela
Filter String com uma condição de filtragem
Filtered Define se a tabela é filtrada
IndexFieldNames Nome dos campo de índice, usados para ordenar os registros da tabela
IndexName Nome do índice atual, vazia quando o índice for a chave primária
IndexDefs Lista com a definição dos índices
MasterFields Campos usados no relacionamento com a tabela mestre
MasterSource DataSource da tabela mestre em uma relação Mestre/Detalhe
Modified Define se o registro atual foi modificado
ReadOnly Define se a tabela é somente para leitura
RecNo Número do registro atual
RecordCount Número de registros
State Estado da tabela
TableName Nome da tabela
TableType Tipo da tabela
Método Descrição
AddIndex Cria um novo índice, a tabela deve ser exclusiva
Append Entra em modo de inserção e, ao gravar, o registro será colocado no fim do arquivo
AppendRecord Insere um registro no final do arquivo através de código
Cancel Cancela as alterações feitas no registro atual
Close Fecha a tabela
CreateTable Cria uma tabela, depende de FieldDefs e IndexDefs
Delete Exclui o registro corrente
DeleteIndex Exclui um índice
DeleteTable Exclui a tabela
DisableControls Desabilita a atualização dos controles visuais
Edit Permite a alteração dos campos do registro atual
EmptyTable Apaga todos os registro da tabela, para isso a tabela não pode esta sendo compartilhada
EnableControls Habilita os controles visuais
FieldByName Acessa um campo, do tipo TField, pelo nome
FindKey Procura o registro com os valores exatos aos dos parâmetros nos campos do índice atual
FindNearest Procura o registro com os valores mais aproximados aos dos parâmetros nos índices
First Move para o primeiro registro
Insert Entra em modo de inserção de um novo registro na posição atual
InsertRecord Adiciona um novo registro, já com os dados, na posição atual
IsEmpty Define se a tabela está vazia
Last Move para o último registro
Locate Procura um registro, usando ou não índices, de acordo com a disponibilidade
LockTable Trava a tabela
Lookup Procura um registro e retorna valores dos campos deste
MoveBy Move um número específico de registros
Next Move  para o próximo registro
Open Abre a tabela
Post Grava as alterações no registro atual
Prior Move para o primeiro registro
Refresh Atualiza a tabela com os dados já gravados
RenameTable Renomeia a tabela
UnlockTable Destrava a tabela
Evento Descrição
AfterCancel Após do método Cancel
AfterClose Após o fechamento da tabela
AfterDelete Após do método Delete
AfterEdit Após do método Edit
AfterInsert Após do método Insert
AfterOpen Após do método Open
AfterPost Após do método Post
AfterScroll Após mudar de registro
BeforeCancel Antes do método Cancel
BeforeClose Antes do fechamento da tabela
BeforeDelete Antes do método Delete
BeforeEdit Antes do método Edit
BeforeInsert Antes do método Insert
BeforeOpen Antes do método Open
BeforePost Antes do método Post
BeforeScroll Antes de mudar o registro
OnCalcFields Evento usado para calcular os valores dos campos calculados
OnDeleteError Quando ocorre um erro ao chamar o método Delete
OnEditError Quando ocorre um erro ao chamar o método Edit
OnFilterRecord Evento usado com filtragem variável
OnNewRecord Quando a tabela entra em modo de inserção, não deixa Modified igual a True
OnPostError Quando ocorre um erro ao chamar o método Post
Filtros
Usando o Filter, você pode filtrar os registro de uma tabela usando uma expressão lógica, como nos exemplos abaixo. Para tornar um filtro ativo, basta colocar Filtered igual a True.
Data = '20/04/1998'
(Data = '20/04/1998') AND (Vendedor = 'Gilherme Augusto da Fonseca')
(Nome > 'A') AND (Nome < 'B')
Contudo, se a condição de filtragem for muito variável, é preferível usar um código como o mostrado abaixo no evento OnFilterRecord da Table, para fazer uma filtragem dinâmica, com a propriedade Filter vazia e Filtered igual a True.
Accept := TblData.Value = Date;
Ao filtrar uma tabela, a propriedade RecordCount da Table, só mostra o número de registros que satisfazem ao filtro, como se os outros registros nao existissem.
Alterando Registros
Para alterar registros em código, colocamos a tabela em modo de edição, alteramos o valor dos campos e gravamos as alterações, se for necessário.
with DtmPedidos do;
begin
Tbl.Edit;
TblData.Value := Date;
TblHora.Value := Time;
Tbl.Post;
end;
Inserindo Registros
Para inserir registros em código você pode usar os métodos AppendRecord e InsertRecord, caso você não precise de algum campo, mesmo assim ele deve ser informado com o valor Null.
DtmProd.Tbl.AppendRecord([Null, EdtDescricao.Text, EdtPreco.Text]);
Localizando Registros
Para localizar registros você pode usar vários métodos, mas o melhor deles é o Locate, no exemplo abaixo é feita uma pesquisa exata.
if not DtmCli.Tbl.Locate('CodCli', Edt.Text, []) then
ShowMessage('Cliente não encontrado.');
Você também pode fazer uma pesquisa parcial e/ou sem sensitividade de caso usando o terceiro parâmetro, que é um conjunto de opções.
DtmCli.Tbl.Locate('Nome', Edt.Text, [loPartialKey, loCaseInsensitive]);
Se você precisar fazer uma pesquisa por mais de um campo, separe os nomes dos campos por ponto e vírgula e use a função VarArrayOf para criar um array com os valores que você quer procurar.
if not DtmPed.Tbl.Locate('Vendedor;Data', VarArrayOf([EdtVendedor.Text, EdtData.Text]),
[loCaseInsensitive]) then
ShowMessage('O vendedor não realizou nenhuma venda nessa data');
Caso os campos pesquisados sejam indexados, a pesquisa será muito mais eficiente, senão será criado um filtro temporário da BDE para localizar os registros
Indexação
A indexação é usada para ordenar os registros da tabela, para isso você deve escolher os campos pelos quais você quer ordenar na propriedade IndexFieldNames, inclusive em código, como mostrado abaixo, todos campos devem ser indexados e separados por ponto e vírgula.
DtmCli.Tbl.IndexFieldNames := 'Nomcli';
DtmPed.Tbl.IndexFieldNames := 'Data, Vendedor';
Estados da Tabela
A propriedade State determina o estado das tabelas, os principais estados são demonstrados abaixo, veja como os métodos mudam o estado.

imagem4
Verificando Alterações
Onde for necessário a verificação de alterações feitas em uma Tabela, por exemplo no evento OnClose de um Form de manutenção, você pode usar a propriedade Modified, como mostrado no exemplo abaixo.
if DtmCli.Tbl.Modified then
if Application.MessageBox('Gravar alterações?', 'Dados Alterados', MB_ICONQUESTION
   + MB_YESNO) = IDYES then
   DtmCli.Tbl.Post
else
   DtmCli.Tbl.Cancel;
Valores Default
Caso você queira especificar valores Default para os campos de uma tabela, use o evento OnNewRecord, pois nesse evento o registro não é marcado como modificado.
TblData.Value := Date;
Percorrendo uma Tabela
Utilize um código semelhante ao mostrado abaixo para percorrer uma tabela do início ao fim.
Tbl.DisableControls;
Total := 0;
Tbl.First;
while not Tbl.EOF do
begin
Total := Total + TblValor.Value;
Tbl.Next;
end;
Tbl.EnableControls;
Forms Modais de Inclusão/Alteração
Para mostrar Forms Modais de inclusão ou alteração de registros utilize comandos como os mostrados abaixo.
TblCli.Insert;
if FormInsCli.ShowModal = mrOk then
TblCli.Post
else
TblCli.Cancel;
Mestre/Detalhe
Nos relacionamentos de 1 para N, uma tabela pode estar ligada a outra em uma relação Mestre/Detalhe, nesse tipo de relação os registros da tabela de ordem N são filtrados pelo campo de relacionamento com a tabela de ordem 1. Por exemplo, se o relacionamento de Clientes com Pedidos  for mestre/detalhe, só serão acessados em pedidos, os registros cujo campo CodCli seja igual ao CodCli da tabela de Clientes.
Para fazer esse tipo de relacionamento, siga os passos abaixo.
No uses da Unit detalhe, Pedidos, inclua a Unit da tabela mestre, Clientes
Na Table detalhe, Pedidos, Coloque em MasterSource o DataSource da tabela mestre, Clientes
Em MasterFields, chame o Fields Links Designer e escolha os campos de ligação das tabelas, no caso, CodCli para as duas tabelas
Fields Editor
Para criar objetos para os campos de uma tabela clique duas vezes no componente TTable ou escolha Fields Editor no seu menu de contexto, na janela do Fields Editor, clique com o botão direito do mouse e escolha Add, na janela Add Fields, escolha os campos que você vai querer usar e clique em Ok.
No Fields Editor podemos também remover os campos criados, alterar sua ordem de apresentação e usar suas propriedades e eventos no Object Inspector. Para cada campo é criado um objeto de um tipo descendente de TField, como TStringField, TIntegerField, TFloatField. As principais propriedades dos objetos TField estão listadas na tabela abaixo.
Se você não criar nenhum objeto TField, todos os campos da tabela estarão disponíveis, mas caso você crie algum, somente os campos que você criar estarão disponíveis.
Se você selecionar os campos no Fields Editor e arrastar para o Form, serão criados os controles visuais para esses campos, Label, DBEdit e outros, mas antes coloque a descrição dos campos na propriedade DisplayLabel.
TField
A classe TField é usada como ancestral para todos as classes dos campos. Geralmente iremos usar objetos de classes descendentes de TField, mas em todos eles podemos encontrar os itens mostrados abaixo.
Propriedades Descrição
Alignment Alinhamento do texto do campo nos controles visuais
AsBoolean Valor do campo convertido para Boolean
AsCurrency Valor do campo convertido para Currency
AsDateTime Valor do campo convertido para DataTime
AsFloat Valor do campo convertido para Double
AsInteger Valor do campo convertido para Integer
AsString Valor do campo convertido para string
AsVariant Valor do campo convertido para Variant
Calculated Indica se o campo é calculado em tempo de execução
CanModify Indica se um campo pode ser modificado
ConstraintErrorMessage Mensagem de erro se a condição de CustomConstraint não for satisfeita
CustomConstraint Condição de validação do campo
DataSet DataSet onde está o campo
DataSize Tamanho do campo, em Bytes
DataType Propriedade do tipo TFieldType, que indica o tipo do campo
DefaultExpression Expressão com valor Default do campo para novos registros
DisplayLabel Título a ser exibido para o campo
DisplayText Texto exibido nos controles visuais associados ao campo
DisplayWidth Número de caracteres que deve ser usado para mostrar o campo no controles visuais
EditMask Máscara de edição do campo
FieldKind Propriedade do tipo TFieldKind que indica o tipo do campo, como Calculado ou Lookup
FieldName Nome do campo na tabela
FieldNo Posição física do campo na tabela
Index Posição do campo nos controles visuais
IsIndexField Indica se um campo é válido para ser usado como índice
IsNull Indica se o campo está vazio
KeyFields Campo chave da tabela no relacionamento com LookupDataSet, usado em campos Lookup
Lookup Indica se um campo é Lookup
LookupCache Define se será usado cache para campos Lookup
LookupDataSet DataSet onde está definido o valor do campo Lookup
LookupKeyFields Campo chave do relacionamento em LookupDataSet
LookupResultField Valor do campo, que será mostrado nos controles visuais
ReadOnly Define se um campo é somente para leitura
Required Define se o campo é obrigatório
Size Tamanho físico do campo
Text Texto de edição do campo
Value Acesso direto ao valor do campo
Visible Define se um campo é visível
Eventos Descrição
OnChange Chamado quando o valor do campo é mudado
OnSetText Chamado pelos controles visuais para atribuir o texto digitado pelo usuário ao campo
OnGetText Chamado para formatar o texto de exibição do campo
OnValidate Validação do valor atribuído ao campo, caso o valor não seja válido, gere uma exceção
Método Descrição
Assign Atribui um valor de um campo a outro, inclusive nulo
FocusControl Seta o foco para o controle visual ligado ao campo nos Forms
Clear Limpa o conteúdo do campo
Estão listadas abaixo algumas classes que realmente iremos manipular no tratamento dos campos de uma tabela, são classes descendentes de TField.
TStringField TBlobField TTimeField
TSmallintField TIntegerField TBytesField
TFloatField TWordField TVarBytesField
TCurrencyField TAutoIncField TGraphicField
TBooleanField TBCDField TMemoField
TDateField TDateTimeField
Em alguns desses campos você pode encontrar as propriedades mostradas abaixo, que não estão presentes em TField.
Propriedades Descrição
MaxValue Valor máximo para o campo
MinValue Valor mínimo para campo
DisplayFormat Formato de apresentação do campo, como ,0.00” %” ou ,0.##” Km”
EditFormat Formato de edição do campo
Currency Define se um campo é monetário
DisplayValues Usado com campos Boolean, define o texto para True e False, como Sim;Não
Métodos Descrição
LoadFromFile Carrega o conteúdo do campo de um arquivo
SaveToFile Salva o conteúdo do campo para um arquivo
Para acessar os campo de uma tabela, existem várias abordagens, como mostrado abaixo..
Usando o objeto TField ligado ao campo.
TblDescricao.Value := TblVendedor.Value + ' em ' + TblData.AsString;
Usando a notação de colchetes. Se você não especificar nenhuma propriedade, é assumida a propriedade Value por padrão.
Tbl['Descricao'] := Tbl['Vendedor'] + ' em ' + Tbl['Data'].AsString;
Através do método FieldByName
Tbl.FieldByName('Descricao').Value := Tbl.FieldByName('Vendedor').Value + ' em '
+ Tbl.FieldByName('Data').AsString;
Usando a lista Fields do TTable
Tbl.Fields[5].Value := Tbl.Fields[3].Value + ' em ' + Tbl.Fields[4].AsString;
Conversão de Tipos
A conversão de tipo de um campo pode ser feita através as propriedades tipo As..., como AsString.
DtmPed.TblData.AsString := EdtData.Text;
Validação
Para validar os valores de um campo, você pode usar a propriedade CustomConstraint, por exemplo para garantir que a quantidade de um item seja maior que zero, use em CustomConstraint Quantidade > 0, e em CustomConstraint coloque a mensagem para o usuário caso a condição seja falsa. Outra forma, mais flexível, é usando o evento OnValidate, com um código como abaixo, onde é gerada uma exceção para cancelar a atribuição do valor ao campo.
if TblQuantidade.Value <= 0 then
raise Exception.Create('Quantidade deve ser maior que zero.');
Formatação Personalizada
Caso queira fazer uma formatação personalizada do campo, pode usar os eventos OnGetText e OnSetText. Por exemplo, se tiver um campo Estado, e quiser que quando o valor do campo for C fosse mostrado Casado S, Solteiro, no evento OnGetText use um código como o abaixo.
if TblEstado.Value = 'C' then
Text := 'Casado'
else if TblEstado.Value = 'S' then
Text := 'Solteiro';
Como controle visual para o usuário escolher o valor do campo, você poderia usar o DBComboBox, com Solteiro e Casado na propriedade Items, e no evento OnGetText do campo o código mostrado abaixo.
if Text = 'Casado' then
TblEstado.Value := 'C'
else if Text := 'Solteiro' then
TblEstado.Value = 'S';
Campos Calculados
Para criar campos calculados, clique com o direito no Fields Editor e escolha New Field, no quadro NewField, digite o nome do campo, o nome do objeto será automaticamente informado, o tipo do campo, seu tamanho e escolha Calculated em Field type.
Para colocar um valor nesse campo usaremos o evento OnCalcFields do componente TTable, em nenhuma outra parte os valores desses campos podem ser alterados.
O código do evento OnCalcFields deve ser enxuto, pois este é chamado várias vezes durante a edição de um registro e um procedimento pesado pode comprometer a performance do sistema.
procedure TDtmAluno.TblCalcFields(DataSet: TDataSet);
begin
if TblFaltas.Value > DtmTurma.TblMaxFaltas.Value then
   TblSituacao.Value := 'Evadido'
else if TblNota.Value >= 7 then
   TblSituacao.Value := 'Aprovado'
else
   TblSituacao.Value := 'Retido'
end;
Campos Lookup
Para fazer um relacionamento, às vezes precisamos criar um campo de descrição, por exemplo em uma biblioteca, na tabela de empréstimos, temos o código do Livro, mas gostaríamos de mostrar o Título, esses campos são chamados de campos Lookup.
Para criar um campo Lookup, siga os passos abaixo, tomando como exemplo o caso do livro no empréstimo.
Abra o Fields Editor do Table desejado, Empréstimos
Clique com o direito e escolha New Field
No quadro New Field, escolha as propriedades do campo como descrito em campos calculados, mas em Field type, escolha Lookup
Em Key Fields escolha o campo da tabela que faz parte do relacionamento, CodLivro
DataSet é a tabela onde está a descrição, Livros
Em Lookup Keys, escolha o campo de DataSet que faz parte do relacionamento, CodLivro
Finalmente, escolha em Result field o campo de DataSet que vai ser mostrado para o usuário, Título
Essas opções correspondem a algumas propriedades do objeto TField gerado, que podem ser alteradas no Object Inspector, KeyFields, LookupDataSet, LookupKeyFields, LookupDataSet e LookupResultField.
Quando esses campo são exibidos em um DBGrid, por padrão é criado um botão de lookup que mostrará os valores da outra tabela uma lista. Para colocar esses campos em um Form, devemos usar o DBLookupComboBox, apenas com as propriedades padrão, DataSource e DataField, onde deve ser escolhido o campo Lookup, quando você arrastar o campo para o Form isso será feito automaticamente.
TDataSource
Componente usado para fazer a ligação entre um DataSet e os componentes visuais.
Propriedade Descrição
AutoEdit Define se a tabela entrará em modo de edição assim que o usuário digitar novos valores nos controles
DataSet DataSet ao qual o TDataSource faz referência
Evento Descrição
OnDataChange Ocorre quando o DataSet é alterado, ao mudar de registro ou mudar os valores dos campos
OnStateChange Ocorre quando o estado do DataSet é alterado
OnUpdateData Ocorre antes de uma atualização
Botões de Navegação Personalizados
O DBNavigator tem os principais botões necessários para a navegação por uma tabela, contudo se você quiser criar seus próprios botões de navegação, o que não é recomendado, no evento OnClick desses botões deve ser chamados os métodos de navegação, como indicado abaixo.
DtmCli.Tbl.Next;
Para controlar a habilitação dos botões de navegação use o evento OnDataChange do DataSource correspondente como indicado abaixo.
BtnProx.Enabled := not DtmCli.Tbl.EOF;
Para criar botões de controle, como inclusão e exclusão, use o evento OnStateChange do DataSource como indicado abaixo para controlar a habilitação.
BtnAlterar.Enabled := DtmCli.Tbl.State = dsBrowse;
Data Controls
Controles usados na interface com o usuário. Todos esses componentes tem uma propriedade DataSource, que deve ter o DataSource do Table ao qual estão ligados.
TDBNavigator
O DBNavigator permite que o usuário realize operações padrão de controle de dados. Cada um dos botões do DBNavigator chama um método do Componente Table ao qual está ligado.
Podemos personalizar o DBNavigator usando as suas propriedades e eventos, mas se quisermos mudar a figura dos botões teremos que editar diretamente o arquivo LIB\DBCTRLS.RES, na pasta do Delphi.
Propriedades Descrição
VisibleButtons Define os botões que serão visíveis
Hints Hints exibidos pelos botões
ConfirmDelete Define se será solicitado uma confirmação antes da exclusão
Eventos Descrição
BeforeAction Quando um botão do Navigator é pressionado, antes da ação ser executada
OnClick Quando um botão do Navigator é pressionado, depois da ação ser executada
TDBGrid
Mostra os registros de uma tabela em forma de grade, cada coluna é um campo e cada registro, uma linha.
Propriedades Descrição
Columns Lista do tipo TDBGridColumns, com as colunas da Grid, cada item da lista é do tipo TColumn
Fields Lista de  objetos TField mostrados nas colunas
Options Set com as opções da Grid, como ConfirmDelete, MultiSelect, ColumnResize
SelectedField Campo da coluna selecionada
SelectedIndex Índice da coluna selecionada
SelectedRows Lista do tipo TBookmarkList, com os registros selecionados em uma Grid com MultiSelect
TitleFont Fonte do título das colunas
FixedColor Cor Fixa, usada nas colunas e indicadores
Eventos Descrição
OnCellClick Ao clicar em uma célula da Grid
OnColEnter Quando uma célula de alguma coluna da Grid recebe o foco
OnColExit Quando uma célula de alguma coluna da Grid perde o foco
OnColumnMoved Quando o usuário mover uma coluna
OnDrawDataCell Evento usado para personalizar a forma de desenhar os dados que são apresentados na Grid
OnEditButtonClick Ao clicar no botão de edição de uma célula, mostrado pela propriedade ButtonStyle da coluna
OnTitleClick Ao clicar no título das colunas
TColumn
Item de uma lista TDBGridColumns, usada na propriedade Columns da Grid, objetos desse tipo representam uma coluna da Grid. Às vezes as propriedades definidas para o campo sobrepõem as propriedades
Propriedades Descrição
ButtonStyle Botão mostrado ao editar as células da coluna
Field Objeto TField ligado à coluna
FieldName Nome do campo ligado à coluna
PickList TStrings com os itens da lista DropDown usada nas células da coluna
Title Propriedade do tipo TColumnTitle com as opções do título da coluna
TDBText, TDBEdit, TDBMemo, TDBListBox, TDBComboBox, TDBImage, TDBRichEdit
Controles genéricos ligados a um campo de uma tabela.
Propriedades Descrição
DataField Campo ao qual o controle está ligado
TDBCheckBox
Usado em campos que podem receber apenas dois valores, como campos lógicos.
Propriedades Descrição
ValueChecked Valor a ser armazenado quando está selecionado
ValueUnchecked Valor a ser armazenado quando não está selecionado
TDBRadioGroup
Mostra algumas opções para o preenchimento de um campo.
Propriedades Descrição
Values Valor a ser armazenado para cada botão de rádio
TDBLookupListBox, TDBLookupComboBox
Preenche um campo com dados contidos em outra tabela. Se o campo mostrado nesses componentes for um campo Lookup, você não precisa especificar nenhuma das propriedades abaixo, apenas DataSource e DataField.
Propriedades Descrição
ListSource DataSource que contém os valores a serem exibidos na lista
ListField Campo de ListSource que será exibido
KeyField Campo de ListSource usado no relacionamento
Exercícios
1. Crie uma aplicação que cadastre os Clientes de uma empresa e as Compras feitas por estes Clientes, permita inclusão, alteração, exclusão e consulta aos dados cadastrados. Na janela principal fica o cadastro de Clientes, com a grade de visualização de suas Compras, crie também uma Janela para localizar Clientes por Nome.
A tabela de clientes deve ter Nome, Endereço, Bairro, Cidade, Estado, CEP e Telefone, defina também índices para melhorar a localização de clientes por Nome. Na tabela de Compras, deseja-se saber a Data, Produtos e Valor, assuma que cada compra tem um Produto apenas. Como foi mencionado, as compras serão cadastradas pelo cliente atual, crie a relação Mestre/Detalhe entre Clientes e Compras.
O Form de localização de Clientes deve permitir pesquisa Nome, da mesma forma da questão anterior.
2. Uma academia de ginástica deseja manter um controle maior sobre seus Alunos, para isso ela organizou os clientes em turmas. Os dados de uma Turma são Número de alunos, Horário da aula, Duração da aula, Data inicial, Data final e Instrutor. Deve ser feita também uma tabela de instrutores para evitar a digitação repetitiva do Nome. Os dados dos Alunos são Matrícula, Data de Matrícula, Nome, Endereço, Bairro, Cidade, Estado, Telefone, Data de nascimento, Altura e Peso. Crie um banco de dados, normalizado, para guardar essas informações.
No cadastro de Turmas, o Horário de aulas deve ser entre 7:00 e 18:00, a Duração não pode ser maior que 2 horas e a Data Final tem que ser, no mínimo 5 dias após a Inicial. Esse cadastro deve ser ordenado primeiro pela Data Final, em ordem decrescente e depois pelo Horário, em ordem crescente. As turmas já encerradas não devem ser mostradas no cadastro, mas crie um arquivo morto com as turmas já encerradas, onde os dados não possam ser alterados. Deve ser possível também procurar o Instrutor pelo Nome, usando um ComboBox, com os registros da tabela de Instrutores.
No cadastro de Alunos, a matrícula é Auto-incremental, a Data de Matrícula deve ser, obrigatoriamente, a Data do sistema e deve ser criado um campo calculado com o peso ideal do cliente, altura menos 1,15.