Dicas DELPHI

Propaganda
Outubro 2009
Outubro 2009
índice
Editorial
Delphi
InfoNews
04
Qual desenvolvedor nunca se apavorou só
com a hipótese de ter
perdido uma base de
dados do cliente? E
quando este pesadelo
se tornou realidade,
quantas horas de...
Delphi
Rapidinhas
Autor: Vitor Manuel
Rodrigues
05
Autor: Mateus André
Chies
Delphi
12
06
Sistema de contatos com mala
direta
.NET
16
20
Journaling System - A solução
definitiva contra
perda de dados parte I
Explorando Records em Delphi 2009
Herança Visual de formulários em
Windows Forms
Autor: Felipe Santos
Autor: Antonio Spitaleri
Autor: Luciano Pimenta
.NET
Dicas Delphi
26
Acesso a dados com JQuery
Autor: Djonatas Tenfen
29
- Alterar propriedade buttonstyle
das toolbars ligadas ao actionmanager em tempo
de execução:
- Criando uma...
Desafio The Club
- Sudoku
Legenda
30
Iniciante
Intermediário
Avançado
Outubro 2009
03
Bem-vindo
Olá amigos
Qual desenvolvedor nunca se apavorou só com a hipótese de ter perdido
uma base de dados do cliente? E quando este pesadelo se tornou realidade, quantas horas de trabalho e às vezes até de sono formam perdidas,
muitas vezes sem sucesso, tentando recuperar os precisos dados de nosso
cliente. Assim neste mês em nossa matéria de capa “Journaling System – A
solução definitiva contra perda de dados”, Felipe Santos aborda no caso
de falhas ambientais que possam corromper nossos banco de dados, a
prevenção, recuperação e restauração do banco de dados Interbase o uso
da tecnologia Journaling System.
Nosso consultor Antonio Spitaleri com seu artigo “Explorando Records em
Delphi 2009”, dá uma aula conceitual sobre as estruturas do tipo records,
discutindo desde detalhes técnicos de sua criação e alocação de memória
até comparações com o uso de classes.
Av. Profº Celso Ferreira da Silva, 190
Jd. Europa - Avaré - SP - CEP 18.707-150
Informações: (14) 3732-1529
Suporte: (14) 3733-1588
Internet
http://www.theclub.com.br
Cadastro: [email protected]
Suporte: [email protected]
Informações: [email protected]
Skype Cadastro: theclub_cadastro
Skype Suporte: theclub_linha1
theclub_linha2
theclub_linha3
www.twitter.com/theclubbr
Agora para os programadores iniciantes que sempre pedem projetos
de exemplo, algo que possam trazer para o mundo real, o nosso colunista
Mateus André Chies, criou um projeto de exemplo que se transformou no
artigo “Sistema de contatos com mala direta”, neste artigo Mateus mostra,
posso a posso, desde a criação do banco de dados ate a configuração dos
componentes, além é claro de como criar uma solução para organizar
nossos contatos.
Copyright The Club Megazine 2009
E nossa sessão .Net Luciano Pimenta mostras uma técnica muita
usado pelos programadores Delphi agora em .net, que é o uso do conceito de Herança da Programação Orientada a Objetos (POO), para o
reaproveitamento de formulários com características semelhantes como
é o caso de formulários de cadastro, neste seu artigo “Herança Visual de
formulários em Windows foms”, Luciano dá uma ótima contribuição para
os programadores novatos em .Net que pretendem iniciar novos projetos
com herança visual.
Revisão
Tassiane Fileto
Também em nossa sessão .Net temos também o artigo “Acesso a dados com JQuery” de nosso colunista Djonata Tenfen, que segue na sua
seqüência de artigos abordando a tecnologia JQuery.
Diretor Técnico
Marcos César Silva
Diagramação e Arte
Vitor M. Rodrigues
Colunistas
Antonio Spitaleri Neto
Djonatas Tenfen
Felipe Santos
Luciano Pimenta
Mateus André Chies
Vitor M. Rodrigues
Impressão e acabamento:
GRIL - Gráfica e Editora
Taquarituba-SP - Tel. (14) 3762-1345
Reprodução
Boa leitura e até o próximo mês, abraço a todos.
Marcos César Silva - Editor Chefe
[email protected]
04
Outubro 2009
A utilização, reprodução, apropriação, armazenamento em banco
de dados, sob qualquer forma ou meio, de textos, fotos e outras
criações intelectuais em cada publicação da revista “The Club
Megazine” são terminantemente proibidos sem autorização
escrita dos titulares dos direitos autorais.
Delphi é marca registrada da Borland International,
as demais marcas citadas são registradas
pelos seus respectivos proprietários.
InfoNews
Rapidinhas
Nota Fiscal Eletrônica
A vilã do momento é a NFe. Alguns já estão utilizando, outros estão implantando e muitos ainda terão de implantar.
A dica é simples, não deixe para última hora, se o seu
sistema não está integrado com a NFe, e se nenhum cliente
solicitou essa é hora de correr atrás. Os contadores estão
avisando os empresários em cima da hora sobre a obrigatoriedade de implantação da NFe, e ainda estão jogando toda
a responsabilidade em cima dos desenvolvedores, tirando
o corpo fora da questão. E como já bem sabemos, para o
cliente “tudo é fácil, é só um botãozinho”, e sabemos que a
coisa não é assim.
Delphi no Windows 7
Estamos testando já há algum tempo o Delphi no
Windows 7 e os resultados são positivos, ele se mostra um
sistema estável, ágil e segundo nossos técnicos está rodando
o Delphi sem problema. Diferente do que acontece no
Windows Vista. Portanto se alguém ainda estava com medo
de instalar o Windows 7, pode rodar sem medo.
Então se prepare, já avise seus clientes sobre como será
o processo de implantação, custos adicionais e informações
sobre a NFe.
1º Delphi Conference
Corre a informação de que a Embarcadero promoverá um
encontro para os desenvolvedores Delphi será o “1º Delphi
Conference”, até o fechamento desta edição ainda não havia
sido divulgado data nem local, o que se sabe é que será no
mês de novembro de 2009 e que tem vários nomes de peso
para apresentação das palestras. Então se prepare, pois esse
evento promete muito.
Outubro 2009
05
Delphi
Sistema de
Contatos
com
Mala Direta
Listagem 1: Criação do Banco de Dados
Neste artigo irei demonstrar uma maneira fácil e útil de se armazenar os contatos
dos cartões pessoais que recebemos de
empresa e pessoas. Muitas vezes guardamos
em gavetas, onde muitos são extraviados, ou
os mais organizados compram porta cartões
para guardar os cartões de visitas.
Criando o Banco de Dados
Vamos lá, a base do sistema será em banco
de dados Firebird 1.5, utilizando Delphi 2007 para
o desenvolvimento, vamos modelar conforme
a listagem 1, onde temos a criação e definição
do GENERATOR, posteriormente temos a tabela
e seus atributos com seus respectivos tipos de
dados, ainda temos a criação da chave primária e
do gatilho que é acionado no evento de Inserir os
dados na tabela.
06
Outubro 2009
****Generated by
IBExpert****/
SET SQL DIALECT 3;
SET NAMES NONE;
SET CLIENTLIB ‘fbclient.
dll’;
CREATE DATABASE
‘127.0.0.1:C:\BANCO\
CONTATOS.FDB’
USER ‘SYSDBA’ PASSWORD
‘masterkey’
PAGE_SIZE 4096
DEFAULT CHARACTER SET NONE;
/****Generators****/
CREATE GENERATOR GEN_
CONTATOS_ID;
SET GENERATOR GEN_CONTATOS_
ID TO 8;
/****Tables****/
CREATE TABLE CONTATOS (
CODIGO
INTEGER NOT
NULL,
NOME
VARCHAR(100),
ENDERECO
VARCHAR(200),
NUMERO
BAIRRRO
CEP
CIDADE
UF
FONE
FAX
CELULAR
EMAIL
SITE
VARCHAR(250),
INTEGER,
VARCHAR(30),
VARCHAR(9),
VARCHAR(60),
VARCHAR(2),
VARCHAR(13),
VARCHAR(13),
VARCHAR(13),
VARCHAR(75),
ATIVIDADE VARCHAR(200)
);
/****Primary Keys****/
ALTER TABLE CONTATOS ADD
CONSTRAINT PK_CONTATOS
PRIMARY KEY (CODIGO);
/****Triggers for
tables****/
CREATE TRIGGER CONTATOS_BI
FOR CONTATOS
ACTIVE BEFORE INSERT
POSITION 0
AS
BEGIN
IF (NEW.CODIGO IS NULL)
THEN
NEW.CODIGO = GEN_
ID(GEN_CONTATOS_ID,1);
END
^
SET TERM ; ^
Construindo nossa aplicação
Crie uma nova aplicação no Delphi 2007
através do menu File, New, VCL Forms Application, defina o width para 850 e o Heigth para 456
junto a palheta Object Inspector, agora salve sua
aplicação utilizando a teclas de atalho Ctrl + Shift
+ S, para o .pas salve com uPrincipal, e para o
projeto Contatos. Vamos começar montar o Layout
da nossa aplicação, adicione 2 TPanel da palheta
Standart da aba Tool Palete, remova o caption
das duas Panel, e para uma defina a propriedade
Align para alTop e a outra para alBottom, adicione
um componente TPageControl da paleta Win32
e defina a propriedade Align para alClient, clique
no centro PageControl e adicione duas páginas,
clicando de direita e acessando o menu New Page,
para a primeira altere o caption para “Contatos” e
a segunda para “Dados”.
Adicione um componente Tlabel da paleta
Standart no panel superior, e defina a fonte através
da propriedade Font da paleta object Inspector
para tamanho 16pt, e estilo da fonte para negrito
e altero o Caption para “Lista de Contatos”.
Selecione a página de contatos e adicione
uma Tpanel, remova o caption e altere o align para
alTop, adicione 4 Tlabel, 1 TEdit e mais um BitBtn
da paleta Additional, altere o align do BitBtn para
alRigth e o caption para “Imprimir Mala Direta”,
para o primeiro label altere o caption para “Dados
da Consulta:”, posicione o Edit logo abaixo do primeiro label, e altere o name para “edt_consulta”,
posicione a segunda label logo abaixo do Edit e
altere o caption para “Consultando por:”, posicione
o terceiro label logo a direta o label anterior, altere
o caption para “Selecione uma coluna clicando no
título”, o name para “lbl_consulta” e a Font para cor
vermelho, e estilo para negrito. Posicione o quarto
label para próximo ao BitBtn de Imprimir, altere o
name para “lbl_total”, nesse label vamos mostrar
o total de registros. No centro dessa página vamos
adicionar um TDbGrid da paleta Data Controls, e
altere o align para alClient.
Muito bem, agora vamos configurar nossa
conexão, adicione um TsqlConnection da paleta
dbExpress, altere o name para “CON”, altere a
propriedade LoginPrompt para “False”, e depois
configure a conexão com o banco de dados
criado. Adicione TSQLDataSet da mesma paleta,
altera a propriedade name para “SQL”, configure
o SQLConnection para “CON”, e na propriedade
CommandText adicione o código da listagem 2, que
é a instrução SQL para selecionarmos os dados do
bando de dados criado.
Listagem 2: Command Text
select * from CONTATOS
Feito essas configurações, vamos adicionar
os campos no nosso SQL, duplo clique sobre o
componente abrira uma janela, nessa janela clique
de direita e acione o menu Add All Fields, agora é
possível visualizar todos os campos da nossa tabela
no banco de dados, selecione o campo CODIGO,
acesse a propriedade ProviderFlags, pfInKey e
altera para “true”, nosso SQL está pronto.
Agora adicione um TDataSetProvider da
paleta Data Access, altere o name para “DSP” e
configure o DataSet para “SQL”. Também adicione
um TClientDataSet, altere o name para “CDS”,
relacione a propriedade ProviderName com o DSP,
duplo clique sobre ele e botão direito do mouse,
Add All Fields, agora já temos todos os campos no
nosso CDS, selecionando um campo de cada vez
é possível altera a propriedade DisplayLabel para
o Label que você deseja que aparece na DbGrid e
junto aos campos, mas tome cuidado, não altere a
propriedade FieldName. Agora ative o nosso CDS.
E por último adicione um TDataSource da paleta
DataAccess, altere o name para “DS” e configure
a propriedade DataSet para “CDS”.
Agora basta ligar a propriedade DataSource da
DBGrid com o nosso DataSouce DS e já é possível
visualizar os nosso campos na DBGrid.
Vamos automatizar nosso operações, adicione
um componente TImageList da paleta Win32, duplo
clique sobre ele e através do botão Add adicione
uma imagem relacionada a cada uma das seguintes
operações Inserir, Editar, Cancelar, Salvar e Excluir.
Mais tarde iremos utilizar essas imagens, para
fins visuais.
Adicione um componente TActionList da paleta
Standart, relacione a propriedade Images a nossa
Lista de Imagens TImageList1. Através dessa lista
de ações é que vamos acionar nossas transações
com o banco de dados. Duplo clique sobre o
Outubro 2009
07
componente, abrirá uma nova janela, acesse New
Standart Action, vamos adicionar as nossa ações,
abrirá uma nova janela, role até encontrar o nó
Dataset, com a tecla Ctrl pressionada selecione os
seguintes itens, TDataSetInsert, TDataSetDelete,
TDataSetEdit, TDataSetPoste e TDataSetCancel,
clique em Ok.
Agora temos a lista das nossas ações, selecione DataSetInsert1 altere o caption para Inserir,
relacione a propriedade DataSource ao DS, altere
a propriedade Hint para Inserir e na propriedade
ImageIndex selecione a imagem relacionada ao
Inserir, agora basta repetir essas configurações para
as demais ações, adequando-as as suas respectivas
funcionalidade, nome e imagem.
Figura 1: Formulário
Adicione 5 TBitBtn na panel inferior, configure todos com Width 100 e heigth para 47, e
respectivamente da esquerda para direta, altera a
propriedade Action para as ações da lista de ações
para Inserir, Editar, Cancelar, Salvar e Excluir. Salve
o projeto. Ainda nessa panel inferior adicione um
componente TDBNavigator, relacione o DataSource
ao DS, e na propriedade VisibleButtons configure
para true apenas os botões First, Prior, Next e
Last, que são Primeiro, Anterior, Próximo e Último
respectivamente, os demais altere para false. O
formulário ficou similar a figura 1.
Veja a Figura 1: Formulário
Figura 2: Campos
Selecione o PageControl e clique na aba Dados, agora vamos adicionar os campos ao formulário, duplo clique sobre o CDS e selecione todos
os campos, e os arraste
para o formulário e organize
a disposição conforme a
figura 2.
Veja a Figura 2: Campos
Mas você deve estar
se perguntado, - Mas não
vamos programar nada?
Calma, vamos agora fazer as
implementações. Selecione o
Form acesse o evento FormShow e vamos abrir
nosso CDS, forçar a sempre abrir com o PageControl na página, que tem o DBGrid e adicionar a label lbl_total o total e registro que tem selecionado
no DBGrid, implementado a listagem 3.
08
Outubro 2009
Listagem 3: FormShow
DS.DataSet.Open;
PageControl1.ActivePage
:= TabSheet1;
PageControl1.
ActivePageIndex := 0;
lbl_total.Caption :=
IntToStr(cds.RecordCount)+’
Regsitro(s)’;
Selecione o ClientDataSet, no evento AfterPost, implemente a codificação da listagem 4, e
no evento AfterDelete relacione com o evento
AfterPost, essa implementação tem a função de
grava no banco de dados cada vez que se aciona o
botão Salvar ou Excluir.
Listagem 4: AfterPost
CDS.ApplyUpdates(0);
CDS.Close;
CDS.Open;
Vamos fazer as implementações na DBGrid,
no evento DblClick apenas codifique para acionar
o botão de alterar, para quando estiver navegando
sobre os registros e der duplo clique nele automaticamente entrará em modo de edição. Ainda na
DBGrid no evento TitleClick, vamos implementar a
listagem 5, para índex os dados pela coluna que foi
selecionada, ainda preencher a lbl_consulta com o
nome do campo selecionado, que servirá no filtro
das informações.
Listagem 5: TitleClick
try
(DS.DataSet as
TClientDataSet).
IndexFieldNames := Column.
FieldName;
lbl_consulta.Caption
:= Column.FieldName;
edt_consulta.SetFocus;
except
ShowMessage(‘Essa
coluna não pode ser
ordena!!!’);
end;
Selecione o TEdit edt_consulta e vamos programar nossa consultas personalizadas, que sempre
que o algo é alterado em um TEdit é acionado
o evento Change, utilizaremos esse evento para
aplicar nosso filtros. Conforme Listagem 6.
Listagem 6: Filtros
try
if edt_consulta.Text
<> ‘’ then //Verifica se o
campo não etsa vazio
begin
cds.Filtered :=
False; //Desativa o filtro
CDS.Filter :=
lbl_consulta.Caption+’
like ‘’%’+edt_consulta.
Text+’%’’’;// Mosta o
filtro
// que sempre que
encontrar algo na
coluna do DbGrid que foi
selecionado
cds.Filtered := True;
//Aplica o filtro
lbl_total.Caption :=
IntToStr(cds.RecordCount)+’
Regsitro(s)’;//Conta quanot
regisro tens filtrado
end
else
begin
cds.Filtered :=
False; //Desativa o filtro
lbl_total.Caption :=
IntToStr(cds.RecordCount)+’
Regsitro(s)’;//Conta quanot
regisro tens filtrado
end;
except
ShowMessage(‘A
consulta não pode ser
realizada!!!’+#13+’Selecione
uma coluna na grade.’);
end;
Agora vamos programar os nosso controles
entre as abas do PageControl, esse controles
serão implementados no evento StateChange do
DataSource, DS. Sempre que o DS estiver em modo
de Insert ou Edit vamos ativar a aba Dados e jogar
o foco para o primeiro campo, caso contrário,
voltamos o foco para a aba Contatos. Conforme
a listagem 7.
Listagem 7: StateChange
if DS.DataSet.State in
[dsEdit,dsInsert] Then
begin
PageControl1.ActivePage
:= TabSheet2;
PageControl1.
ActivePageIndex := 1;
TabSheet1.Enabled :=
False;
TabSheet2.Enabled :=
True;
DBEdit2.SetFocus;
end
else
begin
PageControl1.ActivePage
:= TabSheet1;
PageControl1.
ActivePageIndex := 0;
TabSheet1.Enabled :=
True;
TabSheet2.Enabled :=
False;
end;
Feito todas essas implementações, basta compilar e começar a inserir, alterar e excluir os dados
do nosso banco de dados.
Vamos montar nossas etiquetas de Mala Direta
dos nossos contatos, através do RaveReports, adicione um componente TRvProject altere o name
para “RVREL”, adicione um TRvSystem e altere o
name para RVSYS, relacione o componente RVREL
na propriedade Engine com o “RVSYS”, e por último
adicione um componente TRvDataSetConnection
altere o name para “RVDSCDS”, na propriedade
DataSet selecione o ClientDataSet “CDS”. Salve o
projeto e de um duplo clique sobre o RVREL, o
Rave abrira.
Já com o RaveReports aberto, salve o projeto
com o nome de ETIQUETAS.rav, agora acesse o
menu File – New Data Object, selecione Direct
Data View, Next, aparece o componente RVDSCDS,
selecione e Finish. Agora já temos uma conexão do
RaveReposts com a nossa aplicação, que se conecta
com o banco de dados.
Agora adicione um DataView1Region, configure do tamanho útil da página, adicione um
Outubro 2009
09
DataView1DataBand relacione a propriedade
DataView com a DataView1, altere o Heigth para
0,800 e ainda altere a propriedade Columms para
2, dessa maneira o relatório será gerado em duas
colunas. Agora vamos adicionar nossos campos.
Pressionando a tecla Ctrl selecione os campos
NOME, ENDERECO, NUMERO, BAIRRO, CIDADE,
CEP e UF, arraste para dentro da DataBand e os
disponha conforme a figura 3. Pressione F9 e reja
o resultado do relatório, não esqueça que é necessário já ter dados cadastrados para poder melhor
visualizar, salve o projeto.
Figura 3. Relatório
Veja a Figura 3. Relatório
De volta no Delphi, selecione o componente
RVREL, e na propriedade ProjectFile selecione o
arquivo ETIQUETAS.rav, e no botão de Imprimir
Mala Direta vamos acionar o relatório, conforme
Figura 4: Resultado Final
listagem 8, conforme os dados filtrados na DBGrid,
então dessa maneira quando quiser imprimir etiquetas para determinados registros, basta filtrar
na DBgrid e imprimir.
as etiquetas automaticamente. Veja resultado na
figura 4.
Veja a Figura 4: Resultado Final
Listagem 8. Imprimir
Conclusão
RVREL.Open;
RVREL.SelectReport(‘Etiqu
etas’,False);
RVREL.Execute;
Assim chegamos ao fim, agora basta executarmos o sistema, cadastrar vários registros e imprimir
O principal objetivo desse artigo e apresentar
uma solução para organizar os cartões pessoais
que guardamos, geralmente organizadamente,
agora têm sempre a mão, basta acessar o sistema
e consultar, quando desejar encontrar alguém que
atue em determinada atividade, ou ramo. E ainda
de forma automatizada pode se gerar etiquetas
para enviar Mala Direta.
Sobre o autor
Mateus André Chies
Técnico em Informática, bacharelando em Sistemas de Informação.
[email protected]
10
Outubro 2009
Outubro 2009
11
Olá pessoal,
Esse mês quero apresentar a vocês uma
tecnologia realmente revolucionária da família de bancos de dados InterBase – o Sistema
Journaling. Uma maneira definitiva de prevenir, recuperar e restaurar ambientes inteiros
em caso de corrupção, perda e até mesmo
desastres contra nossos bancos de dados.
Que atire a primeira pedra quem nunca passou por algum problema de corrupção de bancos
de dados InterBase/Firebird? Ou mesmo outro
SGDB? Noites e noites mal dormidas, recuperando
bases de dados com validações, backups, restores
ou mesmo com procedimentos ultra-sofisticados,
como pumps de tabelas, extração de scripts e
inserções manuais. E não estou falando apenas
de grandes empresas, grandes bancos de dados.
Os pequenos consumidores de bancos de dados
sofrem também com dias ou mesmo meses de
dados perdidos por conta de uma corrupção.
Então poderíamos pensar: O InterBase/Firebird não oferece segurança alguma! Precisamos de
um gerenciador mais moderno, mais robusto!
É certo e comprovado que a grande maioria
12
Outubro 2009
dos problemas de corrupção de bancos de dados
está relacionada à infra-estrutura. Seja por conta
de falhas de discos, memória, gerenciamento de
Sistemas Operacionais, panes elétricas, enfim.
E por mais que possamos investir uma pequena
fortuna preparando ambientes extremamente
seguros, estaremos sempre sujeitos a esse tipo
de problema.
Mas sim, cabe ao gerenciador de banco de
dados oferecerem uma solução, uma opção mais
segura aos seus usuários.
E é nesse ponto que entra o Sistema Journaling. Uma alternativa para aumentar significativamente a seguranças de nossos ambientes e,
em especial, nossos bancos de dados, com baixo
investimento. Pois só quem perdeu sabe dizer
quanto custa um dia de trabalho perdido. E apesar
de ser revolucionário, o Sistema Journaling não é
tão recente assim. Está disponível nos bancos de
dados InterBase desde sua versão 2007, lançado
há quase 3 anos.
Vamos durante esse artigo, que também dividiremos em duas partes, mostrar a fundo como
funciona e como aplicar o Sistema Journaling na
prática.
JOURNALING SYSTEM
Pois bem, o Sistema Journaling é uma tecnologia embarcada no gerenciador de banco de dados
InterBase que cria um ambiente para prevenção
e recuperação possíveis falhas nos bancos de dados, causadas, como disse anteriormente, quase
sempre devido à falhas de ambiente. Para o seu
melhor funcionamento, o Sistema Journaling atua
em duas partes. A recuperação de curto tempo,
também conhecida como Short-Term-Recovery,
e a recuperação de longo tempo – o Long-TermRecovery. Vamos então entender e estudar suas
principais características e aplicações.
SHORT-TERM-RECOVERY
Vejam como a idéia é bem simples. Ao ativar
o Sistema Journaling, o InterBase irá desativar (se
assim estiver configurado) a opção Forced Writes
do banco de dados, forçando assim a gravação assíncrona dos dados. Então o Sistema Journaling irá
utilizar um espaço em disco, indicado por nós, para
armazenar em tempo real todas as informações,
todo o conteúdo de todas as transações aplicadas
sobre o banco de dados, em arquivos chamados
Journal Files. Sim, todas as transações e seus
Inserts, Updates, Deletes, Creates, Drops, Alters e
etc., antes de serem aplicadas no banco de dados,
seus conteúdos serão gravados nos Journal Files.
Independentemente se essas transações serão
depois confirmadas (comitts) ou canceladas (rollbacks). E para que? Mais simples ainda! Em caso
de qualquer parada inesperada de sistema, como
um pique de energia, um restart abrupto do servidor, uma queda do serviço que seja, o InterBase
e o Sistema de Journaling irá, automaticamente,
aplicar no banco de dados, o conteúdo das transações que estavam “no ar” no momento da pane,
recuperando as informações que estavam sendo
gravadas, atualizadas ou excluídas, garantindo
assim a integridade do banco de dados. E são essas
pequenas paradas, pequenas falhas que, em pouco
tempo, tornam nosso banco de dados tão corrompido que sua recuperação se torna um verdadeiro
desafio. Abaixo trago dois links importantes que
tratam sobre as principais causas de corrupção de
bancos de dados:
esse disco não seja o mesmo disco onde está localizado o banco de dados de produção. Podemos
então separar um novo disco, ligado ao mesmo
computador, mas que esteja conectado à outra
controladora, ou, de preferência, um outro disco
ligado a outro computador, conectado ao nosso
servidor InterBase através de uma conexão de
rede estável e segura. Essa escolha é fundamental
para que o Sistema Journaling não comprometa o
desempenho de nosso ambiente.
Por ser algo novo, algo que nosso banco
de dados não possui hoje, para ativar o sistema
de Journal precisamos programar uma parada
extremamente rápida do banco de dados que
desejamos aplicar. É importante salientar que essa
parada acontecerá apenas uma única vez. Então,
uma vez que estamos com o banco exclusivo para
nós, podemos utilizar comandos DDL ou mesmo o
utilitário IBConsole para criação do Journal.
http://edn.embarcadero.com/article/29515
h t t p : / / w w w. i b p h o e n i x . c o m / m a i n .
nfs?a=ibphoenix&page=ibp_err_problem
Mas se iremos gravar e criar arquivos Journal
concorrendo com nosso banco de dados que está
em produção, isso não irá trazer perda de performance? Não se criarmos de maneira correta.
CRIANDO O SISTEMA JOURNAL
Relembrando: o Sistema Journaling irá utilizar
um espaço em disco indicado para criação de
arquivos de Journal. Está aqui um ponto chave
do processo. Definir esse espaço. Antes mesmo
de começar a trabalhar, precisamos definir uma
unidade, um disco onde serão criados os arquivos
de Journal (Journal Files). E é imprescindível que
Segue abaixo um exemplo de comando para
essa criação:
CREATE JOURNAL ‘d:\
databases\journal\employee\
emp’
LENGTH 65000
CHECKPOINT LENGTH 10000
CHECKPOINT INTERVAL 120
PAGE SIZE 8192
PAGE CACHE 2500
PREALLOCATE 325000
TIMESTAMP NAME Enabled;
•
O comando Create Journal é seguido
de um caminho. Esse caminho indica o local onde
serão gravados, gerados os arquivos Journal Files.
No caso de nosso exemplo, esse caminho é o D:\
databases\Journal\Employee. Na sequência apara
a palavra Emp. Essa palavra servirá como prefixo
aos nomes dos arquivos que serão gerados nessa
pasta.
•
O LENGTH (65000) define a geração
de um novo arquivo de journal a cada 500MB
(65000x8kb). O LENGTH default 500 gera um novo
arquivo a cada 8MB. O tamanho de cada arquivo
de journal vai depender do tamanho do banco de
dados. É claro que se os arquivos de journal forem
muito pequenos, mais arquivos serão gerados, o
que pode gerar um problema de performance. Uma
dica para definir o tamanho dos arquivos Journal é
medir quanto cresce seu banco de dados por dia.
Quanto maior for o crescimento/dia de seu banco,
maior também deve ser o tamanho de cada Journal
File. Pessoalmente não indico que seja inferior a
100 Mb.
•
O CHECKPOINT LENGTH em 10000
significa que o checkpoint do banco irá ocorrer a
cada 80MB (10000x8k). O CHECKPOINT LENGTH
default é 500, isso significa uma checagem a cada
4M (500x8k). Este parâmetro é muito particular,
pois define o número de bytes que será aplicado
no banco após um crash do servidor e influenciará
no tempo da recuperação automática em caso de
pane. Sua definição dependerá se o Journal está
sendo criado no mesmo servidor ou em outro, se
local ou remoto.
•
O CHECKPOINT INTERVAL é semelhante
ao parâmetro anterior, porém determina o checkpoint em segundos e não em páginas. Você pode
escolher uma das duas opções. Se as duas opções
estiverem marcadas, o InterBase validará a que
acontecer primeiro.
Outubro 2009
13
•
O PAGE SIZE determina o tamanho da
página interna de gravação dos arquivos de Journal, semelhando ao pagesize do próprio banco de
dados. O valor desse parâmetro deve ser sempre
o dobro do tamanho do pagesize do banco de
dados.
•
O PAGE CACHE determina o número
de páginas de Journal que serão armazenadas em
cache. Esse parâmetro também é muito importante, pois um cache pequeno pode ser tornar um
problema de performance.
•
O PREALLOCATE é a opção que temos
de pré-alocar um espaço no disco de Journal. Basta
multiplicar quantos arquivos de Journal desejamos
pré-criar e multiplicar pelo valor indicado na opção
LENGTH. Nesse exemplo iremos pré-alocar 5 arquivos de 500 Mb. Esse parâmetro é especialmente
particular se o disco reservado para Journal também for utilizado por algum outro processo, evitando que acabe o espaço em disco inesperadamente.
Quando esses cinco arquivos forem totalmente
preenchidos, então novos arquivos serão criados
um a um.
Imagem 1 – Caminho para o Menu de criação do Sistema Journal
•
E por fim o TIMESTAMP NAME Enable
indica que os arquivos de Journal terão em seu
nome uma gravação indicando o dia/mês/ano/
hora/minuto e segundo em que foram criados.
Podemos também utilizar o utilitário IBConsole
para realizar essa ativação do Sistema Journal:
Veja a Imagem 1.
Imagem 3 – Visualização do diretório onde foram gerados os Journal Files
Imagem 2 – Tela para configuração dos parâmetros
de ativação do Sistema Journaling
Veja a Imagem 3.
Logo após a criação do Journal, seu ambiente
já poderá ser liberado para uso e, assim, instan14
Outubro 2009
taneamente, seus Journal Files começaram a ser
utilizados. No exemplo acima podemos verificar
que no diretório reservado foi criado:
•
Um arquivo chamado IB_JOURNAL, que
será o responsável pelo gerenciamento o sistema
Journal,
•
Um arquivo chamado EX.2009-1005T23-02-20Z.1.JOURNAL que é nosso primeiro
Journal File já criado com o tamanho determinado
no passo anterior.
•
5
a r q u i v o s
EX.PREALLOCATED.X.JOURNAL que são os cinco
arquivos que já deixamos pré-alocados. Quando o
Sistema Journal começar a utilizar esses arquivos,
os mesmo serão automaticamente renomeados
para o padrão do primeiro arquivo.
Agora, e daqui para frente, todas as transações desse banco de dados irão alimentar nossos
arquivos de Journal.
Em caso de uma eventual falha o Sistema Journal irá executar o processo de Short-Term-Recovery
Imagem 4 – Arquivo InterBase.Log contendo um trecho onde o Sistema Journaling foi utilizado.
para aplicar as últimas transações que foram perdidas no processo. A imagem abaixo mostra trecho
do arquivo de Log do InterBase (Interbase.Log)
que exibe o momento em que o Sistema Journal
realizou a recuperação de curto tempo:
Veja a Imagem 4.
São apenas três passos: 1 - Iniciando o processo. 2 - Aplicando o Journal File e 3 - Encerrando o
processo. Simples, rápido e seguro.
Dessa forma fechamos a implementação da
primeira etapa do Sistema de Journal. Só com esse
procedimento já aumentamos significativamente
a segurança de nossos bancos de dados, independentemente se seu porte.
A segunda etapa consiste na criação de um
ambiente para o arquivamento dos arquivos de
Journal e do banco de dados. Mas esse é um
assunto para nossa segunda parte do artigo, no
próximo mês. Não percam!!!
CONCLUSÃO
zando todos os tipo de recursos. E tudo isso sem
precisar investir em sofisticadas plataformas de
infra-estrutura, como Storages, diversos servidores,
espelhamento de discos, etc. Basta um HD a mais
e uns minutinhos para ativação. Se você já utiliza o
InterBase versão 2007 ou superior, não perca mais
tempo e comece já a utilizar esse fabuloso recurso.
Se você é usuário InterBase versões anteriores ou
Firebird, experimente, teste esse recurso baixando
uma cópia de avaliação do produto. Lembrando
sempre que, se você é desenvolvedor utilize a
versão Developer Edition do InterBase SMP 2009,
disponível gratuitamente no site da Embarcadero
(http://www.embarcadero.com) . Essa versão permite o uso dos completos recursos de Journal. Vale
lembrar também que o Sistema Journaling não está
disponível nas versões Desktop e To-Go Edition do
InterBase, por se tratar de versões voltadas para
aplicações locais, sem acesso via rede, que dispensa
esse tipo de segurança adicional.
No próximo artigo voltaremos para mostrar
com detalhes de como tornar seu Sistema Journaling muito mais poderoso com o sistema de Archiving, completando assim sua solução definitiva
contra perda de dados. Está imperdível! Até lá.
Referência:
É fácil perceber o quanto o Sistema de
InterBase 2009 Operations Guide – cap. 9.
Journaling passa a ser fundamental para
nossos ambientes. Se você é desenvolvedor, imagine o nível de
segurança que você pode
oferecer aos seus clientes,
dos pequenos aos granFelipe Santos
Felipe Santos é especialista em InterBase. Trabalha com o InterBase desde
des. Se você é usuário de
2001. atuando como consultor e instrutor do produto em todo Brasil. Especialista em
ambientes críticos. Atua e trabalha com os maiores clientes do InterBase no Brasil.
InterBase/Firebird, pense
Participante ativo na comunidade, com diversos artigos publicados. Participante do
o quanto esse simples
grupo de beta testers mundial do produto. Palestrante em eventos como IB Tour, Borcon
Conference, CodeRage Latin América, Delphi Developers Day, Linux Day, entre outros.
procedimento pode
Atualmente trabalhando na área técnica do InterBase na Presence Tecnologia – agente
oficial especializado do produto no Brasil.
te ajudar a diminuir
[email protected]
e muito o seu tempo
de parada, economi-
Sobre o autor
Outubro 2009
15
Explorando
Records em
Delphi 2009
Os programadores Delphi, mesmo
aqueles sem muita experiência, já conhecem
ou pelo menos ouviram falar de records ou
estruturas nessa linguagem.
Records são tipos de dados criados pelo
programador, conceito similar ao de classes,
porém records contém apenas atributos e
classes contém além desses os famosos métodos que manipulam os atributos.
Essa é a diferença mais superficial, digamos
assim, além disso, existe outro fator importante a
ser considerado quando trabalhamos com records
e classes, que é a forma de alocação em memória
pelo compilador de cada um.
Existem dois tipos de alocação: Estática e
dinâmica. A primeira é a alocação utilizada para variáveis, sejam elas globais ou locais e para os nossos
records. No caso de alocação estática o programa
utiliza uma área de memória conhecida com pilha,
16
Outubro 2009
onde as variáveis ficam até que a função onde foram declaradas acabe (no caso das variáveis locais)
ou até que o programa seja encerrado (no caso de
variáveis globais). O conceito de pilha é justamente
o que nos vem à mente quando pensamos na palavra: Uma sequência de objetos dispostos um sobre
o outro onde o primeiro a entrar é o primeiro a sair.
Esse conceito fica ainda mais claro se imaginarmos
a seguinte situação em um aplicativo:
Temos a variável global nomeuser que é
solicitada ao usuário quando da abertura do
aplicativo.
Temos a função soma que utiliza as variáveis
locais num1 e num2 que realizam uma soma
comum.
É fácil visualizar o seguinte, assim que o aplicativo é iniciado a variável nomeuser é alocada na
pilha, depois com a chamada da função as variáveis
num1 e num2 são alocadas também. Assim que a
função termina, o programa destrói as variáveis
num1 e num2 que foram as últimas a entrar e,
portanto primeiras a sair. A variável nomeuser
que foi alocada primeiro será liberada por último,
quando o aplicativo for encerrado.
Alocação dinâmica é utilizada por arrays não
dimensionados e classes. Nesse tipo de alocação,
o programa cria um ponteiro para um espaço de
memória contido em uma área chamada “heap”.
Quando trabalhamos com alocação dinâmica
precisamos criar o espaço e liberá-lo depois de
utilizado. Um exemplo é a criação de formulários
em Delphi. Veja o código:
Try
Form1:=tform1.
create(self);
Form1.showmodal;
Finally
Freeandnil(form1);
End;
Nessa sequência, criamos o objeto e consequentemente o espaço em memória para form1
e depois liberamos o espaço e o ponteiro que
referenciava esse espaço com freeandnil. Essa
técnica é utilizada em Delphi com a grande maioria
das classes.
Já foi possível perceber que além da diferença
inicial, records e classes são alocados de forma
diferente. Records de forma estática e classes de
forma dinâmica.
Por serem alocados de forma estática, records
podem ser passados com parâmetros de funções
e pode servir de valor de retorno, o que não se faz
possível com classes.
Além disso, a partir do Delphi 2006, é possível
inserir métodos em records, o que pode ser muito
útil em alguns casos. Nesse artigo estarei falando
um sobre como podemos explorar melhor os records no Delphi 2009.
De início criaremos dois records: um para ser
passado para a função e outro para permitir que a
função retorne os três valores desejados:
Type
DadosEntrada=Record
Nomeusuário:string;
Senha:string;
End;
Type
DadosRetorno=Record
Usuariologado:string;
Codigousuario:integer;
Nível:string;
End;
Records e Funções
Em determinadas situações, precisamos passar
vários valores para uma função ou fazer com que
alguma função retorne um conjunto de valores.
Uma alternativa nesses casos é utilizar arrays,
porém podemos também fazer uso de records, o
que impede que passemos ou retornemos arrays
de tamanho incorreto, causando vazamentos de
memória.
Repare que a declaração de records é igual à de
classes apenas com a diferença da palavra record
que indica qual tipo de dado estamos criando.
Iremos agora à função:
Function Validausuario(dad
os:DadosEntrada):DadosReto
rno
var
sql:string;
sdsvalida:tsqldataset;
Begin
Try
Sql:=’select
* from USERS where LOGIN=
’+quotedstr(dados.
nomeusuario)+’ and SENHA =
’+quotedstr(dados.senha);
Sdsvalida:=tsqldataset.
create(nil);
With sdsvalida do
Begin
Sqlconnection:=conexao;
Commandtext:=sql;
Open;
If
Criaremos a seguir um pequeno exemplo de
função de validação de usuários que receberá
alguns dados para realizar a validação e nos
devolverá nome, código e nível de usuário. Não entrarei em detalhes com
relação ao método de consulta ao banco que utilizarei
para fazer a validação
já que o foco do
artigo são os
records.
Outubro 2009
17
recordcount>0 then
Begin
Result.Usuari
ologado:=fieldbyname(‘NOME’
).asstring;
Result.Codigo
Usuario:=fieldbyname(‘CODIG
O’).asstring;
result
End;
End;
Finally
Sdsvalida.free;
End;
End;
Na função, fazemos um login simples e armazenamos as informações de saída no Record, o que
nos possibilita ter dois valores de saída. Nesse caso
são dois, mas poderiam ser mais bastando para isso
a inserção de mais campos no Record.
Records com Métodos
A partir do Delphi 2006, Records em linguagem
Object Pascal passaram a contar com mais uma
funcionalidade passando a aceitar métodos além
dos campos normais. Isso sem dúvida é uma grande funcionalidade que pode ser explorada pelos
desenvolvedores Delphi.
Como se comportam como variáveis estáti-
18
Outubro 2009
Figura 1
cas, ao usarmos records com métodos, podemos
usufruir de uma maior agilidade já que o Record é
liberado de memória assim que o escopo onde foi
declarado termina.
Vamos construir um exemplo simples agora
para utilizarmos essa funcionalidade dos Records.
Iremos declarar um Record que armazenará nome
e alguns dados de uma pessoa. Nesse Record
teremos o construtor e um método que fará a
alteração da senha.
RG:string;
Cpf:string;
Senha:string;
Constructor
Create(Pnome:string);
Procedure
alterasenha(Psenha:string);
End;
Implementação dos métodos:
Type
Pessoa=Record
Nome:string;
Constructor
Create(Pnome:string);
evento on click faça:
Begin
Nome:=Pnome;
End;
Procedure
alterasenha(senha:string);
Begin
Senha:=Psenha;
End;
Iremos agora criar uma pequena aplicação
exemplo para ilustrar o uso deste Record que
criamos:
Abra o Delphi 2009 e inicie uma nova aplicação,
monte o formulário de acordo com a figura 1:
Veja a Figura 1.
No evento onclick do Button faça:
rg:=edtrg.Text;
cpf:=edtcpf.Text;
senha:=edtsenha.Text;
end;
end;
procedure TForm1.
Button2Click(Sender:
TObject);
var novasenha:string;
begin
novasenha:=InputBox(‘Nova
Senha’,’Digite a nova
senha’,’’);
RefPessoaGlobal.
alterasenha(novasenha);
ShowMessage(‘A nova senha
é: ‘+RefPessoaGlobal.
senha);
end;
Repare que não precisamos nos preocupar em
liberar RefPessoa, que é a variável que faz referência a Pessoa porque como se trata de um Record,
quando a função que instanciou o Record termina
esse último é liberado de memória.
Se quiséssemos manter os dados de RefPessoa poderíamos copiá-los para uma variável de
escopo global que só seria liberada ao término
da aplicação.
Vamos demonstrar isso. Declare uma variável global RefPessoaGlobal do tipo Pessoa e no
evento onclick que criamos a pouco, insira mais
essa linha:
Teste o aplicativo e salve as alterações.
Conclusão
procedure TForm1.
Button1Click(Sender:
TObject);
var RefPessoa:Pessoa;
begin
RefPessoa.create(edtnome.
Text);
with RefPessoa do
begin
RefPessoaGlobal:=RefPessoa;
Com isso essa nova variável irá manter os dados que passamos a RefPessoa já que esta última
será liberada ao final do evento.
Aproveitando essa nova variável, vamos fazer
uso do método alterasenha do Record Pessoa.
Insira mais um Button no formulário e em seu
Através desse artigo, o leitor pode ter contato
com novas funcionalidades em um sistema que
podem ser proporcionadas pelo uso dos records.
Se bem aproveitadas podem ser de grande
utilidade para o dia a dia do desenvolvimento.
Espero que tenham gostado e até a próxima!
Sobre o autor
Antonio Spitaleri Neto
Consultor Técnico The Club.
[email protected]
Outubro 2009
19
Herança Visual
de formulários em
Windows Forms
Uma das técnicas que mais chamou
atenção desde o inicio da minha vida de programador é a herança visual de formulários.
Chama atenção pelo fato de aproveitarmos
o que a Programação Orientada a Objetos
(POO) tem de melhor, usando herança,
abstração, etc.
Uma aplicação Windows Forms comercial
possui dezenas ou até centenas de formulários, onde muitos possuem as mesmas características para um formulário de cadastro,
onde teremos, por exemplo, botões para novo
registro, salvar, excluir etc.
Podemos então aproveitar essa técnica
para criar um formulário base, com todas as
funcionalidades comuns dos formulários de
cadastros e assim, apenas herdar para os novos. Primeiramente, devemos analisar quais
as funcionalidades comuns em um formulário
de cadastro que devem ser implementadas
no base.
20
Outubro 2009
Criando o formulário base
Crie um novo projeto e no formulário dê o
nome de “frmBase”. Todas as propriedades dos
formulários de cadastro devem ser modificadas no
frmBase. Altere as seguintes propriedades: KeyPreview = true, MaximizeBox = false, MinimizeBox =
false, StartPosition = CenterScreen.
Assim temos uma grande vantagem, pois
não precisamos mudar as propriedades em cada
formulário. Os formulários herdados do frmBase
“recebem” as mesmas propriedades do formulário base.
Nota: todas as propriedades do formulário podem ser modificadas nos formulários
herdados. Diferentes dos componentes, que
para terem suas propriedades modificadas,
devem ser configurados para isso. Veremos
mais adiante essa configuração.
Agora precisamos adicionar os controles de
tela que serão comuns em todos os formulários
de cadastro. Poderíamos usar botões, mas nesse
exemplo, usarei um ToolStrip para adicionar as
funcionalidades de cadastro: Novo, Salvar, Excluir
etc.
No ToolStrip, adicione cinco botões
e dê uma imagem a cada um, referente
a sua funcionalidade (propriedade
Image). Na propriedade DisplayStyle mude para ImageAndText, para
mostrar a imagem e o texto.
Dê também nomes sugestivos aos botões, como “btnNovo”, “btnSalvar”,
etc. Adicione
também um StatusStrip no formulário. Veja na
Figura 1 como deve ficar o formulário.
Figura 1. Formulário base da aplicação
Esses são controles comuns de todos os formulários de cadastro, ou seja, os controles para
o cadastro de clientes (TextBox, Labels etc), por
exemplo, devem ser adicionados no formulário
herdado para esse cadastro especifico. Vamos
agora criar os métodos comuns que podem ser
usados em qualquer formulário herdado.
Criando código comum
Um exemplo bem simples e para fácil entendimento sobre a vantagem de usar formulários
herdados é o código para fechamento do formulário usando a tecla ESC. Sem a herança, o código
deveria ser colocado em todos os formulários. Com
a herança, o código será adicionado somente no
formulário base. Para isso, acesse o evento KeyDown do formulário e adicione o seguinte código que
será responsável por fechar o formulário quando o
usuário apertar a tecla ESC:
if (e.KeyCode == Keys.
Escape)
this.Close();
Agora, todos os formulários herdados, não precisam codificar o mesmo
evento para adicionar essa
funcionalidade.
Convenhamos, muita
produtividade e reaproveitamento de
código, mesmo
em um exemplo
simples. Outro
código bastante
comum usado em
cadastros são os métodos que habilitam/
desabilitam controles de tela e
o que “limpa” os controles.
O primeiro serve para indicar
ao usuário, quando os controles
Figura 1. Formulário base da aplicação
de tela podem ficar disponíveis para o usuário e
o segundo, para limpar, principalmente TextBox,
depois de inserção ou atualização dos dados no
banco. Adicione o seguinte código, que será o de
habilitar/desabilitar controles:
private void HabilitaDesabi
litaControles(bool Value)
{
foreach (Control ctl in
this.Controls)
{
if (ctl is ToolStrip)
continue;
ctl.Enabled = Value;
}
}
O código é bastante simples, onde possui
um parâmetro do tipo bool para indicar se deseja
habilitar ou desabilitar os controles, usando a
propriedade Enabled dos controles de tela (this.
Controls), configurados através de um foreach.
Fizemos uma verificação do ToolStrip para
que os botões não sejam desabilitados, assim, se
acharmos um controle do tipo, continuamos o laço,
usando o continue. Já podemos usar o método no
formulário base, pois após o usuário clicar no Novo,
os controles de tela devem ser habilitados.
No botão adicione o código, passando como
parâmetro true. Com esse código, os botões de
cadastros do ToolStrip também estarão desabilitados ou habilitados, então vamos criar um enum
para indicarmos quando devemos habilitar ou
desabilitar determinado botão, conforme o código
a seguir:
public enum StatusCadastro
{
scInsert, scBrowser, scEdit
}
Crie também uma variável do tipo do enum
chamada sStatus. No HabilitaDesabilitaControles
vamos modificar o método, adicionando o código
da Listagem 1, após o foreach.
Listagem 1. Alterando a configuração do botão,
de acordo com o status do cadastro
//habilitado quando não
estivermos inserindo ou
editando, somente navegando
btnNovo.Enabled = (sStatus
== StatusCadastro.
scBrowser);
//habilitado quando estiver
inserindo ou editando
Outubro 2009
21
btnSalvar.Enabled
= ((sStatus ==
StatusCadastro.scInsert) ||
(sStatus ==
StatusCadastro.scEdit));
//habilitado quando
estivermos editando
btnExcluir.Enabled =
(sStatus == StatusCadastro.
scEdit);
//habilitado quando não
estivermos inserindo ou
editando, somente navegando
btnLocalizar.Enabled =
(sStatus == StatusCadastro.
scBrowser);
//sempre habilita o sair
btnSair.Enabled = true;
No código, estamos verificando o valor de sStatus, para habilitar/desabilitar os botões, então para
que isso funcione corretamente, devemos atribuir
o valor correto para a variável, em determinadas
situações.
No botão Novo, antes do HabilitaDesabilitaControles, devemos configurar a variável para
scInsert. Nos botões Salvar e Excluir, atribuía o valor
scBrowser, seguido do HabilitaDesabilitaControles
passando false. Já no Localizar, alteramos a variável para scEdit e devemos habilitar os controles
de tela.
Mais código comum
Como indicado anteriormente, outro código
interessante a ser usado no formulário base, é para
“limpar” controles de tela. Para isso implemente o
código da Listagem 2.
Listagem 2. Método para limpar controles
de tela
private void
LimpaControles()
{
foreach
(Control ctl in this.
Controls)
22
Outubro 2009
{
if
(ctl is TextBox)
(ctl as TextBox).Text = “”;
if
(ctl is ComboBox)
(ctl as ComboBox).
SelectedIndex = -1;
if
(ctl is ListBox)
(ctl as ListBox).
SelectedIndex = -1;
}
}
O código é bastante semelhante ao anterior,
onde fizemos um laço pelos controles de tela. A
diferença fica por conta, que verificamos o tipo de
controle utilizando a diretiva is para saber o tipo
da classe. Sabendo o tipo, usamos o as para fazer
um cast e acessar as propriedades da classe. Assim,
podemos utilizar, por exemplo, o Text do TextBox, o
SelectedIndex do ListBox e ComboBox.
Para outras classes, basta verificar seu tipo e
fazer o cast na propriedade desejada. Bom, e onde
vamos usar esse método? Devemos usar o mesmo
quando o usuário quiser adicionar um novo registro, portanto chame o método no botão Novo.
Nosso processo será o seguinte para um
novo registro: usuário clica em Novo, limpamos e
habilitamos os controles de tela, usuário adiciona
os dados, salvamos o registro, desabilitamos os
controles de tela.
Assim, colocamos o usuário em um processo
onde os erros, têm menos possibilidade de ocorrer
(claro, devemos ter as validações do cadastro em
cada formulário herdado). Precisamos também
deixar os controles limpos e desabilitados quando
o usuário abrir pela primeira vez o formulário.
No evento Load do formulário, usaremos o
seguinte código:
sStatus = StatusCadastro.
scBrowser;
LimpaControles();
HabilitaDesabilitaControles
(false);
A idéia das funcionalidades do cadastro é que
usaremos um cadastro parametrizado, ou seja,
o usuário deve localizar um registro para poder
editá-lo, assim quando abrir o formulário, as opções
existentes são de inserir um registro (botão Novo)
ou localizar para edição.
Métodos virtuais
Podemos declarar métodos no formulário
base, que podem ser subscritos nos formulários
herdados. A vantagem é que precisamos apenas
subscrever, com o código necessário, não precisando chamar o mesmo em determinadas situações,
claro se já o fizermos no formulário base.
Para um melhor entendimento dessa parte,
imagine o método para salvar os dados. Com o
método virtual, declaramos o mesmo no formulário
base, e a implementação que será de acordo com
o cadastro, deve ser feita no herdado.
A chamada do método será feita no formulário base, no botão de salvar os dados. Partindo
para a prática, declare os métodos a seguir no
formulário base:
public virtual bool
Salvar()
{
}
public virtual bool
Excluir()
{
}
public virtual bool
Localizar()
{
}
O método pode ter implementação de código e
vamos subscrever o mesmo no formulário herdado
(ou classe, caso fosse essa a intenção). Faça a chamada aos métodos nos respectivos botões. Como
temos um retorno do método (bool), o código que
já implementamos nos botões devem ser executados, somente se o método retornou true.
Adicionamos uma mensagem ao bloco de
código para que o usuário saiba que o método
foi executado com sucesso. Para o botão Salvar
teríamos o código da Listagem 3.
Listagem 3. Alterando o código dos botões
if (Salvar())
{
sStatus = StatusCadastro.
scBrowser;
HabilitaDesabilitaControles
(false);
MessageBox.Show(“Registro
salvo com sucesso!”,
“Salvar”,
MessageBoxButtons.OK,
MessageBoxIcon.
Information);
}
Figura 2. Criando um formulário baseado em outro
Podemos ainda implementar um código ou
variável que retornasse o motivo do método ter
retornado false, por exemplo, não salvando os
registros. Lembrando, tudo isso pode e deve ser
implementado no base, sem duplicar código em
cada formulário. Execute de maneira semelhante,
os outros métodos nos seus respectivos botões.
Criando o formulário herdado
Bom, podemos claro implementar mais código
no formulário base, mas isso depende da necessidade do nosso projeto. Para criar um formulário
herdado, primeiramente, dê um Build no seu
projeto e em seguida, acesse o menu Project>Add
Windows Forms.
Figura 3. Escolhendo o formulário base
Em Add New Item, na seção Windows Forms,
escolha a opção Inherited Form, como podemos
ver na Figura 2.
Figura 2. Criando um formulário baseado
em outro
Após colocar o nome do formulário e clicar em
Add, teremos um novo editor, onde vamos escolher
o formulário que será herdado. Veja na Figura 3 a
tela onde escolhemos o formulário.
Figura 3. Escolhendo o formulário base
Outubro 2009
23
Caso o formulário que você deseja herdar, não
aparecer, experimente dar um Build na aplicação
e tente novamente. Ao clicar em OK, teremos um
formulário com os mesmos componentes do formulário base (Figura 4).
Figura 4. Formulário herdado
Nota: Os componentes adicionados no
formulário base, não podem ser excluídos
nos formulários herdados, portanto, como
frisado anteriormente, é necessário fazer uma
análise perfeita dos controles que devem ser
mostrados no base.
Você pode alterar propriedades como Enabled
e Visible para modificar o controle no formulário
herdado, mas para isso, deverá alterar a propriedade Modifiers para Public do componente no
formulário base.
Caso esteja utilizando o Visual C# (versão
gratuita do Visual Studio para aplicações Windows
Forms), a opção Inherited Form da Figura 2, pode
não aparecer. Mas para contornar isso, é muito
fácil. Abra o editor de código do formulário que
deseja herdar (crio primeiramente) e na declaração
do tipo, altere como o código a seguir:
Figura 4. Formulário herdado
Veja que não precisamos nos preocupar com
funcionalidades para fechar formulário, limpar e
desabilitar controles de tela, tudo esta codificado
no formulário base, trazendo produtividade e fácil
manutenção dos cadastros. Declare os métodos da
Listagem 4 no formulário de clientes.
Listagem 4. Subscrevendo os métodos da
classe base (formulário)
Antes
public partial class Form1
: Form
Depois
public partial class
frmClientes : frmBase
Após, salve o formulário, feche o mesmo e dê
um build na aplicação. Ao reabrir, o mesmo estará
com os componentes do formulário base.
Codificando o formulário herdado
Após herdar o formulário, o que precisamos
fazer? Primeiro, devemos adicionar os controles
para mostrar os dados do cadastro que precisamos. Aqui, didaticamente, usaremos um cadastro
de clientes. Então, adicione controles de tela, e
precisamos codificar os métodos virtuais, criados
no formulário base, salvando e excluindo os dados
do cliente.
24
Outubro 2009
public override bool
Salvar()
{ return base.Salvar(); }
atualizará os dados do cliente, bem como o de
excluir os dados, usando os métodos. Para efeitos
de didática, imaginamos que temos o código para
adicionar os dados, onde apenas vamos retornar
true no método.
Vamos configurar para que o formulário de
clientes seja o formulário inicial da aplicação. Ao
abrir o formulário, clicamos em Novo e adicionamos os valores nos TextBox. Após clicamos em
Salvar e temos a mensagem de confirmação que
só é executada se o método salvou corretamente
os dados.
Veja que com essa técnica, poupamos trabalho
public override bool
Excluir()
{ return base.Excluir(); }
public override bool
Localizar()
{ return base.Localizar();
}
Veja que temos o retorno do método criado
no formulário base, usando base.NomedoMétodo, isso indica que qualquer código que for
implementado no método, será executado com
essa chamada.
O trabalho que teremos no formulário de
clientes será escrever o código que adicionará ou
para o leitor implementar
e mostrar o conhecimento
adquirido com o artigo.
Conclusão
Figura 5. Exemplo do formulário em execução
e código, ou seja, temos em apenas um método o
código necessário, por exemplo, para excluir um
registro, que varia de acordo com o cadastro. Veja
na Figura 5 o cadastro de clientes em execução.
Veja a Figura 5. Exemplo do formulário em execução
Para a funcionalidade de Localizar, também
podemos criar um formulário de pesquisa base,
e, por exemplo, passar um DataTable ou DataSet
para fazer a pesquisa dos dados. Deixo essa idéia
leitor, mas sempre tenha em mente que o tempo
de análise é muito importante antes de começar
a desenvolver seus projetos e no nosso exemplo,
um formulário base.
Um grande abraço a todos e sucesso em seus
projetos!
Vimos neste artigo,
como criar formulários bases, para serem usados de
maneira produtiva em aplicações Windows Forms. As
dicas apresentadas neste artigo podem e devem
ser melhoradas e adaptadas a necessidade do
Confira o video deste
artigo no site do The
Club na edição online
da revista.
Sobre o autor
Luciano Pimenta
É Técnico em Processamento de Dados, desenvolvedor Delphi/C# para aplicações
Web com ASP.NET e Windows com Win32 e Windows Forms. Palestrante da 4ª edição
da Borland Conference (BorCon).
Autor de mais de 60 artigos e de mais de 300 vídeos aulas publicadas em revistas
e sites especializados. É consultor da FP2 Tecnologia (www.fp2.com.br) onde ministra
cursos de programação e banco de dados. É desenvolvedor da Paradigma Web Bussiness em Florianópolis-SC.
www.lucianopimenta.net
Outubro 2009
25
Acesso a
dados com
jQuery
Olá, chegamos ao final dos nossos 3 artigos sobre jQuery. Nesse artigo irei tratar sobre
como acessar a funções (Handler) no Server
site através de funções nativas do jQuery.
Levando-se em consideração a prática do
primeiro artigo vamos ao que interessa:
Primeiro vamos abrir o Visual Studio 2008 e
criaremos uma aplicação Web (imagem 01). Depois de criarmos a aplicação WEB adicionamos o
jQuery a nossa aplicação e agora estamos prontos
para começar a desenvolver nosso exemplo de
utilização.
Veja a imagem 1.
Imagem 1
Depois da aplicação criada, tecle com o botão
direito sobre o projeto > depois Add > New Item
(Imagem 02), abrirá a tela Add New Item, nessa tela
iremos selecionar a Opção Web do lado esquerdo
e a Opção Generic Handler (imagem 03) neste
ponto nossa aplicação deverá ter os seguintes
arquivos (Imagem 04), esse Generic Handler é uma
espécie de WebService que fará a “ligação” entre
o client-side ( jQuery ) e a camada de negócio ou
o banco de dados, através dele que acessaremos
as funções C#.
Veja a Imagem 2.
Veja a imagem 3.
26
Imagem 2
Imagem 3
Outubro 2009
Agora vamos começar a codificar: Primeiro
vamos incluir o jQuery na nossa página Default.
Aspx através da Listagem 01, nessa listagem
referenciamos o jQuery, logo após esse código referenciamos a nosso objeto de pesquisa
conforme listagem 02, na listagem 02 temos a
lista de categorias que podemos ter em nosso
exemplo, que seria semelhante a uma loja virtual,
observem que estamos criando links e nesses
links apontamos para a própria página através do
# e no evento onclick atribuímos a chamada de
um método JavaScript que iremos implementar
adiante, passamos para esse método o código da
categoria que estamos procurando, exemplo a categoria Culinária é o código 1 Informática código 3
e assim sucessivamente. Agora vamos implementar
nosso método para acessar o servidor e retornar
os produtos da categoria sem a necessidade de
fazer um postback de toda a página (listagem 03),
observem que na listagem 03 eu criei primeiro um
Bloco de text/JavaScript que deve ser criado dentro
das tag <head> do nosso HTML, depois eu criei
uma variável contendo o nome do nosso handler
para facilitar a manutenção futuramente e depois
implementei o nosso GetComunicacaoDados(e),
onde é o código da categoria que estou pesquisando. Depois crio outra variável nomeada como
detailArea contendo o nome do elemento HTML
que vai receber os produtos de determinada categoria, depois implementamos o método $.get
do jQuery que tem como seus parâmetros default
a URL, DATA, CALLBACK onde que URL indica a
página que temos nosso Handler o DATA indica o
valor que queremos passar em nosso parâmetro,
uma espécie de QueryString e o Callback é o que
o Client-side vai processar quando o servidor
responder a requisição, no campo URL passamos
a nossa variável criada anteriormente com o caminho do nosso Handler depois no parâmetro DATA
é no formato JSON indiquei um atributo nomeado
como codCategoria e passei para ele o código da
categoria que tínhamos colocado no onclick lá no
link de categorias, e por último o CALLBACK que
é o que será processado pelo client-side quando
o servidor retornar da requisição, neste caso ele
simplesmente vai colocar o retorno para dentro
do nosso divProdutos onde estarão os produtos
da nossa loja. Para criar o Div de produtos utiliza
a listagem 04. Ok agora o nosso Client-Side está
pronto, a nossa página Default.aspx está ok.
Agora vamos abrir o arquivo Handler1.ashx e
implemente no método ProcessRequest a listagem
05, nessa listagem primeiro criamos uma variável
inteira que receberá o valor do JSON codCategoria
que contém dentro dele a categoria que está sendo
pesquisada, depois eu “escrevo” no context (página) o retorno do meu método RetornarProdutos
que é um método que pode estar em qualquer
NameSpace da minha aplicação, assim conseguimos interagir entre o HTML e o C#, mas retornando
ao nosso exemplo o Método RetornarProdutos
está dentro da mesma classe do Handler esse
método está descrito na Listagem 06, fiz apenas
um exemplo simples para retornar valores pois
não é de intenção desse artigo entrar em questão
o acesso a banco de dados. Agora vamos acessar
a nossa aplicação (F5): Quando abrimos a nossa
página vai estar no topo as categorias que foram
listadas (Elétrodoméstico, Culinária, Etc.) e em
baixo um FieldSet com o título Produtos da Categoria, quando clicamos em alguma das categorias
o JavaScript do onClick daquele link é executado
fazendo uma requisição ao servidor para que o
mesmo retorne com os produtos referenciados
para determinada categoria. Então é isso, espero
que tenham gostado dessa série de artigos sobre
jQuery e em breve estarei com novos artigos sobre
novas tecnologias que estão sendo lançadas no
VS2010 e Silverlight 3.
Listagem 01:
<asp:ScriptManager id=”sm1”
runat=”server”>
<Scripts>
<asp:ScriptReference
Path=”~/Scripts/jquery1.3.2.js” />
</Scripts>
</asp:ScriptManager>
<li><a
href=”#” onclick=”GetCo
municacaoDados(1);return
false;”>Culinária</a></li>
<li><a
href=”#” onclick=”GetCo
municacaoDados(2);return
false;”>Informática</a></li>
<li><a
href=”#” onclick=”GetCo
municacaoDados(3);return
false;”>Jardinagem</a></li>
</ul>
Listagem 03:
<script type=”text/
javascript”>
// The handler url
var handlerUrl =
‘Handler1.ashx’;
function
GetComunicacaoDados(e) {
var detailArea =
‘#divCategorias’;
$.get(handlerUrl
, {
codCategoria: e.toString() }
,
function(data) {
$(“#divprodutos”).
html(data);
});
}
</script>
Listagem 02:
Listagem 04:
<ul id=”categories”>
<li><a
href=”#” onclick=”GetCo
municacaoDados(0);return
false;”>Eletrodomésticos</
a></li>
<br />
<fieldset>
<legend>
Produtos da Categoria </
legend>
Outubro 2009
27
<div
id=”divprodutos”></div>
</fieldset>
Listagem 05
public void
ProcessRequest(HttpContext
context)
{
int
codCategoria = Int32.
Parse(context.Request.
QueryString[“codCategoria”]);
context.
Response.Write(RetornaProdut
os(codCategoria));
}
Listagem 06
private string
RetornaProdutos(int
28
Outubro 2009
CodCategoria)
{
// Aqui posso
criar um acesso a banco de
dados e
// filtrar
os produtos da cateogira
indicada no parâmetro do
método
StringBuilder sb
= new StringBuilder();
sb.Append(“produto 01 da
cateogia “ + CodCategoria.
ToString() + “<br/>”);
sb.Append(“produto
02 da cateogia “
+ CodCategoria.
ToString() +
“<br/>”);
sb.Append(“produto
03 da cateogia “
+ CodCategoria.
ToString() +
“<br/>”);
return
sb.ToString();
}
Conclusão:
O objetivo dessa seqüência de artigos sobre
jQuery era de passar um pouco de conhecimento
aos desenvolvedores .net e web uma pequena parte dessa fabulosa Framework que veio para firmar
ainda mais a chamada WEB 2.0 com muitas mais
interatividade, praticidade e performance.
Sobre o autor
Djonatas Tenfen
Trabalha a quase 7 anos com Delphi, trabalha na empresa Benner
Sistemas (www.benner.com.br ) na área de tecnologia desenvolvendo ferramentas em Delphi e como hobby e visão de mercado está migrando seus
conhecimentos para a plataforma .NET. Faz parte do grupo .NET Blumenau
http://dotnetblumenau.ning.com/ . Possue certificação 70-536 (Microsoft
.NET Framework 2.0 Application Development Foundation ) .
Twitter: djonatastenfen - blog http://www.djonatastenfen.blogspot.com/
[email protected]
Dicas DELPHI
Alterar propriedade buttonstyle das toolbars ligadas ao
actionmanager em tempo de execução:
Mostrar jpg num grid
uses
jpeg
TButtonProperties(ActionMana
ger1.ActionBars[0].Items[0].
CommandProperties).ButtonSize :=
bsLarge;
Esse typecast também serve para alterar outros subitens de command
properties como buttontype, groupposition e textassociation
Criando uma caixa de mensagem personalizada
function mensagem(Texto: string;
Botao: TMsgDlgButtons = [mbOk];
Rotulo:String = ‘Atenção’; Icon :
TMsgDlgType = mtWarning): integer;
var
wl_mensagem: TForm;
begin
no evento do onDrawColumnCell do grid.
var
jpeg:tjpegimage;
begin
if column.Field is tgraphicfield
then
begin
with dbgrid1.Canvas do
begin
fillrect(rect);
jpeg:=tjpegimage.create;
try
jpeg.Assign(column.Field);
draw(rect.Left,rect.top,jpeg);
finally
jpeg.Free;
end;
end;
end;
end;
wl_Mensagem :=
CreateMessageDialog(Texto, Icon,
Botao);
(wl_mensagem.FindComponent(‘YES’)
as TButton).Caption := ‘&Sim’;
(wl_mensagem.FindComponent(‘NO’)
as TButton).Caption := ‘&Não’;
(wl_mensagem.FindComponent(‘OK’)
as TButton).Caption := ‘&Ok’;
(wl_mensagem.
FindComponent(‘CANCEL’) as
TButton).Caption := ‘&Cancela’;
wl_mensagem.Color := clBtnFace;
wl_mensagem.BorderStyle :=
bsSingle;
wl_mensagem.BorderIcons := [];
wl_mensagem.Caption := Rotulo;
result := wl_mensagem.ShowModal;
end;
Wav em sua aplicação
Na Unit do form vá até USES e acrescente lá: MMSystem, (coloque a
vírgula).
Depois vá no evento OnShow do form e coloque o comando:
Begin
PlaySound(‘C:caminho_da_
musicanome_da_musica.wav’, 1, SND_
ASYNC);
End;
End.
Outubro 2009
29
30
Outubro 2009
Outubro 2009
Outubro 2009
Download