Você está na página 1de 30

Revista The Club Megazine - 02/2002

A utilizao, reproduo, apropriao, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criaes intelectuais em cada publicao da revista The Club so terminantemente proibidos sem autorizao escrita dos titulares dos direitos autorais.

Copyright The Club 2002

EDITORIAL

Editorial
Ol amigos, THE CLUB
Rua Acre, 950 - Avar - SP - CEP 18.700-260 Informaes: (0xx14) 3732-3689 Suporte: (0xx14) 3733-1588 Fax: (0xx14) 3732-0987

Internet
http://www.theclub.com.br Cadastro: cadastro@theclub.com.br Suporte: suporte@theclub.com.br Informaes: info@theclub.com.br

Dvidas
Correspondncia ou fax com dvidas devem ser enviados ao - THE CLUB, indicando "Suporte".

Opinio
Se voc quer dar a sua opinio sobre o clube em geral, mande a sua correspondncia para a seo "Tire sua dvida".

Neste ms vamos abordar assuntos interessantes. Vamos ver como possvel trabalhar com o Decision Cube sem estar ligado ao BDE. Muitos de nossos scios esto solicitando esta soluo junto ao suporte tcnico. Vamos tambm falar sobre automao comercial. Veja como emitir cupons a prazo e receber parcelas de carns. Sobre Palm ns vamos ver um componente para ler arquivos PDB que so transportados para o desktop e tambm cri-los, possibilitando o envio ao equipamento. E muito mais. Gostaria de agradecer a todos os associados do The Club que esto escrevendo para dizer sobre o que gostaram de ver publicado em nossa revista, enviando dicas e solues e mensagens de apoio. Continuem escrevendo, o nosso e-mail sugestoes@theclub.com.br. At a prxima.

Reproduo
A utilizao, reproduo, apropriao, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criaes intelectuais em cada publicao da Revista The Club so terminantemente proibidos sem autorizao escrita dos titulares dos direitos autorais.

Copyright The Club 2002 Impresso e acabamento:


Impressos Gril - Gril Grfica e Repr. Ind. Ltda.
Tel.: (0xx14) 3762.1345 - Fax: (0xx14) 3762.1259 Rua So Paulo, 447 - Cep 18.740-000 Taquarituba - SP Tiragem: 5.000 exemplares

Celso Jefferson Paganelli Presidente - The Club

Diretor - Presidente

Celso Jefferson M. Paganelli


Diretor Tcnico

Editorial ........................................................................................03 Executando Programas no .NET ......................................................04 Estruturando datamarts em bases Oracle (2) ...................................09 No ECF (Impressora Fiscal) O que fazer para... ................................11 Especificadoes de Armazenamentos ...............................................14 Usando o Decision Cube sem BDE ..................................................16 Arquivos PDB com o Delphi ..........................................................21 Perguntas e Respostas ...................................................................27

Mauro SantAnna
Colaboradores
Mrio Camilo Bohm - Claudenir C. Andrade Anderson Haertel Rodrigues - Marcio Alexandroni
Delphi marca registrada da Borland International, as demais marcas citadas so registradas pelos seus respectivos proprietrios.

MeGAZINE

COLUNA DO SANTANNA

Executando Programas no .NET


Por Mauro SantAnna (santanna@mas.com.br). Mauro um MSDN Regional Director, consultor e instrutor da MAS Informtica (www.mas.com.br), tendo ministrado treinamentos na arquitetura .NET desde outubro de 2000 para diversas empresas, dentre as quais a prpria Microsoft.

A maneira de executar programas no Windows era chamando a API CreateProcess, o que dava um certo trabalho. Sincronizar o nosso aplicativo com o trmino do programa dava mais trabalho ainda, pois precisvamos lidar com threads e semforos. Tudo isso ficou mais fcil no .NET Framework, pois temos classes especficas para fazer estes trabalhos, especialmente na classe Process do namespace System.Diagnostics. Para ver um exemplo, criaremos um projeto do tipo Windows Application no Visual Studio .NET:

MeGAZINE

COLUNA DO SANTANNA

Coloque componentes visuais como mostrado ao lado:

A classe Process serve tanto para criar novos processos como para obter informaes de processos que j estejam rodando. Uma observao importante: estes exemplos devem estar rodando com altos privilgios de segurana. Na instalao padro do .NET Framework, voc deve ter privilgio de administrador de sistema e rodar o executvel a partir do disco local.

Executando
Para executar um programa, basta ajustar a propriedade StartInfo.FileName com o nome do executvel e chamar o mtodo Start(). Veja um trecho de cdigo correspondente ao evento Click do boto Executa: private void button1_Click(object sender, System.EventArgs e) { // Ajusta nome do programa process1.StartInfo.FileName = textBox1.Text; // Executa process1.Start(); }

A propriedade StartInfo permite fazer outros ajustes antes do programa iniciar, como por exemplo: Arguments: Argumentos de linha de comando passados ao programa; UseShellExecute: Pede para que o Windows Explorer chame o programa ao invs de ShellExecute ao invs de CreateProcess. Isto permite coisas como executar documentos (na verdade, o programa associado ao documento); EnvironmentVariables: Permite ajustar variveis de ambiente para o novo programa.

Esperando
Podemos aguardar o fim do programa chamando o mtodo WaitForExit: private void button2_Click(object sender, System.EventArgs e) { button2.Enabled = false; try { // Ajusta nome do programa process1.StartInfo.FileName =

MeGAZINE

COLUNA DO SANTANNA
textBox1.Text; // Executa process1.Start(); // Espera terminar process1.WaitForExit(); } finally { button2.Enabled = true; } } O cdigo acima bloqueia o processamento de mensagens at que o programa chamado termine. Isto funciona, mas faz com que seu programa parea travado ao usurio final. De forma a permitir que o programa processe outras mensagens, devemos fazer o seguinte: Ajustar a propriedade EnableRaisingEvents para true; Interceptar o evento Exited. Veja um exemplo a seguir: private void button3_Click(object sender, System.EventArgs e) { button3.Enabled = false; // Ajusta nome do programa process1.StartInfo.FileName = textBox1.Text; // Executa process1.Start(); } // Aviso do fim do programa private void process1_Exited(object sender, System.EventArgs e) { button3.Enabled = true; } override public string ToString() { return string.Format({0} ({1}), EsteProcesso.ProcessName, EsteProcesso.Id); } } private void button4_Click(object sender, System.EventArgs e) { // Pega caractersticas de todos os processos Process [] Programas = Process.GetProcesses(); listBox1.Items.Clear(); // Exibe no ListBox (chamando ToString de MeuProcesso) foreach(Process P in Programas) { MeuProcesso Pr; Pr.EsteProcesso = P; listBox1.Items.Add(Pr); } } O cdigo abaixo chamado quando o ndice do ListBox muda e exibe informaes mais detalhadas do processo: // Elemento que ser colocado no ListBox struct MeuProcesso { public Process EsteProcesso; // Define o que ser exibido no ListBox override public string ToString() { return string.Format({0} ({1}), EsteProcesso.ProcessName, EsteProcesso.Id); } } private void button4_Click(object sender, System.EventArgs e) { // Pega caractersticas de todos os processos Process [] Programas = Process.GetProcesses(); listBox1.Items.Clear(); // Exibe no ListBox (chamando ToString de MeuProcesso) foreach(Process P in Programas) { MeuProcesso Pr; Pr.EsteProcesso = P; listBox1.Items.Add(Pr); } } // Um megabyte const double UmMB = 1024 * 1024; // Pega caractersticas de um // processo

Informaes dos programas


Alm de permitir saber quais programas esto rodando, a classe Process permite obter diversas informaes de cada um deles, como por exemplo: Memria usada (diversos tipos); Prioridade; Nome e caminho do executvel do programa; DLLs carregadas; Data e hora de incio e trmino; Tempo de CPU usado. O cdigo abaixo lista os processo em um ListBox: // Elemento que ser colocado no ListBox struct MeuProcesso { public Process EsteProcesso; // Define o que ser exibido no ListBox

MeGAZINE

COLUNA DO SANTANNA
string PegaCaracteristicas(Process P) { if (P.HasExited) { // Pode ser que ele tenha terminado return Processo terminado; } else { return string.Format( Working Set (MB): {0:n2}\r\nMemria virtual total (MB): {1:n2}\r\n, P.WorkingSet / UmMB, P.VirtualMemorySize / UmMB); } } // Pega nomes das DLLs usadas string PegaNomesDLLs(Process P) { string Resultado = ; // Pega lista de DLLs do programa ProcessModuleCollection Modulos = P.Modules; if (Modulos != null) { // Varre a lista e pega nome foreach (ProcessModule M in Modulos) {Resultado += + M.ModuleName + ( +M.FileName + ) + \r\n; } } return Resultado; } private void listBox1_SelectedIndexChanged (object sender, System.EventArgs e) { try { // Verifica se realmente algum tem // est selecionado if (listBox1.SelectedIndex >= 0) { // Pega o processo corrente MeuProcesso Pr = (MeuProcesso) listBox1.Items [listBox1.SelectedIndex]; // Monta texto e exibe textBox2.Text = >>>>> Processo: + Pr.ToString() + \r\n + PegaCaracteristicas (Pr.EsteProcesso) + >>>>> DLLs:\r\n + PegaNomesDLLs (Pr.EsteProcesso); } } catch (Exception E) { textBox2.Text = E.Message; } } Veja a sada do programa:

MeGAZINE

COLUNA DO SANTANNA
Terminando programas
A classe Process tambm pode ser usada para terminar os programas. Na verdade temos duas maneiras de terminar programas, conforme o mtodo utilizado: CloseMainWindow(): S funciona com programas com janela; pede que o programa cometa suicdio, onde ento ele tem a chance de arrumar a casa fechando arquivos e conexes de bancos de dados abertas, terminando impresso etc. O programa pode at mesmo recusar o pedido e continuar rodando. Kill(): Funciona com qualquer tipo de programa e os termina incondicionalmente, sem dar chance do programa arrumar a casa. Veja exemplo: // Mata delicadamente private void button5_Click(object sender, System.EventArgs e) { // Verifica se realmente algum tem est // selecionado if (listBox1.SelectedIndex >= 0) { // Pega o processo MeuProcesso Pr = (MeuProcesso) listBox1.Items[listBox1.SelectedIndex]; // Termina de forma civilizada, dando a // chance do programa arrumar a casa Pr.EsteProcesso.CloseMainWindow(); } } // Mata violentamente private void button6_Click(object sender, System.EventArgs e) { // Verifica se realmente algum tem est // selecionado if (listBox1.SelectedIndex >= 0) { // Pega o processo MeuProcesso Pr = (MeuProcesso) listBox1.Items[listBox1.SelectedIndex]; // Mata sem d, no dando a chance do // programa arrumar a casa Pr.EsteProcesso.Kill(); } }

O .NET Framework permite manipular com facilidade os programas rodando na mquina atravs da classe Process.

Concluso

ORACLE

Estruturando datamarts em bases Oracle... (2)


Mrio Camilo Bohm - Bohm,Interal Fone (011) 4221.6151 - mario@bohminteral.com.br
Continuando nossa discuso sobre a criao de datamarts, bases destinadas especificamente a consulta de dados estatsticos de corporaes, vamos nos preocupar agora em atualizar a base que criamos. (CLIENTES.CHAVE = NOTAS.CHAVE_CLIENTE) AND (PRODUTOS.CHAVE = NOTAS_ITENS.CHAVE_PRODUTO); EXIT; O parmetro NOLOGGING que adicionamos, faz com que as alteraes nesta tabela no sejam includas nos redo log files e, portanto, no sejam recuperveis atravs de recover, seja em aes de recomposio de backup on-line, seja em aes de recover automtico em caso de queda do servidor. Ora, mas isso no um problema?, pode estar se perguntando o leitor mais atento... No. O uso do parmetro NOLOGGING faz com que o banco no perca tempo e recursos com o registro de todas as atividades da tabela, para controlar a necessidade de recover. Isso porque iremos sempre apagar e reconstruir a tabela, que potencialmente ter muitos registros. Desta forma, o banco ir gerar muitos logs que no serviro para nada, j que basta rodarmos novamente o script e a tabela ser reconstruda. E isso nos dar mais performance! E como podemos reconstruir automaticamente a tabela de tempos em tempos?

Atualizando o Datamart
Lembram-se do script que criamos para gerar a tabela que estamos utilizando para o datamart? Pois bem, rodando este script que iremos atualizar as informaes de consulta. Vamos denomin-lo AUTO1.SQL e apenas fazer pequenas alteraes, deixando-o assim: DROP TABLE FATURAMENTO_1; CREATE TABLE FATURAMENTO_1 NOLOGGING AS SELECT NOTAS_ITENS.CHAVE, NOTAS_ITENS.CHAVE_NOTA, NOTAS_ITENS.CHAVE_PRODUTO, NOTAS_ITENS.PRECO_VENDA, NOTAS_ITENS.VALOR_ITEM, NOTAS.DATA_EMISSAO, NOTAS.CHAVE_CLIENTE, NOTAS.TIPO, NOTAS.VALOR_TOTAL, PRODUTOS.CODIGO, PRODUTOS.DESCRICAO, CLIENTES.NOME, CLIENTES.CGC, CLIENTES.INSCRICAO FROM NOTAS_ITENS, NOTAS, PRODUTOS, CLIENTES WHERE (NOTAS.CHAVE = NOTAS_ITENS.CHAVE_NOTA) AND

Chamando o SQLPlus atravs de um script


Quando voc precisa executar qualquer comando no banco, voc no utiliza o SQLPlus? Pois exatamente isso que iremos fazer, chamando o SQLPlus e nos conectando ao banco atravs de um script.

MeGAZINE

ORACLE
Com o comando F:\ORACLE\ORA81\BIN\SQLPLUS [USER]/ [PASSWORD] @F:\AUTO\AUTO1.SQL Onde - F:\ORACLE\ORA81\BIN o path em que est localizado o arquivo SQLPLUS.EXE da mquina onde o script ser rodado; - [USER]/[PASSWORD] o string de conexo com o banco em que ser rodado o script, como por exemplo USUARIO/SENHA@HOST_NAME; - @F:\AUTO\AUTO1.SQL o path do script que desejamos rodar, denominado, como exemplo, AUTO1.SQL. Simples no? Pois . Com este script, voc se conecta ao banco e executa o contedo do script. E isso pode ser programado para rodar automaticamente, por exemplo, todo dia noite, sem interveno humana!

Automatizando a execuo do script


E como podemos fazer isso? Simples tambm. Atravs do agendamento de tarefas do Windows 2000 Server, que vamos tomar como exemplo, embora a funo de agendamento de tarefas esteja disponvel em qualquer sistema operacional, como Linux, Windows NT, Unix, etc. Crie uma nova tarefa agendada e configure para execuo o script que denominamos AUTO1.SQL: (Figura acima). Programe-o para rodar, por exemplo, diariamente s 20:00 horas. (Figura ao lado). Se tiver dvidas como programar tarefas no seu sistema operacional, consulte as referncias tcnicas. Desta forma, sempre pela manh voc ter as informaes do datamart de faturamento atualizadas at o dia til anterior. importante considerar que a grande maioria dos datamarts no esto online com a base transacional, porque voc j deve estar se perguntando o porque desse delay de um dia nas informaes. Primeiro porque estar desligado da base transacional importante para a performance e nos traz muitas facilidades na manuteno da base de consultas e segundo porque, corporativamente, muito mais importante a existncia de dados histricos de grande abrangncia (de 5 anos por exemplo) do que de dados das operaes do dia anterior. Divirta-se!

10

MeGAZINE

DELPHI

No ECF (Impressora Fiscal)O que fazer para....


Comearemos aqui uma seo dedicada automao comercial, onde nossa equipe Bematech estar contribuindo para escrever dicas e truques de como utilizar o ECF e suas peculiaridades. Claudenir C. Andrade

Emitir Cupom A Prazo e Receber Carn das Prestaes


Aqui entra uma operao que voc pode muito bem utilizar a impressora fiscal e seus totalizadores, descarregando da aplicao o controle fiscal e contbil deste processo. Um Recebimento de um Carn uma operao que entra dinheiro no caixa, mas no deve ser tributado pois voc j tributou este valor na compra inicial quando o cliente levou a mercadoria. Vamos imaginar que nosso consumidor X comprou da empresa Y uma geladeira no valor de R$ 1.000,00 reais para pagar em 4 vezes de R$250,00 reais. Quando nosso consumidor adquirir e levar a geladeira dever ser emitido um cupom fiscal normalmente, como se fosse uma venda a vista, podendo colocar na forma de pagamento em um comprovante no fiscal vinculado a indicao que a compra a prazo e que por sua vez acarretar em um recebimento de 4

prestaes de 250,00 Reais. Traduzindo este cupom em Cdigo Ficar assim: /* Abrimos o cupom fiscal, neste caso como se trata de um eletro interessante que seja informado o CPF ou CGC do consumidor*/ Bematech_FI_AbreCupom(Pchar(038.64.726517)); Bematech_FI_VendeItem(Pchar(7896834200029), Pchar(Geladeira Marca Congela modelo TKODFTO), Pchar(1800), Pchar(I), Pchar(1), Pchar(2), Pchar(1000),Pchar(00), Pchar($), Pchar(0)); Bematech_FI_FechaCupomResumido(Pchar(A) ,Pchar(Prazo),Pchar(Compra no valor de R$1000,00 reais, a ser pago em 4 parcelas, parcela 1(um) vencendo dia 30_01_02, parcela 2(dois) vencendo dia 28_02_02, parcela 03

MeGAZINE

11

DELPHI
(trs) vencendo dia 30_03_02 e parcela 04 (quarto) vencendo dia 30_04_02 - Todas as parcelas com valor Fixo de R$250,00 Pagamentos devem ser efetuados na loja da Rua XV primeiro andar)); Esta uma maneira de emitir o cupom fiscal e por sua vez indicar que a compra a prazo e que dever ser recebida em Carn. Um outro truque interessante utilizar o comprovante no fiscal vinculado para a emisso e at mesmo impresso do Carn a ser pago, da seguinte maneira: /* Abrimos o cupom fiscal, neste caso como se trata de um eletro interessante que seja informado o CPF ou CGC do consumidor*/ Bematech_FI_AbreCupom(Pchar(038.64.7265-17); Bematech_FI_VendeItem(Pchar(7896834200029), Pchar(Geladeira Marca Congela modelo TKODFTO),Pchar(1800),Pchar(I), Pchar(1),Pchar(2),Pchar(1000,00), Pchar($),Pchar(0)); /*Fechamos o cupom fiscal com uma mensagem promocional simples*/ Bematech_FI_FechaCupomResumido(Pchar(A Prazo),Pchar(Obrigado!!! Volte Sempre.)); /* Logo aps o fechamento do cupom solicitamos a abertura de um Comprovante No Fiscal Vinculado, esta funo necessita como parmetro Forma de pagamento utilizada no ultimo cupom, valor da forma de pagamento e numero do cupom fiscal/* Bematech_FI_AbreComprovanteNaoFiscalVinculado (Pchar(A Prazo),Pchar(1000,00), Pchar(00234)); /*E assim por diante, repetimos esta operao Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Primeira Parcela Vencimento 30_01_02 - Valor R$250,00 ) ); /*Logo aps solcitamos a impresso das informaes e do carn para pagamento*/ Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Compra no valor de R$1000,00 reais, a ser pago em 4 parcelas, parcela 1(um) vencendo dia 30_01_02, parcela 2(dois) vencendo dia 28_02_02, parcela 03 (trs) vencendo dia 30_03_02 e parcela 04 (quarto) vencendo dia 30_04_02 - Todas as parcelas com valor Fixo de R$250,00 Pagamentos devem ser efetuados na loja da Rua XV primeiro andar)); Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Recorte AquiRecorte Aqui-));

Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Reservado Para Autenticao Favor No Riscar)+#13+#13); Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Recorte AquiRecorte Aqui-)); Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Primeira Parcela Vencimento 28_02_02 - Valor R$250,00 )); Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Reservado Para Autenticao Favor No Riscar)+#13+#13); Bematech_FI_UsaComprovanteNaoFiscalVinculado (Pchar(Recorte AquiRecorte Aqui-));

12

MeGAZINE

DELPHI
mais duas vezes para montar o carn com quatro recibos de pagamento e chamamos a funo para encerrar este relatrio no fiscal Vinculado, esta funo Void*/ Bematech_FI_ FechaComprovanteNaoFiscalVinculado(); Com isso podemos emitir o cupom fiscal e na mensagem promocional do cupom indicar as condies de pagamento etc.. ou utilizar um comprovante no fiscal vinculado para indicar estas informaes adicionais e ainda aproveitar para imprimir o Carn de pagamento das prestaes. Se observarmos o cdigo acima, quando estvamos desenhando o carn de pagamento, temos um espao reservado para a Autenticao, este ser utilizado quando o consumidor for pagar a primeira pestao que para recebermos esta prestao na impressora fiscal deveremos j ter cadastrado um totalizador no fiscal. /*Para nomear um totalizador no fiscal deve ser chamada a funo abaixo que como parmetro necessita um ndice ou cdigo para este totalizador e o nome que voc deseja/* Bematech_FI_NomeiaTotalizadorNaoSujeitoIcms (11,Pchar(Recebimento Carn)); Uma vez com o totalizador cadastrado podemos utiliz-lo para receber valores e habilitar a autenticao do carn, pois o ECF s permite autenticao aps o recebimento de algum valor, seja ele um cupom fiscal ou um comprovante. Quando nosso consumidor se dirigir at o balco para o pagamento da primeira parcela, nosso software dever estar programado para chamar as seguintes funes que formalizao para o ECF o recebimento da Parcela de nosso Carn: /*Indicamos que o pagamento esta sendo realizado em Dinheiro, e que o valor de 250 reais seja contabilizado pelo ECF no Totalizador numero 11 que previamente A Utilizao do comprovante no fiscal vinculado, como fizemos acima para imprimir informaes da prestao e o carn, s poder ser utilizado caso a forma de pagamento do cupom fiscal diferente de Dinheiro, em nosso caso utilizamos A Prazo. Bematech_FI_ProgramaCaracterAutenticacao para criar um pequeno logotipo que identifique. 1) A Programao do totalizador no fiscal deve ser realizada antes de qualquer operao de venda, ou seja, no comeo do dia. Uma Vez programado esta totalizador no necessrio que seja realizada sua programao pois este totalizador no eliminado ao se realizar uma reduo Z, ele Zerado, mas no eliminada sua programao 2) Se voc deseja que seu carn esteja protegido e tenha uma autenticao nica ou que identifique sua loja ou seu software, poder chamar a funo Com as operaes acima, ao realizar uma LeituraX no comeo do dia ou ao Realizar a reduo Z no final do dia, voc ver refletido TOTAL recebido no totalizador Recebimento Carn que voc programou e utilizou, desta forma voc deixou para o ECF realizar toda a operao, desde a emisso do Cupom fiscal, a impresso do Carn e o recebimento das prestaes. /*Solicitamos que o Carn seja autenticado/* Bematech_FI_Autenticao(); Bematech_FI_RecebimentoNaoFiscal(11,Pchar(250,00), Pchar(Dinheiro)); cadastramos/*

CUIDADO!!!!

http://www.bematech.com.br Rua Prof. Henrique Neves Lefvre, 827 So Paulo . SP . 04637-001 Tel.: 11 5536 9986 filialsp@bematech.com.br

MeGAZINE

13

DELPHI

Especificadores de Armazenamentos
A dvida - Default/NoDefault/Stored para as propriedades de um componente.
Por Anderson Haertel Rodrigues - anderson.hr@bol.com.br.
Introduo: Tenho notado em listas de discusso e em alguns lugares na internet a eterna dvida por parte de alguns colegas/desenvolvedores o que realmente , o que fazem e para que servem as diretivas de armazenamentos das propriedades, as famosas: DEFAULT NODEFAULT STORED; Veremos neste artigo como sanar as dvidas! A maioria das propriedades usadas no Object Inspector, so gravadas em arquivos de formulrio (*.DFM), Os .DFM do Delphi so na verdade arquivos de recursos* do sistema operacional, neste caso o Windows. Quando voc compila e cria o seu executvel, anexado ao mesmo os arquivos de recursos, neste caso o .DFM. *Nota: No inteno deste artigo explicar como funciona os arquivos de recursos e tambm como trabalhar com os mesmos em Delphi. Mas, para curiosidade geral, procure por: BRCC32.EXE; E funes da API do Windows como: LoadBitmap(), LoadIcon() , LoadCursor(), LoadString(), FindResource() , LoadResource(), LockResource(), LoadFromResAndSave() entre outras e as famosas Streams. O arquivo de formulrio armazenado com a lista de propriedades e seus valores, podendo se repetir para cada componente no formulrio, porque, armazenado individualmente para cada componente, incluindo aqui o prprio Formulrio. Como padro, quando um componente armazenado, na sua lista so includos os valores das propriedades published que diferem dos valores padro*. Quando se carrega o .DFM, primeiro criado o formulrio e aps isso criado cada componente contido no .DFM e depois disso carregado os valores contidos no .DFM. Neste momento, os valores no padro*, so lidos e carregados e atualizado o componente. Nota: explicado mais adiante o que so os valores padro e no padro para os componentes. Default-NoDefault-Stored so diretivas de armazenamento de valores para propriedades. A diretiva Stored quem realmente controla se a propriedade gravada ou no no arquivo de formulrio .DFM, e as diretivas default/nodefault controlam qual o valor padro da propriedade. Default: Est diretiva indica o valor padro do componente. Veremos como funciona: Digamos que voc deseje dizer a propriedade Tag1 que seu valor padro o seguinte: 23. O que precisaramos fazer para que este valor seja o padro para a propriedade, somente isto: Listagem 1: TEditExamples = class(TEdit) private { Private declarations } FTag1: Integer; protected { Protected declarations } public { Public declarations } published { Published declarations } property Tag1: Integer read FTag1 write FTag1 default 23; end; Certo?. ERRADO!!!!! Vamos ver como se comportou a nossa propriedade com a diretiva Default: Object Inspector:

Figura 1: A propriedade Tag1 com o valor default incorreto. Voc ainda o responsvel por inicializar o valor padro do componente para que o mesmo no seja gravado no arquivo .DFM. Vamos ver como ficou o arquivo .DFM com a declarao mostrada acima, para visualizarmos o arquivo de formulrio no Delphi, devemos pressionar ALT+F12. object Form1: TForm1 Left = 212 Top = 133 Width = 696 Height = 480 Caption = Form1 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = MS Sans Serif Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object EditExamples1: TEditExamples Left = 88 Top = 40 Width = 121 Height = 21 TabOrder = 0 Text = EditExamples1 Tag1 = 0 end end Veja o nosso Tag1 com o valor gravado no arquivo de formulrio=0. Mas, ento como fazemos para que ele tenha o valor default informado por ns e ainda no aparea no arquivo de formulrio: Vamos indicar no constructor do componente qual o valor padro dele:

14

MeGAZINE

DELPHI
A nossa Listagem1 ficar dessa forma agora: Listagem 2: rpida, e por sua vez, tambm reduziu o nmero de vezes que o formulrio precisou ser carregado. Mas, garanto que algum ir perguntar: Ento, onde foi para o valor 23, se este no est mais no Formulrio e como o Delphi saber achar o valor Default? Bom, posso dizer que: Este valor est contido na varivel FTag1 que est declarada na seo private, e ainda posso dizer que, as diretivas citadas no controlam como a propriedade ser usada, este controle feito pela RTTI(Run Time Type Information)* Nota: Este artigo no tem a inteno de ensinar o que a RTTI e como usa-la, mas, para curiosidade geral, procure por: Is, As, TypeCasting, TPropInfo, TTypeInfo, TPropList, entre outros. Nem todas as propriedades podem especificar valor padro, apenas as propriedades de pequeno ordinais de pequenos conjuntos. NoDefault: Serve para indicar que a propriedade no possui um valor Default. Na realidade til para indicar que uma propriedade do qual j tenha sido previamente criado um valor default na classe anterior, no tenha mais este valor. As propriedades se comportam como se no tivessem um valor Default, sendo assim, s necessrio o uso dessa diretiva caso eu necessite realmente retirar o valor default de uma propriedade como j explicado no incio desse pargrafo. Stored: Indica se uma propriedade ou no armazenada no arquivo de formulrio .DFM. Ela deve seguir as seguintes regras: 1) Constantes Booleans: False/True; 2) O nome de um mtodo/function retornando False/True. Sem parmetros; Vou citar um exemplo. A propriedade Color. A propriedade Color declarada em: Graphics.pas. Podemos ver um exemplo do uso de Stored na seguinte declarao: property Color: TColor read FColor write SetColor stored IsColorStored default clWindow; O Mtodo/Funo IsColorStored declarado da seguinte forma: function TControl.IsColorStored: Boolean; begin Result := not ParentColor; End; Onde, se o componente/formulrio tem sua propriedade ParentColor definida para True, no necessrio armazenar o valor de Color no arquivo de formulrio do filho, porque o mesmo j est armazenado no arquivo de formulrio do Pai. Concluso: Os trs especificadores trabalham harmoniozamente juntos e minimizam a quantidade de valores que precisam ser armazenados no arquivo de formulrio. Quando se grava o valor das propriedades em um arquivo de formulrio, A RTTI interage sobre todas as propriedades published do componente/formulrio. A forma como as trs diretivas conversam entre si da seguinte forma: Para cada propriedade avaliada a expresso Stored, se a propriedade False e ou no est ausente, o valor no gravado. Se o resultado True, o valor atual da propriedade comparado com o valor da diretiva default, se o valor igual, o valor/propriedade no armazenado. Se os valores forem diferentes e ou a diretiva nodefault foi especificada, o valor armazenado no arquivo de formulrio.

TEditExamples = class(TEdit)
private { Private declarations } FTag1: Integer; protected { Protected declarations } public { Public declarations } constructor Create(Owner: TComponent); override; published { Published declarations } property Tag1: Integer read FTag1 write FTag1 default 23; end; constructor TEditExamples.Create(Owner: TComponent); begin inherited; FTag1 := 23; end;

Object Inspector:

Figura 2: A propriedade Tag1 com seu valor default correto.. E o arquivo de formulrio ficou assim: object Form1: TForm1 Left = 374 Top = 107 Width = 696 Height = 480 Caption = Form1 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = MS Sans Serif Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object EditExamples1: TEditExamples Left = 88 Top = 80 Width = 121 Height = 21 TabOrder = 0 Text = EditExamples1 end end Onde est a nossa propriedade Tag1? No se encontra mais no arquivo de formulrio. Podemos deduzir que: Com certeza a carga do componente ficou mais

MeGAZINE

15

DELPHI

Usando o Decision Cube sem o BDE


A partir da verso 3, a Borland incluiu um componente TDecisionCube nas edies Client/Server e Enterprise do Delphi. Infelizmente ele requer a utilizao do BDE. Com a migrao para fora do BDE a favor de datasets como dbExpress, ADO e Interbase Express, o componente Decision Cube no foi continuado. Este artigo detalha o que necessrio para conseguir trabalhar com este componente de novo. Existem algumas pequenas inconvenincias ao se trabalhar com o Decision Cube sem o BDE, so elas: Auto-deteco das dimenses e resumos Quando voc conecta um TDecisionCube em uma TQuery ou outro dataset baseado no BDE, o decision cube automaticamente determina quais campos que sero dimensionados e quais sero resumidos agregando campos como por exemplo SUM(), COUNT(), AVG() e assim por diante. Isto lhe permite mostrar um decision grid sem nenhum cdigo adicional. Infelizmente este tipo de trabalho possvel apenas com o BDE. Voc poderia tambm escolher a utilizao da ordem caseinsensitive, a qual ordenaria os caracteres na ordem AaBbCc ou aAbBcC no lugar de abcABC. Quando conectado com um BDE Dataset, o decision cube pode usar a ordem de classificao do BDE. Infelizmente sem o BDE, o decision cube usa a funo AnsiCompareStr que importante se seu database classificar usando a mesma ordem, mas falha se seu database usa, por exemplo, uma classificao ASCII. O banco de dados pode conferir strings em diferentes caminhos, algumas vezes dependendo do caracter configurado. Por exemplo, um caracter configurado como Spanish tem caracteres que o English no tem, o qual deve ser conferido na prpria ordem. com que a sua aplicao obtenha os dados. Ele tambm tem algumas funes que sua aplicao pode usar para fazer algumas coisas a maneira que a base de dados precisar. Uma destas funes a comparao de strings.

Agrupando datas por ms / ano


O primeiro obstculo, est na construo da dimenso. Voc pode fazer isto automaticamente ou manualmente. Ordenando valores nulos, strings vazias e outros caracteres estranhos O BDE faz mais do que ser apenas um mecanismo que faz Quando mostramos a data no decision grid, quase sempre h necessidade de se agrupar por ms ou ano ao invs de mostrar cada data (ou at mesmo agrupar por data e hora) com seu prprio valor. Quando conectado a um BDE DataSet, o decision cube permitir fazer isto alterando a propriedade BinType da dimenso (isto pode ser feito via cdigo ou via caixa de dilogo).

16

MeGAZINE

DELPHI
Solues
A soluo para estes problemas envolve a modificao do cdigo fonte do Decision Cube, o qual faz parte da VCL. Por causa disto, no ser possvel incluir todo o cdigo fonte do Decision Cube sem o BDE como parte deste artigo. Ao invs disso, ser mostrado apenas o cdigo revisado. Para implementar esta soluo voc precisar ter o Delphi Client/Server ou Enterprise. myMap := TCubeDims.Create(DecisionCube1, TCubeDim); try bParsed := false; bDataSetMatch := false; myMap.Assign(TCubeDims(DecisionCube1.DimensionMap)); anError := BuildDataSetMap (IBQuery1, myMap, bParsed, bDataSetMatch); case anError of tqeNotInitialized: raise ECubeDesignError.CreateRes @sQryNotInitialized); tqeNoDimensions: raise ECubeDesignError.CreateRes(@sNoDims); tqeNoAggs: raise ECubeDesignError.CreateRes(@sNoAggs); tqeNotGrouped: raise ECubeDesignError.CreateRes(@sGroupsMissing); end; Passos para construir um Decision Cube 1 Contrua sua Query 2 Construa o mapa dos dados 3 Configure as dimenses e resumos end; Construindo a sua Query: Construir uma instruo SQL que recebe todos os campos e resumos necessrios, incluindo qualquer clusula where e uma clusula group by. Por exemplo: Select Field1, Field2, Count(*), Avg(Field3) from Table group by Field1, Field2 Construindo o mapa de dados: A maior parte do trabalho aqui feito pelo Decision Cube. Voc apenas precisa dizer o que ele deve fazer. Isto o mesmo cdigo que o decision cube usa com os datasets baseados no BDE, mas voc ter que fazer mais na etapa seguinte. var myMap: TCubeDims; nCount: integer; // usado no passo 3 Configure as dimenses e resumos: Finalmente voc deve falar ao decision cube o que fazer com cada campo no dataset. Isto muito simples. Todo o cdigo aqui vai no lugar do comentrio do cdigo para a etapa precedente. with myMap do begin // Parte A: Configure as dimenses for nCount := 0 to [Numero de Dimensoes - 1] do begin Items[nCount].DimensionType := dimDimension; Items[nCount].BaseName := TABLE.FIELDNAME; //Se a dimenso uma data e deveria ser // agrupada, use este cdigo // Aqui onde voc colocar o cdigo do passo 3 finally myMap.Free // DecisionCube1 e IBQuery1 so components // do seu form. DecisionCube1 um // TDecisionCube, e IBQuery1 um TIBQuery, // ou outro descendente de TDataset.

Auto-deteco das dimenses e resumos


A configurao das dimenses podem ser feitas manualmente, em tempo de design, se o seu decision grid mostrar sempre os mesmos campos. Ou pode ser feito manualmente em tempo de runtime pelo usurio, mas esta opo no muito boa. Isto tambm pode ser feito automaticamente, em tempo de run-time, pelo seu cdigo. Isto lhe permite a flexibilidade da modificao do grid sem sobrecarregar o usurio. Note que isto no requer nenhuma mudana no cdigo fonte do decision cube tudo isso feito em seu prprio programa fonte.

MeGAZINE

17

DELPHI
Items[nCount].FieldType:=ftDateTime; Items[nCount].BinType:=binYear {ou} Items[nCount].BinType:=binQuarter {ou} Items[nCount].BinType:=binMonth Items[nCount].BinFormat:=mm/dd/yyyy; Items[nCount].StartValue:=BaseDate; // Se a dimenso no uma data, ou uma // data mas no deveria ser agrupada, use // este cdigo Items[nCount].BinType:=binNone; end; // Part B: Configure os resumos for nCount:=[Numero de dimenses] to [Numero de campos-1] do Items[nCount].DimensionType := dimCount; end; A soluo inicial envolve em fazer uma pequena mudana no // E finalmente, aplique a nova dimenso DecisionCube1.Refresh(MyMap,True); isso a, est pronto. Abra o dataset e voc receber um decision cube. Naturalmente voc pode querer alterar a ordem que os campos aparecem no cubo, mas voc pode fazer isto usando os mtodos normais do decision cube que trabalham bem com o BDE. arquivo mxstore.pas. Encontre o seguinte mtodo. procedure TMultiDimDataLink.UpdateCache (Sender: TObject); Na declarao das variveis remova a seguinte varivel: bHaveBDE: Boolean; Localize a seguinte linha e remova-a. bHaveBDE := True; Localize o trecho abaixo e remova-o. function CmpString(var item1, item2): Integer; No altere o cabealho da funo e as declaraes de varivel, mas substitua o corpo da funo com o cdigo apropriado seqncia da ordem da sua base de dados. Para o Interbase, use o caracter default configurado, veja o cdigo: // Cant differentiate between a null or empty string, Localize a seguinte linha if (FDataStore.BinData) and (bHaveBDE) then E modifique-a para if not (FDataStore.DataSet is TBDEDataSet) then bHaveBDE := IsBDEAvailable; // but this places nulls at the end // of the collation order. if (p1=) and (p2=) then result:=0 else if (p1=) then result:=1 else if (p2=) then result:=-1 else // Otherwise, use CompareStr, which uses the // ASCII character set. Result := CompareStr(p1,p2);

Agrupando datas
A soluo para este problema muito fcil tambm, apesar de ele no trabalhar com todos os datasets. Voc poderia comear a trabalhar com um TIBQuery, mas no com um TADOQuery.

Ordenando valores nulos, strings vazias e outros caracteres estranhos


A soluo para este problema muito simples e requer uma modificao no arquivo mxarrays.pas. Veja esta funo:

18

MeGAZINE

DELPHI
if (FDataStore.BinData) then Localize o seguinte mtodo. procedure TCubeDim.QuarterTransform(var Value: Variant; CubeDim: TCubeDim); E modifique para procedure GetQuarterRange(var Mon, Yr: Word); Substitua a procedure GetQuarterRange inteira, com este cdigo, que baseado no cdigo original: procedure GetQuarterRange(var Mon, Yr: Word); var I: Integer; Q, K, YQ, MQ, DQ: Word; sDate: TDateTime; CY,CM,CD: Word; begin sDate := CubeDim.StartDate; if (sDate = 0) then MQ := 1 else DecodeDate(sDate, YQ, MQ, DQ); DecodeDate(Date,CY,CM,CD); Q := 1; K := MQ; repeat for I := 1 to 3 do begin if (Mon = K) then begin if (Mon >= MQ) then Inc(Yr,(YQ-CY)); if Mon<MQ then inc(yr,(YQ-CY)-1); Mon := Q; Exit; end; Inc(K); if k>12 then k:=1; end; if (K >= 12) then K := 1; Para mudar este comportamento, carregue o arquivo mxgrid.pas e encontre o seguinte mtodo: Localize as linhas iguais a linha abaixo, if FDataStore.DataSet.RecordCount <= 1 then raise ECacheError.Create(sEmptyDataSet); e modifique para if FDataStore.DataSet.RecordCount < 1 then raise ECacheError.Create(sEmptyDataSet); O Decision Grid no usa um PopupMenu atribuido, ele usa sempre seu prprio PopupMenu interno. Isto um pouco estranho, porque o TDecisionGrid publica a propriedade PopupMenu e ento a ignora. Este no um grande problema. procedure TMultiDimDataLink.UpdateCache (Sender: TObject); Inc(Q); until (Q > 4); if (Mon >= MQ) then Inc(Yr,(YQ-CY)); if Mon<MQ then inc(yr,(YQ-CY)-1); Mon := MQ; end; Agora voc pode configurar a propriedade de dimenso StartDate (ou StartValue) para indicar qual o ms/ano usar como base para o calculo. A poro do ms do StartDate indica qual o ms de inicio em Q1. A poro do ano do StartDate indica o ano corrente. Por exemplo, configurando StartDate para 01/01/ 2001 o resultado ser Jan/Fev/Mar (2001)=Q1 2001, Abr/Mai/ Jun(2001)=Q2 2002, etc. Configurando o StartDate para 10/01/ 2002 o resultado ser Jan/Fev/Mar (2001)=Q2 2001, Abr/Mai/ Jun (2001)=Q3 2001, Out/Nov/Dez (2001)=Q1 2002, e assim por diante. A parte do dia do StartDate ignorada.

Mudanas menores
O Decision Cube apresenta uma exceo de dataset vazio no dataset com um registro. Para resolver este problema, carregue o arquivo mxstore.pas e encontre o seguinte mtodo.

MeGAZINE

19

DELPHI
procedure TCustomDecisionGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); Procure no mtodo as referncias para FMenu. Existem trs blocos. Um deles comea como este, FMenu.Clear Outras duas linhas comeam como esta, with FMenu do begin Outra vez, voc far trs mudanas semelhantes. Todos os trs terminam com, if not Assigned(PopupMenu) then begin FMenu.Clear; {or} with FMenu do begin . . . FMenu.PopUpAtMe(Self, X,Y); End;

Concluso
FMenu.PopUpAtMe(Self, X,Y); Este componente introduziu um caminho fcil para que voc Adicione um bloco ifthen em torno da seo FMenu como mostrado abaixo: possa fazer uma analise poderosa de dados, sem a necessidade de escrever muitas linhas de cdigo.

20

MeGAZINE

DELPHI

Arquivos PDB com o Delphi


ClubePalm 2002 por: Marcio Alexandroni
Ol amigos do The Club, continuando a falar sobre como usar o Delphi para integrar solues aos sistemas desenvolvidos para Palm, mostramos agora um componente Shareware para ler arquivos PDB do Palm que so transportados para o desktop e tambm cri-los, possibilitando o envio ao equipamento. Mostramos em uma edio anterior que uma das obrigaes de quem desenvolve aplicaes para Palm de transportar os dados armazenados nele para seu sistema corporativo na retaguarda, por exemplo, no caso de captao de pedidos por vendedores externos, ou mesmo gerar informaes e transmitilas aos Palms dos agentes externos. O mtodo tradicional de executar esta tarefa usar uma aplicao chamada Conduit, que executada durante a operao de sincronismo do Palm (HotSync). Veja o Artigo Conduits em Delphi. Este o mtodo tradicional, mas que possui uma limitao muito grande aos desenvolvedores: a aplicao HotSync do Palm suporta apenas um usurio conectado por vez, o que o torna invivel maioria das aplicaes comerciais. Mais ainda, os produtos que permitem sincronismo de vrios equipamentos ao mesmo tempo so muito caros e so vendidos por nmero de usurios. Para enfrentar esta limitao, os desenvolvedores Palm esto optando por usar um servidor FTP para este sincronismo, enviando os dados para este servidor e deixando o arquivo para que outro aplicativo faa a sincronizao, e tambm gerando arquivos por um aplicativo no servidor para que estes arquivos possam ser transportados ao Palm na mesma conexo FTP, visto que o custo de montagem de um servidor FTP bem acessvel. Alm disso, h softwares freeware FTP para o Palm e bibliotecas que o desenvolvedor pode usar para integrar aos seus aplicativos. O desenvolvedor pode usar o Delphi para ler e gravar arquivos PDB, transportando os dados de/para qualquer Base de Dados que voc deseje. Mais ainda, nesta verso o componente tem suporte nativo a PDBs do NSBasic! Vamos tratar disso neste artigo! Antes, porm, necessrio um pouco de informao a respeito dos Bancos de Dados no Palm. Para quem vem de outras plataformas e linguagens de programao, comum tentar associar um Banco de Dados a um arquivo DBF, Paradox, etc. No possvel! O Banco de Dados do Palm no possui conceito de Campos, ndices e Chave Primria. O PDB (Palm Database) uma estrutura seqencial de registros onde o desenvolvedor responsvel por determinar como os dados so gravados nos registros, e o tamanho de cada registro (porque os registros no precisam ter o mesmo tamanho!). Dentro do Palm, os Bancos de Dados so armazenados em memria, no existe conceito de arquivo como no Windows, extenses, aplicao padro para cada extenso, etc. Tudo o que gravado no Palm feito em Banco de Dados em memria. Quando o sincronismo executado, estes Bancos de Dados em memria so transferidos para o PC, com um nome de arquivo com a extenso PDB. Este o arquivo que iremos ler e gravar! Para obter mais informaes sobre o formato PDB, consulte o artigo FormatoPDB no ClubePalm em www.clubepalm.com.br/ formatopdb.htm. Se voc mesmo desenvolveu sua aplicao para o Palm, seja em C, PocketStudio ou NSBasic, certamente voc sabe como os registros esto gravados, e com este artigo mostraremos como voc pode ter acesso aos seus dados usando o Delphi. Se voc usa outras ferramentas de desenvolvimento como CASL, etc, voc deve obter informaes sobre o formato que elas gravam os registros, para poder ter acesso seus campos. Este Componente Delphi que lhe apresentaremos chama-se PDBDataManager , que possibilita abrir os arquivos PDB como se fossem um Dataset do Delphi, navegar pelos registros e acessar seus dados, e nesta verso, gerao de arquivos PDB! Muitos formatos de gravao podem ser acessados com este componente, ele suporta campos gravados como Strings (terminadas em ZERO), Inteiros (2 ou 4 bytes), Float (4 bytes), Double (8 bytes) e Data/Hora (8 bytes). Veremos isto mais adiante.

MeGAZINE

21

DELPHI
Instalao do Componente
Para nossos exemplos, vamos supor que voc descompactou o pacote com o componente em C:\PDBDataManager . Sob o diretrio PDBDataManager , sero criados os subdiretrios D5 e D6, com os componentes para as verses 5 e 6 do Delphi respectivamente. Para instalar, abra o Delphi, v at o menu Tools , Environment Options e na Tab Library, campo Library Path , acrescente o diretrio C:\PDBDataManager\D5 ou D6, conforme sua verso do Delphi. Depois, v at o menu Component, Install Packages . Clique em Add e move-se at o diretrio correspondente sua verso do Delphi, ento selecione o arquivo PDBDataManD5 ou PDBDataManD6. Uma pasta chamada PDBDataManager ser criada na barra de componentes do Delphi. dados Produtos.pdb, um simples cadastro de produtos com quatro campos, todos os campos tipo String terminados em zero. CadProDelphi: Aplicao Windows e Tabela Paradox Produtos.db para exemplificar a converso de dados entre o PDB<->Windows. A aplicao abre a tabela Produtos.db e apresenta os dados na tela. A tabela tem alguns campos que so usados somente como exemplos, como Alterado e Excludo, porm, se voc colocar o campo Excludo como Verdadeiro (True), o registro no ser gravado no arquivo PDB, caso voc execute a aplicao sob o diretrio CadProCriaPDB. CadProCvFields : Aplicao que converte os dados do arquivo Produtos.pdb para a tabela Produtos.db usando campos definidos do componente PDBDataManager. Nesta verso, possvel detalhar a estrutura do arquivo PDB, informando cada campo e seu tipo, tornando muito simples a recuperao de um valor de um campo ou mesmo estabelecer valores para eles. Veremos isto mais adiante. CadProCvCustom: Aplicao que converte os dados do arquivo Produtos.pdb para a tabela Produtos.db usando o registro puro, separando os campos manualmente. Este exemplo til em casos que o registro no tem um formato padro de gravao, possibilitando a recuperao das informaes pelo ponteiro do registro. CadProCriaPDB: Aplicao que exporta a tabela Produtos.db para o PDB Produtos.pdb, no diretrio que voc especificar na tela principal. Assim como na aplicao Clientes, voc pode usar a aplicao sob o diretrio CadProDelphi para incluir alguns produtos na Tabela Produtos.db e usar esta aplicao para gerar o arquivo PDB, instal-lo no Palm juntamente com a aplicao CadPro.prc, disponvel sob o diretrio CadProPS e ver o resultado da exportao de dados. ProdNSBasicPDB: Contm um banco de dados NSBasic com vrios campos, de vrios tipos de dados, exemplificando como voc pode recuperar registros de tabelas NSBasic que tenham dados gravados como Strings, Double, Date, Time e Integer, de forma nativa. Como espao um fator limitante no Palm, voc pode gravar registros com formatos padro do NSBasic e recuper-los facilmente com o PDBDataManager! ProdNSBasicDelphi: Aplicao que abre o arquivo ProdNSBasic.pdb, disponibilizado no diretrio ProdNSBasicPDB e mostra os campos em uma ListBox. Vamos pegar como primeiro exemplo a aplicao sob o diretrio ClientesCvFields para mostrar como feita a leitura de arquivos utilizando a especificao dos campos do arquivo PDB:

Contedo do pacote
Para exemplificar a utilizao do componente PDBDataManager , disponibilizamos algumas aplicaes-exemplo sob o diretrio Samples , instalado junto com o pacote e que so descritas abaixo, armazenadas nos subdiretrios: ClientesDelphi: Aplicao Windows e uma Tabela Paradox Clientes.db para exemplificar a converso de dados entre o PDB<->Windows. A aplicao abre a tabela Clientes.db e apresenta os dados na tela, alm disso, permite que registros sejam includos, alterados ou excludos. ClientesNSBasic: Colocamos aqui um projeto NSBasic (Clientes.prj), a aplicao j compilada no NSBasic (Clientes.prc) e um arquivo PDB para testes, chamado DBClientes.pdb. ClientesConv: Aplicao que abre o arquivo Clientes.pdb, disponibilizado no diretrio ClientesNSBasic e exporta os dados para a tabela Paradox Clientes.db, basta voc informar os diretrios onde esto localizados os arquivos na tela principal da aplicao. Os diretrios so C:\PDBDataManager\Samples\ ClientesDelphi para a tabela Clientes.db e C:\PDBDataManager\Samples\ClientesNSBasic para o arquivo DBClientes.pdb, isto se voc seguiu nossa sugesto de instalao. ClientesCriaPDB: Aplicao que abre a tabela Paradox Clientes.db e exporta os dados para o arquivo DBClientes.pdb, no diretrio que voc configurar na tela principal. Voc pode utilizar a aplicao sob o diretrio ClientesDelphi, incluir alguns clientes, depois rodar esta aplicao e criar o arquivo DBClientes.pdb. Para test-lo, instale-o no Palm juntamente com a aplicao Clientes.prc, disponibilizada no diretrio ClientesNSBasic. Voc ver os clientes que voc cadastrou mostrados na aplicao no Palm! CadProPS: Aplicao escrita em PocketStudio mais banco de

22

MeGAZINE

DELPHI

Como dissemos anteriormente, voc deve especificar onde est localizada a tabela Clientes.db e o arquivo DBClientes.pdb. Eles esto sob o diretrio: C:\PDBDataManager\Samples\ClientesDelphi e C:\PDBDataManager\Samples\ClientesNSBasic respectivamente. Juntamente com a converso do arquivo PDB, apresentaremos na tela da aplicao informaes relativas a este Banco de Dados. Elas so: Database Name: Nome do Banco de Dados. CreatorID: Todas as aplicaes e Bancos de Dados no Palm tem um identificador nico do criador. Este identificador deve ser registrado no site da Palm Inc. antes que a aplicao seja distribuda em larga escala, sob pena de conflitar com outras aplicaes que possam estar usando o mesmo CreatorID. DBType: Identifica o tipo do Banco de Dados. Como uma aplicao pode abrir vrios Bancos de Dados ao mesmo tempo,

todos eles tem o mesmo CreatorID e um DB Type diferente. Creation Date: Data de Criao do Banco de Dados. Last Backup: ltima vez que o HotSync foi executado para este Banco de Dados. Modification Date: ltima vez que houve modificaes no Banco de Dados. Records: Nmero de Registros do banco de dados. Database Flags: So caractersticas atribudas a um Banco de Dados, como por exemplo, se a aplicao padro de sincronismo do Palm (HotSync) far o Backup deste Banco de Dados. Categories: Alguns Bancos de Dados tem uma lista de Categories, que so classificaes que podem ser atribudas a registros, similares a classes. Um registro s pode ser associado a uma Categoria. Por exemplo, produto classificado na Categoria Alimentcio. Obter estes dados do arquivo PDB muito simples com o PDBDataManager , basta configurar algumas propriedades, abrir o Banco de Dados, informar a estrutura dos campos e ler as informaes. Veja as propriedades do componente:

MeGAZINE

23

DELPHI
Observao (String) e Hora de Atualizao (String). No cdigo associado ao boto Convert, uma das primeiras aes que fazemos informar ao componente, a forma como os campos sero recuperados, e somente depois abrir o arquivo. Isto feito assim: newField := Pdm.Fields.Add; newField.FieldName := Codigo; newField.DataType := pdtString; newField := Pdm.Fields.Add; newField.FieldName := Nome; newField.DataType := pdtString; newField := Pdm.Fields.Add; newField.FieldName := DtCadastro; newField.DataType := pdtDouble; newField := Pdm.Fields.Add; newField.FieldName := LimCredito; newField.DataType := pdtDouble; newField := Pdm.Fields.Add; newField.FieldName := NumCompras; newField.DataType := pdtInteger; newField := Pdm.Fields.Add; newField.FieldName := Obs; newField.DataType := pdtString; newField := Pdm.Fields.Add; newField.FieldName := HoraAtualizacao; newField.DataType := pdtDouble; A funo Add, acrescenta um campo na estrutura interna do registro e retorna um objeto TPDBField, que representa o campo, na varivel newField. Desta forma, para cada campo voc pode associar um nome, importante para poder recuperar e colocar dados nos campos usando a funo FieldByName. Alm disso, importante informar o tipo do campo, isto , de que maneira as informaes esto gravadas no campo. Vamos detalhar isso agora. Tipos suportados no PDBDataManager: pdtByte: O campo em questo representa um byte. Se voc usa NSBasic, este tipo de campo deve ser utilizado se voc gravar no campo, uma varivel tipo Byte. pdtWord: Valor Inteiro com Dois Bytes. Equivalente ao tipo Short do NSBasic, se voc gravar uma varivel Short no banco de dados, este o tipo que voc deve utilizar. pdtInteger : Quatro Bytes Inteiros. Equivalente do tipo Integer do NSBasic. pdtFloat: Quatro Bytes com Ponto-Flutuante. Equivalente ao tipo Single do NSBasic. pdtDouble: Oito Bytes com Ponto-Flutuante. Equivalente ao tipo Double e Float do NSBasic. Nota importante: Observe que os campos DtCadastro e HoraAtualizacao foram declarados como pdtDouble. Vamos explicar isso mais abaixo. pdtDate: 8 Bytes Inteiros representando uma Data no

Creation Date: Data de Criao do Banco de Dados. CreatorID: Identificador do criador do Banco de Dados com quatro caracteres. DatabaseFlags: As configuraes do Banco de Dados. So elas: - dmHdrAttrReadOnly: Banco de Dados somente para leitura. - dmHdrAttrAppInfoDirty: Lista de Categories modificada. - dmHdrAttrBackup: O HotSync far o Backup deste Banco de Dados. - dmHdrAttrOKToInstallNewer: permitido sobrepor este Banco com outro. - dmHdrAttrResetAfterInstall: Fora o Reset do Palm aps a instalao. - dmHdrAttrCopyPrevention: No permite envio do Banco por Infravermelho. DatabaseName: Nome do Banco de Dados at 31 caracteres. DatabaseType: Tipo do Banco de Dados com 4 caracteres. Directory: Diretrio onde o arquivo est gravado. Name: O tradicional nome do componente dentro do projeto. OpenMode: As configuraes possveis so dmModeReadOnly para operao de leitura do arquivo, e dmModeWriteOnly para gravao de arquivos PDB. PDBFilename: Nome do arquivo PDB.

Detalhamento desta aplicao exemplo


Os registros do arquivo DBClientes.pdb tm 7 campos: Cdigo (String), Nome (String), Data de Cadastro (Double), Limite de Crdito (Double), Nmero de Compras (Integer),

24

MeGAZINE

DELPHI
formato PalmOS, isto , nmero de segundos desde Zero Hora de 01/01/1904. Sem equivalente no NSBasic. pdtString: Seqncia de Caracteres terminada com um byte ZERO. Equivalente ao tipo String do NSBasic. Veja o processo de exportao do arquivo PDB para a Tabela Clientes.db: while not EOF do begin // Is it deleted? if (dmRecAttrDelete in GetRecFlags) then begin Next; PB.StepIt; Continue; end; with TbCli do begin Insert; FieldByName(Codigo).AsInteger := StrToInt(Pdm.FieldByName(Codigo).AsString); FieldByName(Nome).AsString := Pdm.FieldByName(Nome).AsString; FieldByName(DtCadastro).AsDateTime := DoubleToDate(Pdm.FieldByName(DtCadastro).AsDouble); FieldByName(LimCredito).AsFloat := Pdm.FieldByName(LimCredito).AsDouble; FieldByName(NumCompras).AsInteger := Pdm.FieldByName(NumCompras).AsInteger; FieldByName(Obs).AsString := Pdm.FieldByName(Obs).AsString; FieldByName(HoraUltAtualizacao).AsDateTime := DoubleToTime(Pdm.FieldByName (HoraAtualizacao).AsDouble); Post; end; // Go to the next record Next; PB.StepIt; end; Perceba que usamos as funes AsString, AsInteger, AsDouble, relativas ao tipo de campo que declaramos na estrutura do arquivo PDB. Para cada tipo de campo suportado h uma funo para recuperao/informao do valor do campo: pdtByte => AsByte pdtWord => AsWord pdtInteger => AsInteger pdtFloat => AsFloat pdtDouble => AsDouble pdtDate => AsDateTime pdtString => AsString Note que grifamos duas funes de converso, DoubleToDate e DoubleToTime. Como a aplicao exemplo do Palm foi escrita em NSBasic, estas duas operaes so necessrias. O NSBasic armazena os tipos Date e Time como valores Double, e gravam esta informao no banco de dados da seguinte maneira: Date: (Ano 1900) * 10000 + Ms * 100 + Dia. Isto faz com que uma data, por exemplo 01/01/2002, seja gravada internamente como 1020101. Time: Hora * 10000 + Minuto * 100 + Segundo. Horas so armazenadas internamente como por exemplo 135210, represetando a hora 13:52:10. As funes DoubleToDate e DoubleToTime transformam os valores em um tipo TDateTime do Delphi com a data e a hora contida nos campos. Estas duas funes esto declaradas na aplicao exemplo.

Acessando o registro sem a estrutura de campos


Se os seus registros no so organizados em campos ou no so campos estruturados, voc pode usar uma outra maneira de acessar as informaes gravadas nele, recuperando os dados diretamente pelo ponteiro do registro. O PDBDataManager disponibiliza o registro como um ponteiro para que voc acesse as informaes dentro dele. Vamos tomar como base a aplicao exemplo do diretrio CadProCvCustom para exemplificar como fazer esta operao. Lembramos que esta uma maneira poderosa, mas ao mesmo tempo perigosa para recuperao de dados, pois qualquer operao errada com o ponteiro pode causar um erro na sua aplicao! while not EOF do begin // Is it deleted? if (dmRecAttrDelete in GetRecFlags) then begin Next; PB.StepIt; Continue; end; mInd := 0; // ID mID := RecordP; mInd := mInd + Length(mID) + 1; // Description mStr := @RecordP[mInd]; mDesc := mStr; mInd := mInd + Length(mDesc) + 1; // Unit mStr := @RecordP[mInd]; mUn := mStr;

MeGAZINE

25

DELPHI
mInd := mInd + Length(mUn) + 1; // Price mStr := @RecordP[mInd]; mPrice := mStr; // Insert in Table with TbProd do begin Insert; FieldByName(NumRegistro).AsInteger := GetRecUniqueID; FieldByName(Codigo).AsInteger := StrToInt(mID); FieldByName(Descricao).AsString := mDesc; FieldByName(Unidade).AsString := mUn; FieldByName(Preco).AsFloat := StrToFloat(mPrice); Post; end; // Next Record Next; PB.StepIt; end; Acessamos o registro com uma varivel PChar, isto , um ponteiro tipo Char para o registro representado por RecordP. Isto nos permite recuperar informaes no registro como se ele fosse um grande Array de Bytes, note que usamos a varivel mInd exatamente para este fim, indicar a posio dentro deste grande Array de Bytes (Registro). Como o arquivo Produtos.pdb, tomado como exemplo nesta aplicao s tem gravados campos String terminados em zero, fica muito fcil a recuperao dos dados, basta: mStr := @RecordP[mInd]; // Colocar o valor do campo em uma varivel PChar mDesc := mStr; // Associar a varivel a uma varivel tipo String mInd := mInd + Length(mDesc) + 1; // Acrescentar nosso ndice com o tamanho dele Uma caracterstica da aplicao CadPro escrita no PocketStudio, que, propositalmente, ela no remove permanentemente os registros que so apagados, ela os marca como excludos. muito importante que ao navegar para o prximo registro, voc teste se ele est apagado, pois o Palm no permite acesso aos dados de um registro marcado como Deleted, provocando uma Exception no componente. Palm em certos projetos. Isto agora pode ser feito com o PDBDataManager! Vejamos a aplicao sob o diretrio ClientesCriaPDB, ela declara a estrutura de campos exatamente como mostramos anteriormente em ClientesConv. Adiciona a estrutura de campos, nomes e tipo de cada um e ao invs de OpenDatabase, esta aplicao chama a funo CreateDatabase para criar o arquivo PDB no diretrio especificado. Depois basta carregar os dados nos campos desta maneira: TbCli.First; while not TbCli.EOF do begin with Pdm do begin Append; FieldByName(Codigo).AsString := TbCli.FieldByName(Codigo).AsString; FieldByName(Nome).AsString := TbCli.FieldByName(Nome).AsString; FieldByName(DtCadastro).AsDouble := DateToDouble(TbCli.FieldByName (DtCadastro).AsDateTime); FieldByName(LimCredito).AsDouble := TbCli.FieldByName(LimCredito).AsFloat; FieldByName(NumCompras).AsInteger := TbCli.FieldByName(NumCompras).AsInteger; FieldByName(Obs).AsString := TbCli.FieldByName(Obs).AsString; FieldByName(HoraAtualizacao).AsDouble := TimeToDouble(TbCli.FieldByName (HoraUltAtualizacao).AsDateTime); Post; end; // Go to the next record TbCli.Next; PB.StepIt; end; Como na aplicao de exportao de dados para a tabela Clientes.db, temos que nos preocupar apenas com os campos tipo Date e Time do NSBasic, pois eles so gravados em formato Double. Criamos aqui duas funes DateToDouble e TimeToDouble para converter Datas e Horas do Delphi para valores Double, que podem ser recuperados pelo NSBasic. isso! Esperamos ter colaborado para facilitar seu trabalho e aprendizado na plataforma Palm. Boa sorte ! O Clube Palm acaba de lanar um Curso de Programao para Palm baseado na ferramenta PocketStudio ! Veja mais detalhes em: www.clubepalm.com.br/cursopocket1.htm

Criando arquivos PDB


Uma caracterstica muito solicitada pelos desenvolvedores era uma ferramenta capaz de criar arquivos PDB, de forma que fosse possvel facilitar a operao de envio de informaes para o

26

MeGAZINE

PERGUNTAS & RESPOSTAS

Pergunta: Como fao para destacar a fonte de uma nica linha no DBGrid quando determinado campo estiver igual a True?
Resposta: Neste caso existem duas formas para fazer essa apresentao, ambas utilizam o evento onDrawColumnCell do DBGrid. Essa primeira forma desenha uma linha vermelha dentro da clula do DBGrid, respeitando as limitaes da clula e sem mexer com a apresentao do texto, ficando o texto com a cor normal que foi definido para ele: procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if Table1.FieldByName(Paid).AsBoolean = True then begin With DBGrid1 do begin Canvas.Pen.Color := clRed; Canvas.MoveTo(Rect.Left+3, Rect.Bottom-2); Canvas.LineTo(Rect.Right-3, Rect.Bottom-2); end; end; end;

Essa segunda opo altera a fonte do texto colocando-a em vermelho e tambm definindo que a fonte tenho o Style modicado para apresentar Sublinhado. procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); begin if Table1.FieldByName(Paid).AsBoolean = True then begin With DBGrid1 do begin Canvas.Font.Color := clRed; Canvas.Font.Style := [fsUnderline]; DefaultDrawColumnCell(Rect, DataCol, Column, State); end; end; end; Faa o teste com as duas opes e veja qual fica melhor, podendo tambm unir as duas instrues, para que assim fique tambm a fonte em vermelho, mas desenhando uma linha dentro da clula, no utilizando assim o sublinhado da fonte. Dvida enviada por Eduardo, So Paulo/SP.

MeGAZINE

27

PERGUNTAS & RESPOSTAS


Pergunta: Gostaria de saber no Delphi como posso obter Fatorial de um Nmero, como por exemplo:
Fatorial(5) = 120. Resposta: O Delphi no possui nenhuma funo pronta com esta finalidade, mas possvel implementar utilizando chamadas recursivas. Veja o exemplo abaixo: function Fatorial(Valor: Integer):LongInt; begin { Verifica se o valor invlido } if Valor < 1 then raise Exception.Create(Valor invlido para ser fatorado!); if Valor = 1 then Result := 1 else { Chamada recursiva } Result := Valor * Fatorial(Valor - 1); end; procedure TForm1.BitBtn1Click(Sender: TObject); begin { Teste o valor } Edit1.Text := IntToStr(Fatorial(SpinEdit1.Value)); end; Dvida enviada por Maurcio Muller, Curitiba/PR.

repetio qualquer, tendo uma data fixa, eu fosse incrementando apenas os meses de novas datas que fossem criadas atravs do lao de repetio usando a funo IncMonth. Como posso implementar?
Resposta: Veja abaixo um simples exemplo: var NovaData: TDate; i: integer; begin for i := 1 to 12 do begin { Date indica hoje} NovaData := IncMonth(Date, i); { MostraDatas um ListBox } MostraDatas.Items.Add(DateToStr(NovaData)); end; end; Dvida enviada por Sandro F. de Brito, Goinia/GO.

Pergunta: Como posso excluir uma coluna de um DBGrid em tempo de execuo?


Resposta: Tendo as colunas adicionadas ao DBGrid, poder fazer o seguinte: procedure TForm1.BitBtn1Click(Sender: TObject); begin DBGrid1.Columns.Delete(0); end; No Delete() dever ser informado o ndice da coluna a ser deletada. Dvida enviada por Vagner Figueiredo, So Paulo/SP.

Pergunta: Estou precisando de uma ajuda, como eu fao para instalar funes externas do Interbase, exemplo no Interbase no tem a funo Subst do Oracle e eu queria saber como instalar no Interbase uma funo desse tipo e onde posso encontrar?
Resposta: O Interbase traz algumas funes externas que esto contidas em uma DLL chamada IB_UDF.DLL. Para registrar, abra o IBConsole, conecte o Banco, v ao WISQL e carregue o script ib_udf.sql que geralmente fica na pasta C:\Program Files\Borland\IntrBase\EXAMPLES\Udf. Com isso sero registradas as funes que j esto disponveis na DLL. Dvida enviada por Joo Vitor, Mogi Guau/SP.

Pergunta: Tenho um domnio:


CREATE DOMAIN BOLEANO AS VARCHAR(1) DEFAULT S Check(Value in (N, S) And (Value = Upper(Value))); Estou usando o Interbase 6.0 e Delphi 5.0. Quando vou incluir um dado em uma tabela que contem esse domnio pelo

Pergunta: Tenho um campo data em uma tabela Paradox e gostaria que a partir de um lao de

28

MeGAZINE

PERGUNTAS & RESPOSTAS


prprio Interbase, o domnio respeitado ou seja, se no coloco valor nenhum no campo ele automaticamente me retorna S, por ser Default do domnio o que correto. Mas quando vou inserir um registro por uma Query via Delphi o domnio no respeitado, ou seja, ele no coloca o valor Default S. Esse problema ocorre tambm quando coloco qualquer campo com valor Default, ignorada a imposio definida no Script da tabela, o que ocorre? Resposta: Realmente existe um problema em relao a valores defaults entre o Delphi e os bancos de dados, pois para que o banco atribua um valor default um campo, este campo DEVE chegar ao banco como NULL, porm o Delphi mata o atributo de NULL do campo e ele chega vazio ao banco, mas no NULL, por isso o banco no atribui o valor default ao mesmo. Uma alternativa seria adicionar os campos ao Fields Editor da Query e na propriedade Default Expression do campo definir o valor default ser atribudo ao campo. Dvida enviada por Mrio Fonseca, Belo Horizonte/MG.

para importar os dados em uma tabela do banco de dados SQL SERVER 2000. Lembrando que a estrutura das tabelas so diferentes e o software est sendo desenvolvido em Delphi 6.0 e ASP para Internet.
Resposta: Para exportar dados do Interbase para XML, voc poder utilizar o componente IBClientDataSet da pasta Interbase, ligando-o a tabela que voc deseja exportar e executar o seguinte: procedure TForm1.Button1Click(Sender: TObject); begin IBClientDataSet1.SaveToFile (d:\testes\gdbs\teste.xml, dfXML); end; Feito isso, o arquivo XML j ser gerado. Aps isso, poder atravs do ADO, carregar este arquivo XML e ir atribuindo campo a campo para sua tabela do SQL Server. Via Delphi, isso poder ser feito atravs do componente ADODataSet, via mtodo LoadFromFile() do mesmo. possvel gerar o arquivo XML a mo tambm, porm da um pouco de trabalho. Veja essa dica em nossa revista de Novembro de 2001, caso no possua a revista poder acessar em nosso site, www.theclub.com.br. Dvida enviada por Telveny Nascimento, Belo Horizonte/MG.

Pergunta: Gostaria de saber se h alguma forma de dimensionar a altura da DetailBand via programao, durante o carregamento do relatrio.
Tenho que imprimir uma listagem de produtos (com descrio sendo um campo memo), e alguns do apenas uma linha e outros do at 10 linhas de descrio. (Muitas vezes em toda a listagem s tem itens com a descrio pequena de uma linha), s que para no dar problema quando tiver uma descrio grande j tenho que deixar configurado com um espao excessivo. Gostaria de saber se posso via programao alterar o tamanho (altura) da DetailBand conforme o necessrio para cada item que vou imprimir. Resposta: No h necessidade de fazer o controle de altura da banda Detail a mo, pois o prprio QReport se encarrega desta tarefa. Para imprimir seu campo Memo, utilize um componente QRDBText ( o mesmo que utiliza para os demais campos ) e altere a propriedade AutoSize = FALSE e AutoStretch = TRUE e deixe o componente da largura mxima que ele poder chegar. Com isso se tiver apenas uma linha, ser impresso somente uma, caso haja mais linhas, a banda ir se redimensionar automaticamente. Dvida enviada por Eder Both, Chiapetta/RS.

Pergunta: Gostaria de saber como formatar um campo data no SQL-Server para que seja mostrado somente ms/ano, ou seja, se eu criar uma View o campo referente a data dever ser mostrado no formato ms/ano.
Resposta: Felizmente o SQL Server dispe de funes bastante poderosas de converso. Neste caso poder utilizar a funo SUBSTRING/CONVERT, como por exemplo: SELECT SUBSTRING(Convert(VarChar(10), Data, 103), 4, 7) as MESANO FROM CadData Dvida enviada por Paulo Henrique, So Jos dos Campos/SP.

Pergunta: Como fao para exportar os dados de uma tabela do banco de dados Interbase 6.0 em XML

MeGAZINE

29

PERGUNTAS & RESPOSTAS


Pergunta: Como converter uma varivel numrica para PChar()?
Resposta: Veja abaixo simples exemplo: var E: Extended; C: PChar; begin E := 1500; C := PChar(FloatToStr(E)); ShowMessage(C); end; Dvida enviada por lcio M. Cruz, So Jos do Rio Preto/SP.

Pergunta: Preciso criar um banco de dados MSAccess via programao em Delphi. Como posso proceder?
Resposta: Isso possvel utilizando uma API chamada SQLConfigDataSource() que est disponvel na ODBCCP32.DLL. Abaixo segue um exemplo de como utiliz-la:

var Form1: TForm1; { constante utilizada na API } const ODBC_ADD_DSN = 1; { declara a API fazendo referencia a DLL } function SQLConfigDataSource( hwndParent: HWND; fRequest: WORD; lpszDriver: LPCSTR; lpszAttributes: LPCSTR): BOOL; stdcall; external ODBCCP32.DLL; implementation {$R *.DFM} procedure CreateDatabase(DbName: String); begin SQLConfigDataSource(0, ODBC_ADD_DSN, Microsoft Access Driver (*.mdb), PChar (CREATE_DB= + DbName + #0)); end; procedure TForm1.Button1Click(Sender: TObject); begin if FileExists(c:\Teste.mdb) then DeleteFile(c:\Teste.mdb); try CreateDatabase(c:\Teste.mdb); ShowMessage(MDB criado com sucesso!); except ShowMessage(Problemas ao criar o MDB!); end; end; end. Dvida enviada por Altec Solues, Araras/SP.

Pergunta: Por favor, estou desenvolvendo um sistema e preciso saber qual a semana corrente, o componente TMonthCalendar me mostra o nmero da semana, mas gostaria de recuperar esse nmero automaticamente para gravar no meu BD, se esse componente no fizer isso, por favor me indiquem um que o faa.
Resposta: possvel implementar uma rotina para retornar o nmero da semana no ano, veja abaixo um exemplo: function WeekOfYear(ADate : TDateTime) : word; var day : word; month : word; year : word; FirstOfYear : TDateTime; begin DecodeDate(ADate, year, month, day); FirstOfYear := EncodeDate(year, 1, 1); Result := Trunc(ADate - FirstOfYear) div 7 + 1; end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(IntToStr(WeekOfYear(Date))); end; Dvida enviada por Ricardo Gorgueira, So Paulo/SP.

30

MeGAZINE