Clube-Delphi 144 Hxjugphe
Clube-Delphi 144 Hxjugphe
Boas Práticas
06 – MVVM no Delphi
[ Paulo Roberto Quicoli ] Sumário
Novidade
16 – CodeSite no Delphi XE 2
[ Giuliano Scombatti Pinto ]
Boa Ideia
28 – Trabalhando com Streams e Threads dando a compreender com ainda
mais facilidade o conteúdo desta
[ Giuliano Scombatti Pinto ]
edição. Será um prazer contar com
sua companhia! Confira abaixo o
Minicurso, Mobile
36 – Desenvolvimento Android – Parte 4 que teremos nesta revista:
[ Giuliano Scombatti Pinto ]
Minicurso, Easy
44 – dbExpress de A-Z – Parte 3
[ Alexandre Borges ]
Feedback
eu
Dê seu feedback sobre esta edição!
s
Dê
sobre e
A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber o que você, leitor, acha da revista!
Dê seu voto sobre esta edição, artigo por artigo, através do link:
s
ta
edição
www.devmedia.com.br/clubedelphi/feedback
EDITORIAL
E
screver um sistema que atenda aos requisitos de um cliente deve ser
o objetivo principal de qualquer desenvolvedor, contudo, depois de
pronto esse sistema pode ficar em funcionamento por anos. Ou seja,
inicia-se a fase de manutenção do mesmo. Nessa fase sua empresa pode
mostrar um diferencial à concorrência conseguindo responder às solicita-
ções de mudanças de forma mais rápida e mais barata. Para conseguir isso
Ano 12 - 144ª Edição 2012 - ISSN 1517990-7 Impresso no Brasil
um segundo objetivo deve ser incluído durante o desenvolvimento: a utili-
zação de uma boa arquitetura. Quando falamos em arquitetura, a primeira
Corpo Editorial
visão que nos vem é a separação das camadas de um sistema, principalmen-
Editor Geral te a visual e lógica de negócios. Nesta edição apresento um artigo sobre
Paulo Quicoli essa separação. Como aplicá-la em seus projetos utilizando um padrão de
pauloquicoli@gmail.com projeto pouco conhecido, o MVVM. Além disso, são explorados detalhes do
Editor Técnico framework que o implementa o DSharp e os benefícios obtidos ao se separar
Daniel Sobrinho Laporte essas camadas.
daniel.laporte@gmail.com O Giuliano traz três assuntos. Temos um artigo sobre o CodeSite da versão
Equipe Editorial XE 2. Esse assunto é importante pois mostra como podemos armazenar um
Guinther Pauli log de forma diferenciada, que poderá nos ajudar na fase de manutenção
guintherpauli@gmail.com de um sistema. Ele também explora um estudo sobre o uso de Streams no
Fabrício Hissao Kawata Delphi, mostrando a criação de um gerenciador de download que faz uso de
fabricio.kawata@bol.com.br multithreads para quebrar o arquivo a ser baixado em três partes simultâ-
neas. A aplicação desenvolvida expõe conceitos que podem ser reutilizados
Giuliano Scombatti Pinto
giuliano@sygnux.com.br em outras situações, não perca. E nesta edição o minicurso sobre desenvolvi-
mento Android se encerra, mostrando um pouco mais sobre jQuery. Espero
Jornalista Responsável que essa pequena série de artigos tenha despertado o interesse de muitos
Kaline Dolabella - JP24185 sobre o assunto, pois é o que movimentará o mercado nos próximos anos.
Toda a história entre InterBase e Firebird é conhecida pela maioria dos uti-
Atendimento ao Leitor lizadores do Firebird, contudo, uma vez que optaram pelo Firebird, nunca
A DevMedia conta com um departamento exclusivo para o atendimento ao leitor. Se você tiver mais viram nada sobre o InterBase. O Fabrício mostra em seu artigo os recur-
algum problema no recebimento do seu exemplar ou precisar de algum esclarecimento sobre assi- sos que banco de dados da Embarcadero possuir.
naturas, exemplares anteriores, endereço de bancas de jornal, entre outros, entre em contato com:
Por fim, o Alexandre traz a parte final sobre dbExpress, que os iniciantes
www.devmedia.com.br/central agora se sintam confortáveis com a tecnologia e a utilizem eficientemente
(21) 3382-5038
no seu trabalho diário.
Publicidade Uma boa leitura!
Para informações sobre veiculação de anúncio na revista ou no site e para fechar parcerias ou
ações específicas de marketing com a DevMedia, entre em contato com:
É muito importante para a equipe saber o que você está achando da revista: que tipo de artigo você
gostaria de ler, que artigo você mais gostou e qual artigo você menos gostou. Fique a vontade para
entrar em contato com os editores e dar a sua sugestão!
Assine agora e tenha acesso a
Se você estiver interessado em publicar um artigo na revista ou no site ClubeDelphi, entre em contato todo o conteúdo da DevMedia:
com os editores, informando o título e mini-resumo do tema que você gostaria de publicar: www.devmedia.com.br/mvp
Paulo Quicoli - Editor da Revista
pauloquicoli@gmail.com
Seção Boas Práticas artigos sobre as tecnologias que poderão aumentar a qualidade do desenvolvimento de software
MVVM no Delphi
Separe interface e regra de negócios
A Resumo DevMan
separação da interface de usuário (UI) do
restante das regras de negócio não é um
assunto novo. Mesmo assim essa separação De que se trata o artigo:
não é aplicada no dia a dia pela grande maioria dos Este artigo tem por finalidade destacar a importância de se organizar
desenvolvedores. Muitos pensam que para alcançar uma aplicação em camadas lógicas, como conseguir isso separando a
esse objetivo seria necessário alterar toda sua progra- interface visual de sua lógica ao fazer uso do padrão MVVM e como ele
mação, abandonar o estilo RAD (Rapid Application pode ser aplicado em Delphi através do Framework DSharp. São aborda-
Development) do Delphi e se voltar totalmente para a dos conceitos como DataBinding, separação de camadas e as vantagens
Orientação a Objetos. que essa separação traz.
É muito comum encontrar projetos onde os códigos
para exibição de dados, sentenças SQL e validação de Em que situação o tema é útil:
negócio estão centralizados nos formulários, esse é o Este tema é utilizado para organizar o código fonte de uma aplicação,
famoso código espaguete ou macarrônico. Fazer um separando as funcionalidades existentes em camadas lógicas. Um exem-
projeto dessa maneira é muito rápido e em tese, não é plo do que deve ser separado é a camada visual e a camada de negócios,
errado, pois o que importa é resolver o problema de um que uma vez independentes uma da outro, permitem a aplicação de outra
cliente. Mas além de pensar simplesmente nisso seria boa prática, o uso de testes automatizados.
bom pensar também na vida desse projeto.
Existe uma fase no ciclo de vida de um projeto intitu- MVVM no Delphi:
lada manutenção. Nela são implementadas melhorias, Desde o Delphi 2010 vários recursos internos foram acrescidos à lingua-
correções e até mesmo novos recursos. Essa fase pode gem Delphi. Muitos deles localizados na parte de RTTI, ou introspecção
fazer com que um projeto seja menos competitivo que de informações. Com isso a linguagem foi ficando poderosa o suficiente
outro ou até mesmo mais custoso. Neste caso, pode-se para facilitar o desenvolvimento de Frameworks que hoje auxiliam na
dizer ser menos competitivo porque dependendo de aplicação das mais diversas boas práticas da orientação a objetos. A di-
como foi escrito, alterar uma rotina pode levar dias, visão de responsabilidades é uma dessas. Porque a camada de interface
semanas. E consequentemente isso gera custo, o que precisa estar tão ligada à camada de negócios? O ideal é que ela somente
torna cara a manutenção. O código macarrônico causa apresente os dados. Conseguir isso não era fácil, contudo temos agora o
essa situação. DSharp, um Framework que implementa o padrão de separação visual
As camadas do projeto são amarradas entre si, geran- MVVM. O ponto chave desse padrão é a utilização do recurso chamado
do uma dependência desnecessária, impossibilitando DataBinding, ou ligação de dados, para propiciar essa separação. É
a reutilização de rotinas, regras de negócio. Sem falar exatamente isso que o DSharp traz e que vamos explorar neste artigo,
a aplicação de rotinas consagradas para atestar quali- construindo exemplos e discutindo a teoria.
dade, como testes unitários.
MVVM/Presentation Model
O objetivo desse padrão é representar o estado e comportamento
de uma View, independente dos controles utilizados. A essência
Figura 1. Camadas lógicas de um software do MVVM está na classe (View Model) que representa todos os
dados e comportamentos de uma UI, mas sem conter os controles
Quando essas camadas se misturam é dito que existe um aco- utilizados para exibir esses dados. A UI, representada por View,
plamento entre elas. No momento que você insere código SQL simplesmente projeta o estado do View Model. Para isso o View
em evento OnClick de um botão o acoplamento foi realizado. Seu Model contém propriedades para todas as informações dinâmicas
formulário, que é sua camada de apresentação, está fazendo acesso da View. Essas informações são compreendidas pelo conteúdo
direto aos recursos do que seria sua camada de dados. Isso impede dos controles e valores de estado dos controles, utilizados, por
a reutilização da lógica contida no formulário. Tudo isso dificulta exemplo, para habilitar ou não um controle visual. Isso não signi-
a manutenção do seu sistema porque você terá SQL espalhado por fica que seja necessário armazenar todo o estado de um controle
todo código e não apenas centralizado em uma área. visual, mas apenas aqueles que podem ser alterados pela intera-
Outra prática que é muito comum é de se criar os eventos e dentro ção com o usuário. Como o View Model deve conter os dados a
deles escrever um código tão longo que para entender o que está serem exibidos, é ele que se conecta aos objetos de negócio, que
sendo feito é quase como ler um livro. Consequentemente, a rotina são a parte chamada Model desse padrão e fica responsável por
ali dentro poderia ser quebrada em classes ou funções. sincronizar com a View esses dados.
Quando uma rotina faz mais do que foi projetada a fazer é dito que A principal diferença em relação ao MVC ou MVP é que as
existe uma baixa coesão nela. A baixa coesão é outro problema para partes View e ViewModel não possuem dependência entre si. É
a boa manutenção do seu Software. Então, como podemos separar possível construir a UI independentemente da regra de negócio
as camadas sem evitando a baixa coesão e alto acoplamento? e posteriormente ligar, ou usando o jargão específico: realizar o
Quem já está no mercado há algum tempo com certeza já ouviu Binding dessas partes. Essa é palavra que faz esse padrão funcio-
sobre os padrões MVC (Model-View-Controller) ou MVP (Model- nar, Binding. Mas o que é um Binding?
View-Presenter). Esses padrões de projeto, que são soluções
atestadas por vários desenvolvedores, sugerem uma solução à Conceituando DataBinding
separação da UI. Esses são padrões bem genéricos, que podem É um objeto que representa a ligação entre outros dois objetos.
ser implementados por qualquer linguagem orientada a objetos, Ele define como dois objetos estarão ligados, sua relação. Em
visto que não utilizam recursos específicos. uma operação de Binding um objeto pode ser um Source ou
O MVC para separar a camada de apresentação cria três partes Target (Figura 2). Source é o objeto “fonte de dados” enquanto
distintas, o Model, a View e o Controller. Podemos defini-los da que o Target é o alvo, o objeto que irá exibir o Source. Também
seguinte forma: Model – É a representação da informação que a é definido o que exibir e onde exibir, para isso são informadas
aplicação utiliza; View – É a representação gráfica do Model. Por a propriedades relativas de cada objeto. Por exemplo, podemos
exemplo, um formulário expondo as informações de um cliente. determinar que a propriedade Nome de um objeto TPessoa seja
Uma View está sempre ligada a um model e sabe como exibi-lo exibida na propriedade Text de um controle TEdit.
ao usuário. Além disso, também pode ser composta por várias É possível ainda determinar o fluxo dos dados, ou seja, quem
Views; Controller – É responsável em mapear as ações do usuário atualiza o que. Por exemplo, se apenas o Source é que envia dados
em ações do sistema, por exemplo, se um botão ou item de menu para o Target, se apenas o Target envia ou ambos trocam informa-
é clicado é ele que deve definir como a aplicação responderá. ções. Com esse comportamento podemos determinar uma espécie
O MVP é por sua vez, uma extensão do MVC, tratando a View apenas de Binding somente leitura, onde um TEdit apenas apresenta os
como uma camada simples que implementa uma Interface dados e não envia as alterações para o objeto source. Os fluxos
contendo todas as propriedades e métodos necessários para o possíveis podem ser vistos na Figura 3.
No modo OneWay somente o Source atualiza o Target. Já em Para Delphi existe o Framework DSharp. Ele foi desenvolvido
TwoWay, os dois trocam informações e no OneWayToSource, o observando o que existia para o .NET, extraindo conceitos que
Target é que envia os dados para o Source. Nos modos em que poderiam ser aplicados. Um desses é o chamado ModelView
o Source pode ser atualizado (TwoWay e OneWayToSource), Binder, que representa uma classe que toma uma View (como um
podemos ainda determinar quando essa atualização é feita formulário) e um View Model (como um DataModule ou outro
(Figura 4). objeto de negócio) e pode criar ligações entre eles utilizando
convenções nominativas. Por exemplo, no View Model temos uma
propriedade chamada NomeCliente, na View temos um TEdit
com o nome NomeCliente, automaticamente os dois são ligados
entre si. A mesma ideia também é utilizada para preenchimento
de controles como TComboBox, uma propriedade “Cidades” no
View Model também poderia ser ligada a um combo Cidades da
View. Objetos encadeados também podem ser ligados automati-
camente obedecendo a um padrão. Digamos que no View Model
Figura 2. Relação de ligação temos Cliente.Endereco.Logradouro. Isso poderia ser ligado a um
TEdit na View chamado Cliente_Endereco_Logradouro.
Essa forma de funcionamento é chamada de convenção sobre
configuração ou simplesmente codificação por convenção. É um
paradigma na modelagem de Software que tem o objetivo de fazer
com que os desenvolvedores tomem menos decisões, gerando
simplicidade, sem perder flexibilidade. Isso quer dizer que um
desenvolvedor teria que se preocupar apenas com os aspectos não
convencionais de sua aplicação. Se ele está codificando uma classe
Figura 3. Fluxos de binding View Model chamada PessoasViewModel, a sua contrapartida
View seria chamada PessoasView por padrão.
Quando temos um Framework que segue essas ideias, temos
menos código de configuração a escrever. Outro conceito adotado
pelo DSharp foi a adoção de um Framework de injeção de depen-
dência. A injeção de dependência é um mecanismo onde é possível
informar o que determinado objeto precisa para ser instanciado
e esse Framework se encarrega disso. Por exemplo, temos um
objeto TLog que recebe em seu construtor um parâmetro do tipo
TTipoLog, que seria outra classe que contém a configuração para
Figura 4. Determinando a atualização realização de um Log. Tudo isso implica que toda vez que fosse
necessário criar um objeto TLog, também teríamos que criar um
Isso é feito através de uma propriedade UpdateSourceTrigger. TTipoLog. Ao registrar essa dependência em Framework de inje-
Ela pode receber o valor LostFocus, onde a atualização ocorre ção, simplesmente pedimos a esse Framework uma nova instância
quando o Target perde o foco e seu evento OnExit é disparado. O de TLog e ele se resolve para nos entregar. Esses são recursos bem
outro valor possível é o PropertyChanged, que atualiza o Source avançados, contudo, neste artigo vamos focar no que é possível
sempre que a propriedade do Target ligada ao Binding sofre algu- de fazer com Data Binding.
ma alteração. Por fim temos ainda o Explicit. Nesse caso o Target
só envia as atualizações para o Source quando o desenvolvedor
chamar o método UpdateSource do target. Tutorial
Frameworks MVVM
Apesar do MVVM ser também conhecido como Presentation Instalando o DSharp
Model, na verdade ele é uma implementação específica que uti- O Framework DSharp está disponível para Delphi 2010 e
liza recursos do .NET/WPF como o mecanismo de Binding. Esse superiores. Neste artigo utilizaremos o Delphi XE 2. Após realizar
mecanismo permite ligar qualquer propriedade de um controle o download de seu código fonte (veja seção Links) acessamos
visual a uma propriedade ou método de objetos de negócio. Vários a pasta {pasta_instalação}\Packages\DelphiXE2 e carregamos
Frameworks foram desenvolvidos para explorar esse mecanismo o arquivo BuildPackages.groupproj. Esse arquivo representa o
da melhor forma e, com isso, agilizar a criação de um aplicativo grupo de projetos que compõe o DSharp. Uma vez carregado, a
que faça uso deste padrão. janela Project Manager ficará como na Figura 5.
Sempre que um valor é digitado na View, o mesmo é passa- Listagem 5. Retornando uma mensagem de erro
do por Binding à sua propriedade correspondente, o que por
01 function TEnvioEmailViewModel.GetItem(const AName: string): string;
sua vez dispara o método Set dessa propriedade. Assim que a 02 const
mesma recebe o valor, é disparado o evento DoPropertyChan- 03 Propriedades: array[0..3] of string = (
ged, passando o nome da propriedade em questão. Isso faz 04 ‘Remetente’,
05 ‘Destinatario’,
com o que o Framework de Binding atualize todas as ligações 06 ‘Assunto’,
relacionadas a essa propriedade. E como o objetivo é ir vali- 07 ‘Conteudo’);
dando o estado geral a cada digitação, nós setamos o valor da 08 begin
09 case IndexText(AName, Propriedades) of
propriedade IsValid com o resultado da função Validate. Este 10 0:
é o View Model. 11 begin
Na View, que é nosso formulário, adicionamos em uses uma 12 if not IsValidEmail(Remetente) then
13 Result := ‘Remetente inválido’;
referência à nossa unit EnvioEmailViewModel e criamos um 14 end;
campo privado do tipo do View Model: “FDataContext: TEnvio- 15 1:begin
16 if not IsValidEmail(Destinatario) then
EmailViewModel”; Esse campo será utilizado para realizarmos
17 Result := ‘Destinatário inválido’;
as operações de Binding. Essas operações não serão criadas de 18 end;
forma manual, mas através de código. Adicionamos uma pro- 19 2:begin
20 if Trim(Assunto)=’’ then
cedure ao formulário que centraliza essa rotina, como mostra a
21 Result := ‘Assunto não pode ser vazio’;
Listagem 4. 22 end;
23 3:begin
24 if Trim(Conteudo)=’’ then
Listagem 4. Construindo os bindings 25 Result := ‘O email precisa de um conteúdo’;
26 end;
procedure TEnvioEmailView.ConfiguraBinding; 27 end;
begin 28 end;
BindingGroup1.AddBinding(FDataContext,’Remetente’,Edit1,’ Text’);
BindingGroup1.AddBinding(FDataContext,’Destinatario’,Edit2,’ Text’);
BindingGroup1.AddBinding(FDataContext,’Assunto’,Edit3,’ Text’);
BindingGroup1.AddBinding(FDataContext,’Conteudo’,Memo1,’ Text’);
Esse método é chamado internamente pelo Framework DSharp
BindingGroup1.AddBinding(FDataContext,’IsValid’,Button1,’Enabled’);
end; sempre que uma propriedade envolvida em Binding recebe um
valor. Esse passa no parâmetro o nome da propriedade que está
em uso no momento. Para não criar vários comandos if de for-
O componente TBindingGroup oferece um método simples ma encadeada, foi criado um Array (linha 3) com os nomes das
para criação de Binding, o AddBinding. Nele passamos uma propriedades disponíveis e então, através da função IndexText
instância de objeto que será o Source, seguida de uma String conseguimos localizar a posição dentro do Array do texto que
que é o nome de uma propriedade desse mesmo Source. Deste está vindo como parâmetro. Essa função está disponível na
modo informamos quem será o Target e qual propriedade estará unit StrUtils e foi adicionada na seção implementation. Pode
ligada à propriedade do Source. Veja que a propriedade IsValid ser observado também o uso de uma função chamada IsValid
foi ligada à propriedade Enabled do botão, isso irá controlar o Email, na qual foi implementada para verificar se a String do
botão automaticamente quando preenchemos os campos. Antes valor da propriedade confere com um possível e-mail, ou seja,
de executarmos os exemplo, basta adicionar no evento OnCreate se ela contém um “@” ou um “.com” pelo menos. Inclusive a
do formulário a criação do campo FViewModel e a chamada do função Validate criada anteriormente foi alterada para fazer
método ConfiguraBinding. Feito isso, execute e veja que o botão uso dessa função. Sua implementação completa pode ser vista
só é ativo quando tudo está preenchido. no download do código fonte. Essa é a única alteração realizada
no View Model.
Melhorando a validação Para que o mecanismo de Binding possa detectar a validação
É uma boa prática informar ao usuário o que está inválido. A em uso e mostrar as mensagens de erro, é preciso configurar os
classe TViewModelBase expõe um método que pode ser sobre- Bindings. A Listagem 6 mostra como o método ConfiguraBinding
carregado em nosso View Model para aplicar nossas regras de foi ajustado.
validação e retornar uma mensagem. Como utilizamos Binding, Na linha 3 foi definida uma variável do tipo TBinding, esse é o
essa mensagem pode ser ligada aos Hints dos controles visuais, tipo que o Framework cria quando adicionamos um novo Binding,
ou até mesmo algo mais visual pode ser criado, como a mudança seja via código ou pelo Designer. Como criamos os Bindings por
de cor do próprio campo. código, ele é utilizado para configurarmos opções que só seriam
Para alcançar esse objetivo, a primeira coisa é sobrecarregar no possíveis pelo próprio editor.
View Model o método “GetItem(const AName: string): string”. Na linha 5 criamos o primeiro Binding. O método AddBinding
Isso é visto na Listagem 5. retorna o objeto TBinding recém criado e sua referência fica
Ela deve verificar se, quando temos apenas uma propriedade invá- Nós registramos a existência do caso de teste TTestViewModel.
lida no View Model, o mesmo permanecerá inválido. A Listagem 7 Suite, se houvessem outros, bastaria fazer o mesmo para cada um.
mostra a classe e sua implementação. Agora ao executar projeto de teste vemos sua execução, como pode
ser observado na Figura 11.
Como o caso de teste foi registrado, o DUnit cria uma interface
Listagem 7. Classe de teste
para executar tudo o que está registrado. Observe que o método
01 type TesteRemetenteInvalidoBloqueiaEmail foi marcado automatica-
02 TTesteViewModel = class (TTestCase) mente. Ao clicar em cada teste é possível escolher qual se deseja
03 published
04 procedure TesteRemetenteInvalidoBloqueiaEmail; executar. Execute o teste clicando no botão “play” de cor verde e
05 end; veja o resultado (Figura 12)
06
07 implementation
08
09 { TTesteViewModel }
10
11 uses EnvioEmailViewModel;
12
13 procedure TTesteViewModel.TesteRemetenteInvalidoBloqueiaEmail;
14 var
15 viewModel: TEnvioEmailViewModel;
16 begin
17 viewModel := TEnvioEmailViewModel.Create;
18 viewModel.Remetente := ‘emailnaoformatado’;
19 viewModel.Destinatario := ‘email@ok.com.br’;
20 viewModel.Assunto:= ‘assunto ok’;
21 viewModel.Conteudo := ‘conteudo ok’;
22 CheckFalse(viewModel.IsValid);
23 end;
s
Dê
Um abraço e até mais. A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber
sobre e
o que você, leitor, acha da revista!
s
ta
edição
CodeSite no Delphi XE 2
Depuração e criação de logs
O
desenvolvimento de aplicações é um processo Resumo DevMan
que envolve diversas etapas que se iniciam no
planejamento e seguem até as fases de manu- De que se trata o artigo:
tenção e atualização. Contudo, quando um Software Este artigo demonstra uma importante ferramenta para auxiliar na
começa a receber uma série de recursos e se torna cada depuração das aplicações desenvolvidas no Delphi XE 2, o CodeSite,
vez mais complexo, é comum que erros e outros con- abordando suas principais características, componentes e formas de
tratempos apareçam, embora isto ocorra também em empregá-la no dia-a-dia, com o intuito de ajudar na identificação e
aplicações de pequeno porte. Muitas vezes, as falhas são solução de possíveis falhas de execução, bem como registrar tudo o que
fáceis de serem identificadas e corrigidas, porém, erros ocorre no Software através de arquivos de Log.
difíceis de serem encontrados também fazem parte do
cotidiano da equipe de desenvolvimento. Diante deste Em que situação o tema é útil:
fator, um recurso extremamente comum que é adotado é Agilizar no processo de identificação de erros presentes na aplicação
a depuração (Debug), que pode estar presente na própria que podem ser difíceis de ser encontrados por meio dos métodos
ferramenta de desenvolvimento, através de Softwares de tradicionais de depuração, empregando formas avançadas para este
terceiros ou ainda ser efetuada de forma manual, através processo, visando assim uma maior produtividade para o desenvolvedor
da geração de arquivos de Log ou mensagens. e qualidade para o Software final.
O Delphi conta com uma ferramenta de Debug integra-
da em seu ambiente, que auxilia no processo de análise CodeSite:
e identificação de falhas, onde recursos específicos No ambiente de desenvolvimento de Softwares, os indesejáveis “erros”
como os Breakpoints podem ser utilizados. Todavia, são praticamente inevitáveis, principalmente em casos onde complexas
a identificação de certos tipos de erros pode ser uma rotinas devem ser empregadas. Evidentemente, problemas simples
tarefa demorada, onde surgem diversas dificuldades podem ser resolvidos de uma forma rápida mesmo sem uma avançada
que devem ser consideradas. Dentro deste fator, existe a ferramenta de auxílio, apenas utilizando um depurador básico e o recurso
ferramenta CodeSite desenvolvida pela Raize Software e de breakpoints, revisando o trecho que apresenta o problema, mas nem
que acompanha o Delphi e as outros IDEs do RadStudio sempre este processo é assim. Podem surgir falhas complexas ou erros
desde as versões mais antigas, oferecendo diversas fun- pouco detalhados, fazendo com que o desenvolvedor tenha que revirar a
cionalidades para o recurso de depuração, permitindo aplicação em busca de uma reposta, perdendo muito tempo que poderia
uma análise mais rápida e detalhada do Software para ser empregado em outras tarefas. Diante deste fator, existe uma ferramen-
os desenvolvedores e garantindo assim uma melhor ta que acompanha a suíte de aplicativos do RAD Studio, o CodeSite. Esta
qualidade do mesmo. Através dele, o desenvolvedor ferramenta incorpora a implementação de novas técnicas para auxiliar
pode inserir comandos no código fonte da aplicação na identificação das possíveis falhas, através de métodos e visualizadores
em questão com o intuito de enviar mensagens para as que permitem um monitoramento dos processos em tempo real ou ainda,
ferramentas de visualização que compõem o CodeSite através da gravação de arquivos de Log. Neste artigo serão apresentadas
e assim, poder analisar o comportamento da mesma de formas de gerar informações sobre os processos internos do Software,
uma forma otimizada e no momento em que as ações facilitando assim a identificação de erros, primeiramente adotando um
são executadas, facilitando assim a descoberta de erros. processo manual, através da simples gravação de um arquivo txt e pos-
Este processo pode ser efetuado sem que a execução do teriormente, de uma maneira mais ampla e produtiva, com a utilização
programa seja interrompida, uma vez que traz consigo dos recursos da ferramenta CodeSite.
um novo modelo de depuração, dispensando o uso de
breakpoints, permitindo que logs possam ser gerados
e facilmente consultados para que as prováveis falhas em que as mesmas ocorrem. O sistema de registros do CodeSite é
possam ser identificadas. Vale lembrar que o CodeSite baseado praticamente em três componentes principais, sendo eles
também não se limita a estruturas de dados simples, as classes de Log (Logging Classes), o Dispatcher (despachante)
registrando além dos processos e falhas, o momento e os visualizadores (Viewers). Para o processo de log a classe
é aberto para que a informação possa ser adicionada através do Listagem 3. Código do envento OnClick para a geração do Log manual
método Append, caso contrário, ele é criado através do método
ReWrite. Uma vez que o arquivo está preparado, os dados são procedure TFormLog.btGravarManualClick(Sender: TObject);
var
gravados através de comandos Writeln, onde a data e a hora Qry: TSQLQuery;
atuais são obtidas com a utilização da função Now e formatadas begin
Qry := TSQLQuery.Create(nil);
corretamente de acordo com FormatDateTime, seguidas pela men-
GerarLog(‘Clicou no botão btGravarManual’);
sagem em String que foi passada como parâmetro. Para concluir, a try
associação entre a variável e o arquivo externo é encerrada com o with Qry do
begin
emprego do método CloseFile, que como o próprio nome sugere,
SQLConnection := SQLConnection1;
encerra a abertura do arquivo. SQL.Text := ‘ INSER INTO CLIENTE ‘+
‘ VALUES (1, ‘+
QuotedStr(edNome.Text) + ‘, ‘+
Listagem 2. Procedimento para geração manual de um arquivo de log QuotedStr(edEndereco.Text) + ‘);’;
GerarLog(‘Criou o SQL: ‘+ Copy(SQL.Text, 1, Length(SQL.Text) -1));
procedure TFormLog.GerarLog(Mensagem: string); ExecSQL;
var Close;
ArquivoLog: TextFile; end;
Endereco: string; except
begin on e:Exception do
Endereco := ‘C:\LogSitema.txt’; GerarLog(‘Erro: ‘+ e.Message +’ : ‘+ e.ClassName);
AssignFile(ArquivoLog, Endereco); end;
if FileExists(Endereco) then FreeAndNil(Qry);
Append(ArquivoLog) end;
else
ReWrite(ArquivoLog);
Writeln(ArquivoLog, FormatDateTime(‘dd/mm/yyyy hh:mm:ss’, Now) + ‘: ‘
+ Mensagem); Posteriormente, a Query é executada através do método Exec
CloseFile(ArquivoLog);
end;
SQL. Para concluir, sempre que uma exceção for gerada, com
o auxílio da estrutura try/except, o procedimento GerarLog é
chamado novamente para gravar a mensagem de erro retor-
Com a função responsável por gerar o log manualmente defini- nada (contida em e.Message) com base na classe Excpetion,
da, a próxima etapa é criar o código que receberá a monitoração, finalizando assim o o processo com a liberação do objeto Qry
que neste exemplo foi o evento OnClick para o primeiro botão, da memória.
onde um comando SQL baseado em uma instrução de INSERT foi Como pode ser observado, a geração de arquivos de log
atribuído de forma errada propositalmente para que o registro do manualmente é um processo que permite um bom monitora-
log fosse realizado. Na geração de logs manuais, uma estrutura mento do que é realizado e que pode ser melhorado para obter
muito útil que pode ser empregada para o tratamento das exce- informações mais específicas. Também vale ressaltar que em
ções e evidentemente, seus registros, é o bloco de tratamento de algumas ferramentas de desenvolvimento, o desenvolvedor
exceções “try/except”, já que o mesmo permite determinar um pode enviar mensagens de log diretamente para um console ao
trecho de código que deve ser tratado caso ocorra alguma falha. invés de um arquivo. Todavia, quando falhas mais complexas
Outro ponto que deve ser considerado é com relação aos locais ocorrem, uma ferramenta mais específica deve ser empregada
onde a função será chamada, para que as informações desejadas para que os esforços gastos neste processo sejam eliminados,
ou de maior risco possam ser capturadas. A Listagem 3 apresenta como é o caso do CodeSite.
o código do evento OnClick para o botão btGravarManual.
Neste trecho de código é possível notar que a classe TSQLQuery Logs com o CodeSite
foi empregada para a execução das instruções SQL de forma ma- O mesmo projeto criado anteriormente será adotado, onde a Unit
nual para o Framework dbExpress, sendo assim instanciada para CodeSiteLogging foi incluída na seção Uses do formulário. Para
o objeto Qry. Em seguida, o procedimento GerarLog é chamado fazer um rápido teste e ver o funcionamento da ferramenta, o
para registrar que o clique no botão foi realizado. Posteriormente, código a seguir pode ser atribuído no evento OnClick do segundo
o objeto Qry tem sua propriedade SQLConnection definida para botão inserido (btGravarCodeSite):
indicar qual a conexão que deve ser empregada na execução da
mesma. Na propriedade SQL.Text, utilizada para a definição da CodeSite.Send(‘Clicou no botão btGravarCodeSite’);
instrução SQL, é atribuído um SQL com uma falha (“INSER” no Ao executar a aplicação e clicar no botão btGravarCodeSite, a
lugar de “INSERT”) para que uma exceção seja propositalmente ferramenta CodeSite Live Viewer é carregada automaticamente
gerada, uma vez que este é um erro muito comum de ocorrer. e já exibe a mensagem que foi informada para o método Send. A
Neste momento também é adicionada uma nova linha para o Figura 1 apresenta a janela da ferramenta CodeSite Live Viewer
log, contendo as informações do comando SQL que foi fornecido. com a mensagem retornada.
Classe/Método Descrição
TCodeSiteLogger.AddCheckPoint Incrementa um contador específico para Check points e adiciona uma mensagem de checagem.
TCodeSiteLogger.AddSeparator Adiciona um separador (linha) para uma organização visual do log.
TCodeSiteLogger.CloseDispatcher Encerra a ferramenta Dispatcher.
Utilizado para alterar a conexão com um Dispatcher através do protocolo TCP (Transmission Control Protocol), permi-
TCodeSiteLogger.ConnectUsingTcp
tindo assim um monitoramento remoto.
TCodeSiteLogger.SendIf Envia uma mensagem se uma condição é satisfeita.
TCodeSiteLogger.SendScreenShot Permite o envio de uma imagem de uma janela específica.
Permite o envio das mensagens para um servidor de aplicação baseado no protocolo HTTP (HyperText Transfer
TCodeSiteDestination.HTTP
Protocol).
TCodeSiteDestionation.TCP Permite o envio das mensagens para uma ferramenta Dispatcher remota através do protocolo TCP.
um botão (TSpeedButton) ao formulário principal. A classe que do mesmo, e MaxParts, para o número máximo de arquivos.
permite o gerenciamento de como e onde as mensagens enviadas Também é desativada a visualização através do Live Viewer com a
pelos métodos do CodeSite serão gravadas, é a TCodeSiteDes- subpropriedade Viewer.Active. Posteriormente, o destino padrão
tination. Através dela também é possível definir mais de um (DefaultDestination) do CodeSiteManager é definido com as con-
destino para as mensagens. Outro recurso importante que deve figurações do objeto Destino. Neste momento, o mesmo código
ser empregado neste momento é o CodeSiteManager. Ele tem o apresentado na Listagem 4 pode ser empregado para a geração
objetivo de disponibilizar e gerenciar todas as propriedades para do arquivo de Log. Para concluir, o objeto Destino é liberado da
as instâncias da classe TCodeSiteLogger, sendo então utilizado memória através do procedimento FreeAndNil.
em conjunto com as definições da instância de TCodeSiteDesti-
nation. A Listagem 5 apresenta o código do evento OnClick do Outros recursos da ferramenta CodeSite
botão btGravarCodeSiteLog para a geração de um arquivo de log Além dos recursos que foram apresentados para auxiliar na
diretamente no disco. depuração de uma simples aplicação, o CodeSite também pode
ser empregado para a análise de Threads, onde o método Set-
CurrentThreadName, presente no objeto CodeSiteManager, pode
Listagem 5. Código do envento OnClick para o botão btGravarCodeSiteLog ser empregado para a identificação da Thread em questão. Em
procedure TFormLog.btGravarCodeSiteLogClick(Sender: TObject); conjunto com o mesmo, os métodos apresentados anteriormente
var também podem ser empregados para o registro das ocorrências
Qry: TSQLQuery; de acordo com a necessidade do projeto.
Destino: TCodeSiteDestination;
begin Se por algum motivo o desenvolvedor necessitar enviar da-
Qry := TSQLQuery.Create(nil); dos personalizados para o CodeSite, ele pode criar classes que
Destino := TCodeSiteDestination.Create(nil);
implementem a interface ICodeSiteCustomData, classes que
with Destino.LogFile do
begin derivem de TCodeSiteFormatter ou ainda classes que possuam
Active := True; informações de tipo em tempo de execução usando RTTI (Run
FilePath := ‘C:\’;
Time Type Information), que por sua vez podem ser declaradas
FileName := ‘LogSistema.csl’;
MaxSize := 100; com as diretivas de compilação {$M+} e {$M-} , ou simplesmente
MaxParts := 20; derivadas da classe TPersistent.
end;
Destino.Viewer.Active := False;
O CodeSite também conta com uma diversidade de métodos
CodeSiteManager.DefaultDestination := Destino; que podem ser empregados e que não foram apresentados neste
//Mesmo código da Listagem 4 ... artigo mas que também são úteis. A Tabela 1 demonstra alguns
FreeAndNil(Destino);
end;
dos outros métodos que podem ser empregados.
Conclusão
Neste trecho de código é possível notar que uma instância da No processo de desenvolvimento de um Software, erros de
classe TCodeSiteDestination é criada e atribuída ao objeto Destino execução são uma realidade que fazem parte da rotina do de-
após a devida criação de uma instância da classe TSQLQuery. senvolvedor. No Delphi XE 2, assim como em outras versões, o
Em seguida, são definidas diversas propriedades para o objeto Debugger integrado em conjunto com os Breakpoints, normal-
Destino, sendo elas a Active (True), FilePath, para a definição mente é o processo mais empregado para ajudar na solução dos
do diretório onde será gravado o arquivo de Log, FileName erros do sistema, entretanto, podem surgir ocorrências inespe-
para o nome do arquivo, MaxSize para o tamanho máximo radas muito mais complexas. Se desejar, o desenvolvedor pode
s
Dê
mensagens para o CodeSite Live Viewer ou diretamente para A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber
sobre e
arquivos no disco rígido, contando com diversos recursos para a o que você, leitor, acha da revista!
s
ta
personalização deste processo.
edição
InterBase XE – Parte 1
Conheça este SGBD de alta performance, leve e
escalável da Embarcadero
O
InterBase é o SGBD atualmente desenvolvido, barcadero, mas que esteve fora de pauta por um longo tempo dentro
mantido e comercializado pela Embarcadero, da comunidade, apesar de estar presente no mercado desde seu
a mesma fabricante do Delphi. Como se sabe lançamento inicial há mais de uma década atrás. Por motivos princi-
SGDB é o acrônimo de Sistema de Gerenciamento de palmente relacionados ao crescimento da própria comunidade nos
Banco de dados. Esta denominação é uma referência últimos tempos, novos desenvolvedores talvez não tiveram contato
traduzida do termo em inglês DBMS (Database Ma- com o produto. Sendo assim, o presente artigo remonta a história e faz
nagement System). No entanto, no caso do InterBase, uma apresentação do InterBase, dando um foco maior na versão mais
comumente é utilizada a sigla RDBMS (Relational recente do produto, ao mesmo tempo em que é exposto um pouco de
Database Management System), algo como Sistema de suas principais características onde muitas delas são provindas de seus
Gerenciamento de Banco de Dados Relacional, especifi- releases anteriores.
cando assim sua característica. Adicionalmente, ele é um
sistema bastante convencional e totalmente compatível Em que situação o tema é útil:
com a SQL-92 (ver nota do DevMan 1). Demonstrar as qualidades do banco de dados da Embarcadero, permi-
Partindo de uma comparação inicial com outros tindo assim, acrescentar ainda mais opções para uma importante etapa
SGBDs, o grande atrativo do InterBase fica por conta de do desenvolvimento, a escolha da solução de armazenamento.
seu tamanho enxuto, alto desempenho e quase zero de
requisitos de administração. Em relação a este último, InterBase XE – Parte 1:
significa dizer que o próprio desenvolvedor é capaz de Historicamente falando, como é de conhecimento de muitos, Delphi
administrá-lo (como já acontece em muito dos casos), e InterBase sempre estiveram relacionados. Isso se justifica pelo fato de
extinguindo a necessidade de um profissional especia- ambos sempre serem geridos por uma mesma fabricante, o que resulta
lizado, tal como um administrador de banco de dados inclusive em diversos recursos nativos. Exemplo disso é uma paleta
(DBA). Este cenário de dependência é o que ocorre de componentes exclusiva (IBX) dentro do IDE de desenvolvimento,
corriqueiramente com SGBDs do porte de Microsoft bem como um driver dbExpress otimizado. Apesar de estarem ligados,
SQL Server, Oracle e DB2. No mais, a conectividade o que se percebe no cenário atual é que o Delphi obteve muito mais
do InterBase se estende a vários sistemas operacionais sucesso em termos de visibilidade e usabilidade. O InterBase, por si
diferentes, mais precisamente Windows, MacOS X, só, apesar de ter ficado à sua sombra, sempre esteve no mercado e,
Linux e Solaris. como qualquer produto comercial, foi constantemente melhorado
a cada novo lançamento. Dito isto, este artigo tem a intenção de re-
Um pouco de história tomar o InterBase em meio à comunidade, mostrando um pouco do
Podemos pontuar a década de 90 como o início da estágio atual deste SGBD, fazendo um overview de algumas de suas
história do InterBase, no momento em que a Borland principais características presentes em sua versão mais recente (XE),
estabelecia a aquisição de uma empresa até então pro- sejam elas novas ou integrantes de seu legado. Por se tratar de um
prietária do produto, e que culminou com a inclusão do assunto extenso, o tema será abordado numa série de dois artigos,
InterBase como parte do negócio. Na década seguinte, em onde este primeiro terá como foco a apresentação geral do produto
meados de 2000, a Borland traçou uma estratégia para um em si, deixando para o segundo uma abordagem mais prática, mas
desmembramento que tinha como objetivo determinar não menos conceitual.
uma empresa específica para tomar a frente do produto.
sendo introduzidas, refletindo seus recursos relacionados que com um banco de dados InterBase, foi introduzido o suporte a SQL
foram sendo introduzidos neste caminho. A fim de elucidar um dinâmico em Store Procedures, o que garante uma flexibilidade
pouco deste cenário, podemos citar algumas delas. Por exemplo, anteriormente inexistente ao desenvolvedor. Finalmente, pelo lado
palavras corriqueiras relacionadas a campos, tipos e valores, tais do desempenho, houve uma otimização substancial do manuseio
como BOOLEAN, TIMESTAMP, DAY, MONTH, YEAR, TRUE, de objetos de banco de dados de tamanho considerável (grande),
FALSE, ROWS e EXTRACT foram surgindo com maior intensidade através de métodos Stream elaborados.
até a versão 2007 do produto. Adicionalmente, outras palavras
relacionadas a funções específicas, tais como NULLIF, PRESERVE, Edições do produto
ENCRYPT, DECRYPT e COALESCE ganharam um espaço maior Como todo produto comercial de médio e grande porte, o Inter-
em releases maiores, tal como as versões 7.5, 2009 e XE. Base possui diversas edições, em que cada qual se adéqua a um
determinado tipo de cenário. A seguir será feita uma explanação
de cada uma das edições disponíveis bem como a necessidade
que cada uma visa atender. No mais, servirá inclusive para expor
ao leitor que o produto possui uma versão gratuita, assim como
outros grandes SGBDs conhecidos no mercado, fato este que
certamente soará como uma novidade para muitos.
de criação de uma nova base de dados da versão 7.5 do produto, comando, por meio do utilitário iSQL (isql.exe, presente na basta
lançada em 2004. No detalhe pode ser vista a opção de Embedded Bin de instalação). Para um novo banco de dados, a habilitação
User Authentication já disponível na época. do EUA é feito da seguinte forma:
Falando um pouco mais do EUA, o que este recurso faz é arma- Figura 3. Opção de Embedded User Authentication no InterBase XE
zenar (embutir) o nome de usuário e senha do banco diretamente
no próprio banco de dados, o que acaba por justificar sua nomen- Se comparado a um comando CREATE simples, a diferença
clatura. Consequentemente, esta característica proporciona alguns fica por conta da indicação de WITH ADMIN OPTION. Inter-
ganhos, tais como uma maior proteção da estrutura interna de namente, esta cláusula determina que os dados de usuário e
metadados da base, bem como uma segurança maior no transporte senha do banco sejam criadas em sua própria tabela de sistema
do próprio banco, não podendo ser violada simplesmente pela RDB$USERSsystemTable. De forma similar, para os casos em que
substituição de um arquivo externo. Falando em termos práticos, se deseja habilitar ou revogar o EUA para um banco de dados já
a administração do EUA de uma base de dados se restringe única existente, utiliza-se o comando ALTER, conforme o seguinte:
e exclusivamente ao seu proprietário (Owner), não dependente
de um usuário SYSDBA. Todos os outros eventuais usuários do //habilita o recurso
ALTER DATABASE <nome do banco> ADD ADMIN OPTION
banco só podem alterar sua própria senha.
Além disso, o Embedded User Authentication está estritamente //desabilita o recuso
ligado a outro recurso disponível no InterBase XE, que é o de ALTER DATABASE <nome do banco> DROP ADMIN OPTION
criptografia. Este recurso, conforme já mencionado, permite se
estabelecer uma criptografia em nível de banco (suas páginas Uma vez que o EUA é desabilitado, o acesso ao banco de dados
como um todo), ou mesmo de colunas específicas. Desta maneira, volta ao processo padrão, onde a autenticação é realizada com
o recurso de criptografia só é possível para bancos que estejam base nos dados de usuário que ficam centralizados num banco de
com o EUA habilitado. Em outras palavras, o acesso a bancos dados externo, aqui denominado Admin.ib, similar ao já citado
InterBase criptografados só se torna possível para os usuários security.fdb do Firebird.
quando sua opção de EUA estiver definida como True. Da mesma
forma que foi mostrada anteriormente, com o InterBase 7.5, na Bancos de dados multiarquivos
versão XE do produto esta opção fica disponível no momento O InterBase oferece suporte ainda a bancos de dados multi-
da criação de um novo banco de dados (Figura 3). arquivos (incluindo arquivos de sistema), recurso este também
A forma vista para se habilitar o EUA para uma base de dados, se conhecido como Multifile Databases e que provê a adição de
deu através da utilização da ferramenta administrativa IBConsole, arquivos adicionais a um banco de dados. Citando a versão mais
que acompanha a instalação do InterBase. Esta, sem dúvida, é a recente (XE) do produto, a definição de um banco multi-arquivos,
forma mais trivial de se habilitar o recurso. Contudo, opcional- partindo de um já existente, se dá através de um processo de
mente, esta definição também pode ser feita através de linha de Backup/Restore, via Database Restore da ferramenta IBConsole
de banco é pré-alocada nativamente. Do contrário, isto poderia A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber
sobre e
causar algum transtorno ou desperdício, em situações em que o que você, leitor, acha da revista!
s
ta
edição
não haja a necessidade de reserva de espaço na base. Dê seu voto sobre este artigo, através do link:
Devido a uma falha humana, por exemplo, caso a definição do
www.devmedia.com.br/clubedelphi/feedback
recurso de Preallocate exceda o próprio espaço disponível em
Trabalhando com
Streams e Threads
Crie um gerenciador de downloads
A Resumo DevMan
informação é um fator extremamente im-
portante para todos em qualquer contexto,
seja na informática, nos relacionamentos, De que se trata o artigo:
estudo, trabalho, etc. No ambiente computacional e, Este artigo aborda a utilização de Streams, sequências de bytes
mais especificamente, dentro do desenvolvimento de criados na memória que podem ser empregados para ler, gravar e
Software existem vários meios para a manipulação das copiar informações, oferecendo recursos adicionais para a manipu-
informações, que podem ser simples através de uma lação dos dados, apresentando também uma forma de empregá-los
rápida e objetiva função, ou mais complexas, onde de- na elaboração de uma simples ferramenta de gerenciamento de
mandam maiores recursos. Outro fator importante é Downloads em segmentos, baseada em Threads, que permitem a
com relação à troca das informações entre as entidades execução de tarefas em paralelo.
envolvidas, como é o caso das redes e em especial, a
Internet, onde mecanismos devem ser implementados Em que situação o tema é útil:
para que todo o processo ocorra de forma satisfatória. Manipular informações em nível de bytes, podendo copiar arqui-
A comunicação no ambiente computacional tem como vos ou dados de uma forma direta ou mais elaborada, podendo
um de seus pilares os protocolos, onde o TCP (Transfer ainda “recortar” tais dados e empregar o conceito de concorrência
Control Protocol) merece ser evidenciado, uma vez que nos projetos através da utilização de Threads.
fornece a garantia de que as informações serão devi-
damente entregues ao seu destinatário, porém, além Streams:
deste, uma variedade de tecnologias podem ser em- A informação é um dos pilares no ambiente computacional. Todos
pregadas quando surge a necessidade de executar uma os dias, mais e mais dados são lidos, copiados e compartilhados
tarefa mais específica, como é o caso da transferência entre os usuários. Ter à disposição um mecanismo capaz de oferecer
de um arquivo binário por exemplo. Um recurso que diversos recursos para a manipulação das mais variadas informa-
pode ser adotado para a manipulação e transferência ções, torna-se algo essencial em grande parte das aplicações, e
de informações de uma forma mais ampla é o Stream. uma tecnologia que pode ser empregada para este fim é o Stream.
Este pode ser resumido como um fluxo de dados pre- Ele pode ser resumido como uma sequência de bytes presente na
sente na memória, que tem um início e um fim, sendo memória, que oferece ao desenvolvedor a possibilidade de copiar,
constituído por uma sequência de bytes, permitindo ler e gravar as informações, enviando-as para um destino desejado,
que a aplicação possa percorrer tais dados obtendo que pode ser outro Stream ou um meio físico de armazenamento,
informações como tamanho, por exemplo, tendo um como o HD. Sendo assim, a aplicação pode “quebrar” arquivos
funcionamento semelhante ao processo de navegação binários e posteriormente, reuni-los novamente, como é o caso de
pelos registros de um DataSet. Além disso, os Streams um Software gerenciador de Downloads. O Delphi conta com uma
podem ser utilizados para manipular uma diversida- variedade de classes que podem ser empregadas para as mais diver-
de de tipos de dados, como imagens, áudio, binários, sas tarefas empregando Streams, que por sua vez possuem muitos
textos e assim por diante, bem como ter seu tamanho métodos importantes. Neste artigo, serão apresentadas as classes
estendido até os limites disponíveis e permitidos pela básicas para a utilização deste recurso, empregando técnicas para
memória física. dividir um arquivo qualquer em três partes sem corrompê-lo e
No cenário de Streams é muito comum ouvir o assim efetuar o Download do mesmo paralelamente, recorrendo
termo Streaming. Como é uma palavra inglesa no também ao uso de Threads.
gerúndio, indica que é uma ação que está ocorrendo,
Classe Descrição
TFileStream Destinada à manipulação de arquivos, permitindo que as aplicações possam ler e gravar os mesmos em um meio físico.
TMemoryStream Empregada para a manipulação de dados na memória dinâmica, capacitada também a oferecer recursos de I/O (Entrada e Saída).
TStringStream Destinada à manipulação de Strings, oferecendo recursos de I/O e permitindo a gravação das informações diretamente para um meio físico.
TOleStream Utilizada para interagir com uma interface COM para escrita e leitura de um objeto OLE.
TBlobStream Empregada em manipulações com campos do tipo BLOB, ou em outras palavras, grandes objetos do tipo binário.
TWinSocketStream Utilizada para escrever e ler informações através de uma conexão de soquete (Socket).
THandleStream Destina-se à leitura e gravação de soquetes, arquivos, entre outros, empregando um identificador (Handle).
Método Descrição
O método construtor deve ser utilizado para a criação de uma instância da classe em questão. Na classe TFileStream, alguns parâmetros podem
Create
ser especificados, tais como o fmCreate, indicando que o arquivo deve ser criado ou substituído.
SetSize Permite a definição do tamanho (Bytes) de um Stream.
Read Utilizado para a leitura dos dados de um Stream para um Buffer, retornando o número de Bytes lidos.
Write Utilizado para a escrita de dados presentes em um buffer para um Stream, retornando o número de Bytes gravados.
Seek Define a posição atual para um Stream, permitindo assim se mover pelo mesmo.
CopyFrom Empregado para copiar os dados de um Stream para outro de uma forma simples.
ReadBuffer Efetua a leitura dos dados de Stream para um Buffer.
WriteBuffer Efetua a gravação dos dados de Stream para um Buffer.
Método/Propriedade Descrição
O método construtor, responsável pela criação de uma instância da classe que pode ser estendido para se adaptar as necessidades do projeto.
Create Neste momento, também se define se a Thread deve ser imediatamente inicializada, através do parâmetro de entrada CreateSuspended do
tipo Boolean.
Se no momento da criação da Thread o parâmetro CreateSuspended foi definido como verdadeiro (Create(True)), então este método pode ser
Resume
utilizado para que a Thread inicie sua execução no instante em que é chamado.
É o método que deve conter o código que será executado pela Thread, onde a propriedade Terminated pode ser verificada para constatar se a
Execute
execução da Thread foi concluída.
Suspend Uma vez que a Thread esteja em execução, este método permite que a mesma seja pausada, podendo sua execução ser iniciada posteriormente.
Este método tem o objetivo de sincronizar a Thread em questão com a Thread principal da aplicação, efetuando uma chamada a determinado
Synchronize
procedimento externo. Convém empregá-lo toda vez que é efetuada uma chamada a um método que não faz parte da Thread.
OnTerminate Este método é chamado no momento em que a Thread é finalizada.
Terminate Este método encerra a execução da Thread em questão.
Esta propriedade permite a definição de um nível de prioridade para a execução da Thread em relação a outras Threads que estão sendo
Priority
executadas, onde quanto maior o nível, maior o tempo de processamento dedicado a mesma.
Permite que o objeto instanciado da classe TThread em questão seja liberado da memória assim que for encerrado, caso seu valor seja definido
FreeOnTerminate
como verdadeiro.
Após a definição dos métodos WorkBegin e Work, resta também que será efetuado o Download, tal como o tamanho total do
a definição do WorkEnd, que por sua vez é executado no encer- mesmo, entre outras.
ramento do Download através de um objeto do tipo TIdHTTP.
A Listagem 5 apresenta o código empregado para o método Listagem 6. Método Execute classe TDownloadThread
WorkEnd da classe TDownloadThread.
01 procedure TDownloadThread.Execute;
02 begin
03 FIndyHTTP := TIdHTTP.Create(FFormulario);
Listagem 4. Método Work da classe TDownloadThread
04 try
05 with FIndyHTTP do
01 procedure TDownloadThread.Work(ASender: TObject;
06 begin
AWorkMode: TWorkMode; AWorkCount: Int64);
07 OnWorkBegin := WorkBegin;
02 var
08 OnWork := Work;
03 Porcentagem: Integer;
09 OnWorkEnd := WorkEnd;
04 Descricao: string;
10 Head(FArquivoDownload);
05 begin
11 HandleRedirects := True;
06 Porcentagem := Trunc((AWorkCount/FLimiteDownload)*100);
12 end;
07 Descricao := IntToStr(FInicio) + ‘-’ + IntToStr(FInicio + FLimiteDownload) + ‘ / ‘ +
13 FTamanhoTotal := FIndyHTTP.Response.ContentLength;
08 IntToStr(Porcentagem) + ‘%’;
14 if not Pos(‘bytes’, FIndyHTTP.Response.AcceptRanges) > 0 then
09 if FOrdemParte = 1 then
15 raise Exception.Create(‘Segmentação não aceita para este download!’);
10 begin
16 FLimiteDownload := FTamanhoTotal div FTotalPartes;
11 FFormulario.ProgressBar1.Position := Porcentagem;
17 FInicio := FLimiteDownload * (FOrdemParte - 1);
12 FFormulario.Label1.Caption := Descricao;
18 if FOrdemParte = FTotalPartes then
13 end
19 Inc(FLimiteDownload, FTamanhoTotal mod FTotalPartes);
14 else if FOrdemParte = 2 then
20 FStreamMemoria := TMemoryStream.Create;
15 begin
21 FStreamMemoria.Position := FInicio;
16 FFormulario.ProgressBar2.Position := Porcentagem;
22 with FIndyHTTP do
17 FFormulario.Label2.Caption := Descricao;
23 begin
18 end
24 Request.ContentRangeStart := FInicio;
19 else if FOrdemParte = 3 then
25 Request.ContentRangeEnd := FInicio + FLimiteDownload;
20 begin
26 Request.Range := Format(‘%d-%d’,[FInicio,FInicio + FLimiteDownload]);
21 FFormulario.ProgressBar3.Position := Porcentagem;
27 end;
22 FFormulario.Label3.Caption := Descricao;
28 FIndyHTTP.Get(FArquivoDownload, FStreamMemoria);
23 end;
29 FStreamMemoria.Size := FInicio + FLimiteDownload;
24 end;
30 FStreamMemoria.Position := FInicio;
31 FreeOnTerminate := True;
Listagem 5. Método WorkEnd da classe TDownloadThread
32 Synchronize(FFormulario.ConclusaoProcesso);
33 finally
procedure TDownloadThread.WorkEnd(ASender: TObject;
34 FIndyHTTP.Disconnect;
AWorkMode: TWorkMode);
35 FIndyHTTP.Free;
begin
36 end;
if FOrdemParte = 1 then
37 end;
FFormulario.ProgressBar1.Position := 100
else if FOrdemParte = 2 then
FFormulario.ProgressBar2.Position := 100
else if FOrdemParte = 3 then A propriedade HandleRedirects é definida como verdadeiro
FFormulario.ProgressBar3.Position := 100;
end;
para a manipulação automática de redirecionamentos de URL
pelo objeto FIndyHTTP, caso ocorram. Em seguida na linha 13,
a propriedade FTamanhoTotal recebe a informação presente
Este simples método é utilizado para garantir e definir o valor na propriedade Response.ContentLength, que por sua vez foi
final (100) para as barras de progresso também de acordo com adquirida com a utilização do método Head e assim, armazena
a propriedade FOrdemParte da Thread em questão. o tamanho total do arquivo que será efetuado o Download. Um
Com a criação de alguns métodos auxiliares, a próxima etapa ponto importante neste momento é saber se a segmentação é
é definir o método principal de TDownloadThread, o método permitida para a origem do Download, onde a não utilização
Execute. A Listagem 6 apresenta seu código. deste teste poderia ocasionar uma falha durante o processo de
O primeiro passo deste método é a criação de uma instância segmentação. Este teste pode ser efetuado através da função
da classe TIdHTTP (linha 3), que por sua vez foi atribuída Pos (linha 14), verificando se consta no retorno presente em
ao objeto FIndyHTTP. Em seguida, são definidas algumas Response.AcceptRanges, os caracteres “Bytes”, indicando que
propriedades para o mesmo, para o correto funcionamento podem ser especificadas faixas (segmentos) para o processo
do processo de Download (linhas 5-12). Primeiramente, são de Download, e caso não sejam encontrados tais caracteres,
atribuídos os eventos, OnWorkBegin, OnWork e OnWorkEnd uma exceção é gerada com uma mensagem para abortar a
para os devidos métodos criados anteriormente, WorkBegin, execução. Uma vez que a segmentação pode ser empregada, a
Work e WorkEnd. Posteriormente, o método Head do objeto propriedade FLimiteDownload recebe o resultado da divisão
FIndyHTTP é utilizado para obter informações do arquivo do tamanho total pelo total de partes (FTamanhoTotal div
A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber
sobre e
e o total de partes.
o que você, leitor, acha da revista!
Neste momento, a aplicação de exemplo para Download de
s
ta
edição
arquivos de forma segmentada está concluída. A Figura 1 apre- Dê seu voto sobre este artigo, através do link:
senta o visual final da aplicação efetuando o Download de um www.devmedia.com.br/clubedelphi/feedback
executável através da Internet.
Desenvolvendo para
Android – Parte 4
RadPHP e Delphi XE 2
Este artigo faz parte de um curso Resumo DevMan
De que se trata o artigo:
Esta quarta e última parte deste minicurso tem o objetivo de concluir
o desenvolvimento do Servidor de Aplicação DataSnap e o Software
Cliente (Web Application) que será exportado para a plataforma Android,
utilizando as ferramentas Delphi XE 2 e RadPHP XE 2, tendo seu desen-
volvimento baseado no Framework jQuery.
N
os artigos anteriores deste minicurso foram
abordados todos os recursos necessários para o Em que situação o tema é útil:
desenvolvimento de um conjunto de aplicações Elaborar rapidamente um simples Software para a plataforma Web
para prover funcionalidades para a plataforma móvel e Android empregando tecnologias WebStandards (HTML, CSS e Java
baseada em Android, tais como o Servidor de Aplicação Script), apresentando formas de se beneficiar com os vários recursos dos
DataSnap, as tecnologias REST (Representational State Frameworks jQuery e jQM (jQueryMobile).
Transfer), HTML (HyperText Markup Language), CSS
(Cascading Style Sheets), JavaScript e a PhoneGap. Nesta Desenvolvendo para Android :
etapa final da aplicação móvel, iniciada no terceiro arti- Em meio à grande e ascendente popularidade dos dispositivos móveis,
go, serão necessárias as inclusões de dois novos métodos a criação de aplicações para tais dispositivos se torna uma ótima opção
para o Servidor de Aplicação DataSnap com o intuito de para os desenvolvedores que querem inovar e entrar para um novo nicho
disponibilizar remotamente os serviços restantes que de mercado. O RAD Studio XE 2 conta com uma gana de ferramentas que
ainda não foram implementados, tais como a obtenção permitem a elaboração de aplicações para os mais variados Sistemas Ope-
dos itens e a efetivação de uma venda, bem como novas racionais, assim como o Android, através do RadPHP. Nesta última parte
funções na aplicação móvel Android, elaborada com a deste minicurso, o servidor DataSnap e a aplicação cliente apresentados
ferramenta RadPHP XE 2 e a API PhoneGap, que por sua anteriormente, receberão novos métodos e ambos os Softwares serão
vez permite o emprego das tecnologias padrões da Web finalizados. Para concluir, o projeto será exportado para o emulador ou
(WebStandards) para o desenvolvimento de aplicações um dispositivo real baseado no sistema Android, através do assistente
híbridas nativas destinadas a plataforma móvel. de exportação que utiliza a API PhoneGap, que por sua vez é compatível
Como também mencionado nos artigos anteriores, com diversos sistemas operacionais.
os Frameworks jQuery e jQM (jQueryMobile) foram
adotados como a base para o funcionamento de toda a
Aplicação Cliente deste projeto. Vale à pena lembrar que
a jQuery é uma biblioteca livre, composta por uma diver-
sidade de funções que agilizam e simplificam o desen-
Tutorial
volvimento de documentos HTML e consequentemente,
a elaboração de aplicações destinadas ao ambiente Web.
Com relação à jQM, ela é uma extensão da jQuery que Novos métodos para o Servidor Datasnap
tem como alvo a plataforma móvel, contendo outras fun- Em ambientes heterogêneos, um importante recurso que pode ser
cionalidades mais especificas, assim como componentes empregado para a centralização das regras de negócio da organiza-
visuais característicos desta plataforma. ção é o Servidor de Aplicação DataSnap. Através deste, a instituição
classe, integrante do Framework dbExpress, permite que instruções CREATE TABLE VENDA (
SQL ou procedimentos armazenados possam ser executados, onde CODIGO INTEGER NOT NULL,
a classe TDBXCommandTypes também deve ser utilizada para que CODIGOCLIENTE INTEGER,
DATA DATE,
o tipo do comando possa ser definido, salientando que o mesmo VENDEDOR VARCHAR(30),
deve trabalhar em conjunto com uma conexão (TSQLConnection). TOTALVENDA NUMERIC(9,2),
Outro ponto importante é que um objeto do tipo TDBXCommand FORMAPGTO VARCHAR(5),
EFETIVADA VARCHAR(1)
tem seu valor padrão retornado do tipo TDBXReader, que por );
sua vez é um leitor unidirecional para os registros de uma tabela
Listagem 3. Código SQL da tabela VENDAITENS
do banco de dados. A Listagem 1 apresenta o código do método
GetItens que é baseado no objeto TDBXCommand. CREATE TABLE VENDAITENS (
Nesta função, o resultado retornado é do tipo TDBXReader, CODIGOVENDA INTEGER NOT NULL,
CODIGOITEM INTEGER NOT NULL,
que dentro deste contexto, é automaticamente convertido em um QUANTIDADE NUMERIC(9,3),
documento baseado na notação JSON (JavaScript Object Nota- VALORVENDA NUMERIC(9,2),
tion), lembrando que tal notação é o padrão para a definição de SUBTOTAL NUMERIC(9,2)
);
objetos na linguagem JavaScript e é adotado neste minicurso para ALTER TABLE VENDAITENS ADD CONSTRAINT PKY_VENDAITENS
a transferência de informações entre o Servidor e a Aplicação PRIMARY KEY (CODIGOVENDA, CODIGOITEM);
Cliente através do protocolo HTTP. Posteriormente, é efetuado ALTER TABLE VENDAITENS ADD CONSTRAINT FKY_VI_ITEM
FOREIGN KEY (CODIGOITEM) REFERENCES
um comando Trim no parâmetro Descricao para limpar espaços ITEM (CODIGO) ON UPDATE CASCADE;
desnecessários e verificar se algo foi preenchido, o que implica ALTER TABLE VENDAITENS ADD CONSTRAINT FKY_VI_VENDA
na elaboração de um filtro baseado na instrução SQL LIKE. Em FOREIGN KEY (CODIGOVENDA) REFERENCES VENDA (CODIGO)
ON UPDATE CASCADE;
seguida, o comando é criado para o objeto de conexão SQLCon-
nection1 através da função DBXConnection.CreateCommand e
seu tipo é definido como SQL, conforme a utilização de TDBX- Com as tabelas devidamente criadas, a próxima etapa é elabo-
CommandTypes.DbxSQL. A propriedade Text do objeto TDBX- rar a função responsável pela venda no servidor de aplicação.
Command é atribuída com todas as instruções SQL para que a A Listagem 4 apresenta o código da função InserirVenda, que
consulta de itens possa ser efetuada. Também é verificado se o por sua vez, deve ser adicionada ao módulo ServerMethods1 do
objeto está pronto (através de .IsPrepared) e, caso não esteja, o projeto.
mesmo é preparado através do método Prepare. Para concluir, é Nesta função, o resultado retornado é do tipo Boolean, indi-
efetuada a execução das instruções SQL através de ExecuteQuery cando se a venda foi efetuada corretamente. Em um primeiro
e o resultado é atribuído para o retorno da função. momento, é criada uma variável do tipo TSQLQuery, uma classe
do Framework dbExpress para efetuar comandos baseados em cliente para este exemplo. É possível observar que a função Int-
SQL no banco de dados, tais como consultas. Também é decla- ToStr é utilizada para converter um inteiro para String já que o
rada uma variável do tipo TDBXTransaction. Esta última classe comando SQL deve ser informado como texto. Obtido o valor do
permite definir o início de uma transação, seu tipo e consequen- item vendido com a abertura da query (Open) e seu armazena-
temente, confirmar todo o processo (Commit) ou possibilita o mento em uma variável, é calculado o total da venda de acordo
cancelamento da operação (Rollback). Vale à pena salientar que com a quantidade informada (Linha 15). Posteriormente, o mesmo
uma transação é um processo de tudo ou nada, onde todos os objeto (Qry) é utilizado para gravar a venda no banco de dados,
comandos contidos entre o início e o fim da mesma devem ser através da instrução SQL de INSERT (Linha 21). Em conjunto com o
executados de forma satisfatória ou nenhum deve ser efetuado, mesmo são utilizadas algumas funções importantes para auxiliar
desfazendo as alterações até então. Declarada todas as variáveis, neste processo. A primeira é a QuotedStr, cujo objetivo é adicionar
a classe TSQLQuery é instanciada. A variável CodigoVenda tem os caracteres de aspa simples (‘’) na String informada, essenciais
seu valor definido através da função GetNovoCodigo, apresentada para a manipulação deste tipo de dado no banco. A função For-
na segunda parte deste minicurso, cujo o intuito é simplesmente matDateTime também é utilizada para alterar o formato da data
obter o último valor inteiro de determinado campo de uma tabela (yyyy-mm-dd / ano-mes-dia) para o formato correto a ser gra-
(MAX) e incrementá-lo, gerando assim um novo código sequencial vado no banco de dados, tendo seu valor retornado como String.
para a chave primária. Uma vez que várias instruções SQL serão Para concluir, também é empregada a função StringReplace, que
executadas em série, a transação é iniciada através do comando substitui determinados caracteres por outros, para a formatação
SQLConnection1.BeginTransaction, onde seu tipo é passado como e gravação de um campo do tipo Float, uma vez que o mesmo foi
parâmetro (TDBXIsolations.ReadCommitted) conforme pode ser convertido em String. A instrução SQL montada com estas carac-
visto na Linha 10. terísticas concentra-se na Linha 21. Continuando a explanação da
Posteriormente, são definidas as propriedades do objeto TSQL- listagem, a próxima etapa é gravar o item vendido de acordo com
Query (Qry), como a conexão e o primeiro comando SQL que será a venda, na tabela VendaItens, onde o código da venda é infor-
executado através da propriedade Text, que neste processo tem mado e a função StringReplace é novamente utilizada. Desta vez
o objetivo de obter o valor do item que foi vendido, uma vez que é criada uma instrução SQL de UPDATE na tabela de itens com
não será permitida a alteração do valor do mesmo pela aplicação o intuito de atualizar o estoque, uma vez que o item tenha sido
Figura 1. Painel referente ao Menu Elaboradas as telas necessárias para que a venda seja efetuada
corretamente, será criado um novo objeto através da linguagem
Após a atualização da tela de menu, o próximo passo é criar duas JavaScript utilizando Object Literals, para auxiliar na gravação das
novas telas (painéis) para a realização da venda. A Primeira tem o informações da venda atual. Este recurso permite a concepção de
intuito de efetuar uma filtragem inicial para as informações que objetos, suas propriedades e valores de uma forma bem simpli-
farão parte da venda, minimizando assim o tamanho da informa- ficada. A Listagem 5 apresenta o código do objeto denominado
ção que será enviada como retorno, e a segunda, com o objetivo “vendaatual”, que por sua vez, deve ser inserido logo após o objeto
de permitir ao vendedor selecionar a pessoa e o item, informando criado anteriormente para este projeto, denominado “conexao”,
também a quantidade, bem como a possibilidade de confirmar ou presente na Tag HTML <script>.
cancelar a venda. No primeiro painel foram inseridos 3 Labels, 2 Ao analisar o código é possível notar que as propriedades do
MEdits e 1 MButton. A Figura 2 apresenta o visual final do painel mesmo servem para armazenar os dados da pessoa e do item
da tela de filtragem. atual que será vendido através da Aplicação Cliente, auxiliando
O painel referente a segunda tela terá dois componentes do tipo assim o processo da venda.
MComboBox, presente na aba jQueryMobile, que por sua vez A próxima etapa é iniciar o desenvolvimento dos códigos dos
também possui um visual característico do ambiente móvel. novos métodos para as telas e objetos criados anteriormente.
Um ponto importante que deve ser ressaltado é com relação Como o Framework jQuery foi utilizado como o “motor” principal
ao documento HTML que será gerado, onde este MComboBox é deste projeto, todos os códigos à partir deste momento devem ser
inseridos no bloco criado no artigo anterior, jQuery(document). os dados retornados pelo servidor de aplicação. A Listagem 7
ready, para o correto funcionamento, uma vez que este código é apresenta o código do botão “btnProsseguir”, presente no painel
executado e monitorado quando o documento HTML é devida- “mpInserirVenda”.
mente carregado, ou também utilizando o método da jQM que tra-
balha de forma semelhante, jQuery(document).bind(“mobileinit”, Listagem 7. Código do evento click do botão btnProsseguir
function($){...}). O primeiro botão que teve seu evento “click”
definido foi o btnIniciarVenda, cujo intuito é apenas carregar a 01 $(‘#btnProsseguir’).click(function() {
02 var Parametro = $(‘#edtPesNome’).val();
tela de pré-filtragem das informações. A Listagem 6 demonstra 03 var Parametro2 = $(‘#edtPesItem’).val();
o código responsável pela manipulação do evento click do botão 04 Parametro = Parametro.toUpperCase() +’/’;
“btnIniciarVenda”. 05 Parametro2 = Parametro2.toUpperCase() +’/’;
06 var Uri = ‘http://’ + conexao.ip + ‘:’ + conexao.porta +
07 conexao.path + conexao.servicos[1] + Parametro;
08 var UriItens = ‘http://’ + conexao.ip + ‘:’ + conexao.porta +
Listagem 5. Declaração do objeto vendaatual
09 conexao.path + conexao.servicos[3] + Parametro2;
10 $.getJSON(Uri, function(pessoas) {
var vendaatual = {
11 $(‘#cbxPessoas’).empty();
pessoacodigo: ‘’,
12 $.each(pessoas.result[0].CODIGO, function(pos, codigo) {
pessoanome: ‘’,
13 $(‘#cbxPessoas’).append(‘<option value=”’+
itemcodigo: ‘’,
14 pessoas.result[0].CODIGO[pos] + ‘”>’ +
itemdescricao: ‘’,
15 pessoas.result[0].CODIGO[pos] + ‘-’ +
itemvalor: ‘’
16 pessoas.result[0].NOME[pos] + ‘</option>’);
}
17 });
Listagem 6. Código do evento click do botão btnIniciarVenda 18 $(‘#cbxPessoas’).selectmenu(‘refresh’);
19 });
$(‘#btnIniciarVenda’).click(function() { 20 $.getJSON(UriItens, function(itens) {
Mudar($(‘#mpMenu’),$(‘#mpIniciarVenda’)); 21 $(‘#cbxItens’).empty();
return false; 22 $.each(itens.result[0].CODIGO, function(pos, codigo) {
}); 23 $(‘#cbxItens’).append(‘<option value=”’ +
24 itens.result[0].CODIGO[pos] +’”>’+
25 itens.result[0].CODIGO[pos] + ‘-’ +
26 itens.result[0].DESCRICAO[pos] + ‘-’ +
Em um documento HTML é uma boa prática definir a proprie- 27 itens.result[0].VALORVENDA[pos] + ‘</option>’);
dade “id” para cada elemento que faz parte do mesmo com o 28 });
29 $(‘#cbxItens’).selectmenu(‘refresh’);
intuito de informar um identificador para tal objeto, facilitando o 30 });
acesso direto a ele através da linguagem JavaScript por exemplo, 31 $(‘#cbxPessoas’).change(function() {
32 vendaatual.pessoacodigo = $(‘#cbxPessoas’).val();
entretanto, existem outras formas de acessar tal componente sem
33 });
ser por esta propriedade, utilizando o array de elementos que 34 $(‘#cbxItens’).change(function() {
é criado automaticamente para os objetos. Como o Framework 35 vendaatual.itemcodigo = $(‘#cbxItens’).val();
36 });
adotado para este projeto é a jQuery, um elemento pode ser
37 $(‘#edtQtde’).val(‘’);
facilmente acessado pela sua propriedade “id” simplesmente 38 Mudar($(‘#mpIniciarVenda’),$(‘#mpVenda’));
ao utilizar o comando $(‘’), como é o caso do botão deste trecho 39 return false;
40 });
de código, $(‘btnIniciarVenda’), porém o valor definido para
a identificação do objeto deve ser precedido do caractere “#”.
Também é possível notar que o evento click para o mesmo é No início deste trecho de código, nas linhas 1 e 2, são criadas
manipulado, cuja função neste trecho é chamar o método criado duas variáveis, Parametro e Parametro2, que recebem os valores
anteriormente, “Mudar”, para que a troca entre as telas possa ser presentes nos respectivos objetos do tipo MEdit, utilizando os
realizada, lembrando que o primeiro parâmetro obtido através identificadores dos mesmos (id) e os recursos do Framework
do id, mpMenu, é o painel que será ocultado, e o segundo, mpIni- jQuery, assim como o método val, cuja função é obter ou atribuir
ciarVenda, é o painel que será exibido. Vale a pena ressaltar que a um valor a determinado objeto. Em seguida, através da função
jQM também possui uma forma de definir várias subpáginas em toUpperCase, as informações das variáveis são convertidas para
apenas uma, através do atributo data-role, possuindo inclusive maiúsculo. Posteriormente, são criadas duas novas variáveis, Uri
animações, porém, que não foram adotadas para este exemplo. e UriItens (linhas 6 e 8), cujo objetivo é a elaboração das URIs que
Para concluir, o método return false é utilizado para que não serão utilizadas para o acesso ao servidor de aplicação, obtendo
seja efetuada a ação padrão que é adotada quando um clique também as informações que foram definidas anteriormente com
em um botão é realizado, uma vez que isso poderia ocasionar o o objeto “conexao”. O Framework jQuery possui diversos métodos
recarregamento do documento HTML. úteis e que podem ser utilizados rapidamente, como é o caso do get
O próximo botão que terá seu código desenvolvido é o btn- JSON. Esta função se assemelha ao método ajax deste framework.
Prosseguir, cujo intuito é ajudar na filtragem das informações Ela utiliza o HTTP GET e é destinada a obtenção de documen-
e preencher os objetos que fazem parte da tela de vendas com tos baseados na notação JSON, podendo criar automaticamente
novamente através do método Mudar (linha 23) e também é efe- Configurações>Aplicações>Desenvolvimento no menu principal
tuado o return false. do aparelho, deve ser ativada. Concluída esta etapa, a aplicação
Como pode ser observado, a Aplicação Cliente pode ser com- é devidamente criada e enviada para o alvo selecionado e pode
pletamente e facilmente desenvolvida baseada nos recursos dos ser executada. A Figura 5 apresenta a aplicação cliente DataSnap
Frameworks jQuery e jQM. Outro ponto extremamente importante executando no emulador do sistema Android, com a tela de ven-
que deve ser observado é com relação aos navegadores que serão das aberta contendo alguns itens e pessoas cadastrados para os
utilizados para o processo de Deploy da Aplicação Cliente du- testes. Como foi possível observar, a exportação do projeto para o
rante o período de testes, pois os mesmos podem barrar o correto emulador ou um dispositivo físico é um processo simples e muito
funcionamento dos métodos devido as suas configurações de rápido através do assistente da ferramenta RadPHP XE 2.
segurança. O navegador utilizado para este projeto foi o Google
Chrome, contudo o mesmo deve ser carregado com a segurança
desabilitada para a Web. Para tanto, basta selecionar o atalho do Nota do DevMan
navegador, clicar com o botão direto sobre o mesmo e acessar a
opção Propriedades. O comando “disable-web-security” deve ser O URI (Uniform Resource Identifier – Identificador Uniforme de Recurso) é utilizado para identificar
adicionado no final do campo Destino, que por sua vez contém o determinado recurso disponível em uma rede tal como a Internet, sendo composto pelo protocolo,
como é o caso do HTTP, e uma sequencia de caracteres (String).
endereço do executável do Chrome, permitindo assim que todos
os métodos apresentados funcionem corretamente.
s
Dê
É Analista Desenvolvedor da Sygnux Software (www.sygnux.com.br) A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber
sobre e
localizada em Monte Alto/SP, atuando também com desenvolvimento o que você, leitor, acha da revista!
s
ta
Web e Android. Formado pela Fatec/TQ, começou a desenvolver com Delphi
edição
dbExpress de A a Z –
Parte 3
Recursos avançados
Este artigo faz parte de um curso Resumo DevMan
De que se trata o artigo:
Na terceira parte deste curso demonstraremos os recursos avançados
O
Framework dbExpress é a forma mais simples e introduzidos no DBX Framework. Estes recursos permitem manipular
transparente de acesso a dados que o Delphi pos- facilmente informações de estrutura, permitindo utilizar o próprio
sui, através dela já é possível executar diversos Framework para a construção de outras soluções que podem inclusive
comandos desde o CRUD básico (inserção, atualização, derivar ferramentas de ORM (Object Relational Mapping).
exclusão e seleção – ver Nota do DevMan 1), até mesmo a
manipulação de dados, execução de Procedures, manipu- Em que situação o tema é útil:
lação de Views, e quaisquer outros recursos que o banco Manipular uma grande quantidade de dados através do Delphi, manter
nos ofereça, além é claro da comunicação destes dados. registro de todas as informações processadas, tanto em arquiteturas sim-
Porém, um assunto bastante trabalhado, mas pouco deba- ples ou complexas, abrangendo situações como uma camada, múltiplas
tido, são os grandes processamentos de dados dentro do camadas e vários usuários. Além de obtermos aqui uma estrutura para
Delphi, onde na maioria das vezes, possuímos o cenário contemplar o processo de manipulação da camada DDL nos bancos de
em que existe uma grande massa de dados que precisa dados, camada esta, que pode ser trabalhada sem a necessidade de
ser obtida de um ponto e movida para outro. utilização de comandos SQL, bastando apenas utilizar classes contidas
dentro do Delphi. Todos estes processos serão bastante úteis em algumas
tarefas como importações de dados ou atualizações de bancos. Além de
Nota do DevMan 1 trazer alguns conceitos para melhorar a codificação diária de qualquer
sistema que utilize banco de dados relacional. Este artigo irá unir de forma
CRUD acrônimo de Create, Read, Update e Delete em língua Inglesa para as quatro simples como melhor utilizar os componentes de manipulação de dados
operações básicas utilizadas em bancos de dados relacionais ou em interface para de forma mais elegante, eficiente e simples.
usuários para criação, consulta, atualização e destruição de dados.
dbExpress de A a Z – Parte 3 :
Nesta série de artigos iremos abordar a os recursos avançados do
Outra questão refere-se ao tratamento de Logs de for- dbExpress responsáveis pela manipulação de grade massa de dados. Parte
ma simples, tanto em estruturas já existentes quanto as esta que ao longo dos anos sofreu grandes transformações, tornando-se
iniciadas. Destaque neste artigo para a forma simples e hoje um Framework indispensável para quem deseja criar aplicações robus-
de baixo impacto em sistemas já consolidados. Além é tas, capazes de grandes processamentos e com baixo consumo de recursos,
claro, de uma questão importante que causa em diversos além de integrar cada vez mais o Delphi com os mais diversos bancos de
Softwares uma grande dor de cabeça quando se trata dados, tornando assim a experiência com o acesso a dados algo mais con-
de manutenção, que é a abordagem da atualização de fortável para quem necessita utilizar desta integração no cotidiano.
estruturas de dados em bancos já existentes.
É utilizando deste cenário como ponto de partida que
este artigo começa. Serão abordadas maneiras de utilizar As execuções complexas do Delphi requerem sempre uma boa
ao máximo os componentes dbExpress em benefício do arquitetura do código, isto vai desde a escolha e configuração dos
desenvolvimento produtivo, visando sempre o código componentes, forma como se trabalha os recursos do banco em
limpo, funcional e simples. conjunto com o Delphi, além de boas práticas de código. Para o
Introduzindo os recursos avançados Para a manutenção podemos construir processos únicos e unifor-
O dbExpress como conjunto de classes que estão contidas na mes, que contemplem todas estas necessidades.
unit (DbxCommon), além de trabalhar com os diversos bancos de Uma forma de fazer esta tarefa é utilizando ferramentas de
dados já suportados no Delphi, também é a base para o trabalho modelagem de dados, porém, para o profissional que se enquadra
com a característica de processo complexos, como a manipulação na figura de desenvolvedor que não participa da estruturação ou
de grande quantidade de informações. Através de sua estrutura de modelagem de um sistema. Estas opções, apesar de eficientes, não
classes que iremos criar tabelas em distintos bancos e manipular chegam a ser uma “solução final” para a situação.
as informações de um para outro. Tudo isto utilizando de boas
práticas de programação com o Delphi, visando o código limpo Criando as tabelas
e utilizando o paradigma de orientação a objetos. Para iniciar, crie uma nova aplicação VCL Forms (File>New>VCL
Utilizaremos uma estrutura de dados já trabalhada no primeiro Forms Application – Delphi), para que possamos interagir com
artigo (Figura 1). Esta estará disponível para os bancos Firebird e o processo de criação. Dessa forma, desenvolva um layout seme-
SQL Server, sendo os dois exatamente idênticos, porém cada um lhante ao da Figura 2.
com suas características particulares (tipos primitivos, sequências,
triggers e etc).
Para começar, iremos criar estas tabelas sem a utilização de
comandos SQL. Este é um recurso contido no dbExpress a partir
da versão 4 em diante, na qual auxilia os desenvolvedores que
necessitam realizar manutenção em diversos bancos.
Hoje, quando um só aplicativo tem a necessidade de trabalhar
com diversos bancos simultaneamente, o processo de criação e
atualização torna-se, na maioria das vezes, um ponto crítico que Figura 2. Tela Principal
os desenvolvedores enfrentam, pois é parte vital desta tarefa,
que nestes casos, é feita de forma manual e sem auxílio de outras Os processos serão controlados por uma classe “assistente
ferramentas. de criação”, claro que para facilitar este exemplo, utilizaremos
Como sabemos, os bancos de dados relacionais trabalham com Generics (ver Nota do DevMan 2). Sendo assim, será feita a
uma estrutura de linguagem SQL ANSI que é comum entre eles, representação da estrutura do banco por meio de classes. Crie
tomando isto como base, pode-se chegar a uma conclusão lógica. uma Unit nova (untTabela) e adicione o código da Listagem 1 que
ilustra a representação da estrutura de classe referente as tabelas. O método construtor (Create) deverá ser preenchido conforme o
Em seguida, em uma nova Unit (untCampo) adicione o código da código da Listagem 3. O construtor simplesmente inicializa as
Listagem 2 na qual representa as colunas da tabela. variáveis de classe através dos parâmetros de entrada informados
no momento da criação da classe TCampo.
O próximo passo é a elaboração da classe responsável por criar
Listagem 1. Classe TTabela (representação de uma tabela) as tabelas em si. Sendo assim, crie uma nova Unit nomeando-a
//Adicione a unit untCampo (Listagem 2) à sessão uses para untConstrutorTabela. Na Listagem 4 temos a declaração da
unit UntTabela; classe e a seguir, a explanação de seus respectivos métodos.
interface
Listagem 2. Classe TCampo (representação das colunas de uma tabela)
uses
System.Generics.Collections, 01 unit untCampo;
Data.SqlExpr,
Data.DBXDataExpressMetaDataProvider, 02 interface
UntCampo;
type 03 type
TTabela = class
04 ETipoCampo = (tpString, tpInteger, tpDouble, tpDateTime);
private
FNome: String;
FCampos: TList<TCampo>; 05 TCampo = class
protected 06 private
public 07 FNome: String;
property Nome : String read FNome write FNome; 08 FTipo: ETipoCampo;
property Campos : TList<TCampo> read FCampos write FCampos; 09 FTamanho : Integer;
end; 10 FRequirido : Boolean;
11 FChavePrimaria: Boolean;
12 public
Note na classe TTabela (Listagem 1), que foi designada para ser 13 property Nome : String read FNome write FNome;
a representação de uma tabela do banco de dados, a propriedade 14 property Tipo : ETipoCampo read FTipo write FTipo;
15 property Tamanho : Integer read FTamanho write FTamanho;
“Campos”, que nada mais é do que uma lista genérica (Generics –
16 property Requirido : Boolean read FRequirido write FRequirido;
ver Nota do DevMan 2). A adição da propriedade Campos como 17 property ChavePrimaria: Boolean read FChavePrimaria write
um “TList<TCampo>” sugere que teremos várias ocorrências FChavePrimaria;
de colunas por tabela, tratando assim, cada TCampo como um 18 constructor Create(strNome : String; tpTipo : ETipoCampo;
intTamanho : Integer = 0;
objeto de TTabela.
boolRequerido : Boolean = False;
boolChavePrimaria: Boolean = False);
19 end;
procedure TDmExemploImportacao.Importar(
ProCodigo,CliNome,CliDataNascimento,CliEndereco,CliBairro,
CliCidade,CliUF,CliCEP,CliLimiteCompras,CliLimiteCredito : String);
var SQL : String;
begin
SQL := ‘INSERT INTO CLIENTES (‘
+ ‘ PRO_CODIGO’
+ ‘ ,CLI_NOME’
Figura 3. Trace via SQLConnection
+ ‘ ,CLI_DATA_NASCIMENTO’
+ ‘ ,CLI_ENDERECO’
+ ‘ ,CLI_BAIRRO’
Uma outra maneira de efetuar o processo de log é utilizar um
+ ‘ ,CLI_CIDADE’ conjunto de recursos disponíveis no dbExpress. Para isso, utiliza-
+ ‘ ,CLI_UF’ se os eventos do componente DataSetProvider, que possui seu
+ ‘ ,CLI_CEP’
+ ‘ ,CLI_LIMITE_COMPRAS’ funcionamento semelhante ao de um Trigger de banco de dados,
+ ‘ ,CLI_LIMITE_CREDITO)’ no entanto, suas ações ocorrem diretamente em seus eventos.
+ ‘ VALUES ( ‘ Mantendo o Log desta maneira o código fica desacoplado
+ ProCodigo + ‘, ‘
+ CliNome + ‘, ‘ das regras de negócio, banco de dados, estação de trabalho e
+ CliDataNascimento + ‘, ‘ etc. Isto torna esta abordagem bastante genérica e ampla, onde
+ CliEndereco + ‘, ‘
com as devidas customizações, pode-se incluir qualquer tipo
+ CliBairro + ‘, ‘
+ CliCidade + ‘, ‘ de informação.
+ CliUF + ‘, ‘ Vale lembrar que o Log através do Trace também pode ser feito
+ CliCEP + ‘, ‘
+ CliLimiteCompras + ‘, ‘
na arquitetura Cliente-Servidor utilizando o DataSnap.
+ CliLimiteCredito + ‘)’;
Conclusão
sqlquery.SQL.Text := SQL;
sqlquery.ExecSQL;
Neste artigo abordamos diversos temas que são comuns no coti-
end; diano de um desenvolvedor, tais como a manipulação de tabelas
de um banco de dados, onde construímos uma estrutura sem a
Listagem 10. Exemplo de passagem de parâmetros
utilização direta de comandos SQL, mantendo a capacidade de
procedure TDmExemploImportacao.Importar; trabalhar com múltiplos bancos de dados. Como consequência
begin
disto temos um dinamismo na hora de efetuar manutenção dos
sqlqryCliente.ParamByName(‘PRO_CODIGO’).AsInteger := 0;
sqlqryCliente.ParamByName(‘CLI_NOME’).AsString := ‘’; aplicativos, tornando cada vez mais fácil o trabalho com aplica-
sqlqryCliente.ParamByName(‘CLI_DATA_NASCIMENTO’).AsDate := Now; tivos multi-banco.
sqlqryCliente.ParamByName(‘CLI_ENDERECO’).AsString := ‘’;
Também foi abordada a questão de otimizações e boas práticas na
sqlqryCliente.ParamByName(‘CLI_BAIRRO’).AsString := ‘’;
sqlqryCliente.ParamByName(‘CLI_CIDADE’).AsString := ‘’; utilização de comandos SQL dentro do código, visando a melhor
sqlqryCliente.ParamByName(‘CLI_UF’).AsString := ‘’; forma de se trabalhar com esta perspectiva. Geralmente este é um
sqlqryCliente.ParamByName(‘CLI_CEP’).AsString := ‘’;
sqlqryCliente.ParamByName(‘CLI_LIMITE_COMPRAS’).AsFloat := 0;
assunto bastante importante, pois um código bem escrito, além
sqlqryCliente.ParamByName(‘CLI_LIMITE_CREDITO’).AsFloat := 0; de facilmente compreendido, também proporciona uma rápida
sqlqryCliente.ExecSQL; manutenção e consequentemente, um rendimento e um melhor
end;
aproveitamento de tempo. Ainda na questão de otimizações de
uso de comandos SQL, vale a pena ressaltar que a abordagem aqui
contida é apenas um aspecto do dbExpress. Os artigos anteriores recursos do dbExpress visualizando boa parte de seus recursos, o
mostraram uma característica bastante abrangente de como se que facilmente pode proporcionar a criação de aplicações robustas,
utilizar os componentes para seu melhor uso e estruturação de escaláveis e o mais importante, com qualidade. Até a próxima.
acesso a dados.
Por fim, falamos aqui um pouco sobre o trabalho com o proces- Generate Data
so de Log, processo este que é comumente utilizado de diversas http://www.generatedata.com/#generator
formas. Com isso, finalizamos esta série de artigos que aborda
s
Dê
Alexandre Borges A ClubeDelphi tem que ser feita ao seu gosto. Para isso, precisamos saber
sobre e
contato@all-s.info o que você, leitor, acha da revista!
s
ta
Desenvolvedor, instrutor e consultor: Delphi, C#, iOS, Maker.
edição