Anda di halaman 1dari 32

dezembro 2011

dezembro 2011

ndice
04

Chegamos a mais um final de ano.


Mais uma vez foi uma
grande honra para todos ns do The Club
estar com vocs associados...

Delphi

05

Criando uma aplicao Clientserver no Delphi


- Parte 2
Autor:Luciano Pimenta

10

Intruduo ao Android com SQLite

Autor:Thiago Cavalheiro
Montebugnoli

Delphi

15

Streams e compresso de arquivos


com ZipMaster
em Delphi
Autor: Antonio
Spitaleri

Delphi

Delphi

Editorial

Mtodos RAVReport - de A a Z parte 3

Autor: Leonora Golin

22
Desafio The Club

Dicas
- Dicas Delphi

Comunicado:

28

Seguindo nossa tradio, o The Club estar em recesso do dia 19 de


dezembro de 2011 a 30 de dezembro de 2011.

- Cruzada

Legenda

30

Iniciante
Intermedirio
Avanado
dezembro 2011

03

Bem-vindo

hegamos a mais um final de ano. Mais uma vez foi uma grande
honra para todos ns do The Club estar com vocs associados
auxiliando nas mais diversas dvidas e tornando esse trabalho
de desenvolver sistemas mais fcil.

Claro que no porque estamos no final do ano que nossos artigos sero
mais light. Preparamos para esse ms grandes matrias e dicas para essa
ltima revista do ano.
Para comear, temos a continuao da matria de nosso colaborador
Luciano Pimenta: Criando uma aplicao client server no Delphi parte
2, mostrando como aplicaes client server podem ser uma grande
alternativa na programao Delphi.

Av. Prof Celso Ferreira da Silva, 190


Jd. Europa - Avar - SP - CEP 18.707-150
Informaes e Suporte: (14) 3732-1529

Internet

http://www.theclub.com.br
Cadastro: cadastro@theclub.com.br
Suporte: suporte@theclub.com.br
Informaes: info@theclub.com.br
Skype Cadastro: theclub_cadastro
Skype Suporte: theclub_linha1
theclub_linha2
theclub_linha3

www.twitter.com/theclubbr

Na sequncia, temos outra continuao. Dessa vez, nosso colaborador


Thiago Montebugnoli segue nos mostrando a plataforma Android, trazendo como utilizar o banco de dados Sqlite com essa plataforma, no artigo
Introduo ao Android com Sqlite.
No artigo: Streams e compresso de arquivos com ZipMaster em Delphi,
mostro a vocs como Streams e a compresso de arquivos so importantes
em aplicaes Delphi e podem agilizar diversas aes que eventualmente
precisemos realizar na manipulao de arquivos.

Copyright The Club Megazine 2009

Para fechar, temos a terceira parte do artigo de Leonora Golin sobre os


mtodos do Rave Report no artigo Mtodos Rave Report A a Z.

Diagramao e Arte
Vitor M. Rodrigues

Por esse ms isso. Ns do The Club desejamos um feliz Natal e um


grande e prspero Ano Novo a todos e esperamos que nossa parceria continue por muito tempo.
Abraos a todos e at 2012!

Diretor Tcnico
Marcos Csar Silva

Reviso
Eliziane Valentim
Colunistas
Antonio Spitaleri Neto
Bruno Alcars
Eduardo Massud
Leonora Golin
Luciano Pimenta
Thiago Cavalheiro Montebugnoli
Impresso e acabamento:
GRIL - Grfica e Editora
Taquarituba-SP - Tel. (14) 3762-1345

Reproduo

Antonio Spitaleri Neto - Editor Chefe


antonio@theclub.com.br
04

dezembro 2011

A utilizao, reproduo, apropriao, armazenamento em banco


de dados, sob qualquer forma ou meio, de textos, fotos e outras
criaes intelectuais em cada publicao da revista The Club
Megazine so terminantemente proibidos sem autorizao
escrita dos titulares dos direitos autorais.
Delphi marca registrada da Borland International,
as demais marcas citadas so registradas
pelos seus respectivos proprietrios.

Delphi

Criando uma aplicao


client-server no DelphiParte II
Comeamos no artigo anterior a criao
de uma aplicao cliente-server no Delphi,
onde mostrei dicas e maneiras corretas para
usarmos esse tipo de arquitetura em nossos
projetos. A maneira correta (no sou o dono
da verdade, apenas quero mostrar uma
maneira eficiente de desenvolvimento), se
refere a utilizao de OO nas telas de cadastro, onde usamos os conceitos de herana e
polimorfismo.
Nesse artigo, vamos aprofundar alguns
conceitos de OO, onde vamos criar uma
classe, que ser a responsvel por manipular
os dados com o banco. No vou criar aqui
um framework de persistncia, longe disso.
Quero apenas mostrar outra forma de utilizarmos classes em aplicaes cliente-server
no Delphi, que tem por objetivo manipular
dados no banco.

Criando a classe

Vamos criar uma classe para a aplicao. Acesse o menu File>New>Unit Delphi e d o nome de
uClasse.pas. Veja na Listagem 1 a parte inicial da
nossa classe.
Listagem 1. Classe da aplicao
unit uClasse;
interface
uses
Classes, SqlExpr,
Provider, dbclient, DB;
type
{: classe base de
Cadastro }
TBaseCadastro = class
private
FQuery: TSQLQuery;
FSQLConnection:
TSQLConnection;
FsNmTabela: string;

FClientDataSet:
TClientDataSet;
public
constructor Create();
destructor Destroy;
override;
function
Salvar(bInsert: Boolean):
Boolean;
function Excluir:
Boolean;
property Conection:
TSQLConnection
read FSQLConnection
write FSQLConnection;
property Campos:
TClientDataSet
read FClientDataSet
write FClientDataSet;
property sNmTabela:
string read FsNmTabela
write FsNmTabela;
end;
dezembro 2011

05

implementation
uses SysUtils;
...

Veja que temos trs propriedades. Connection do tipo SQLConnection, responsvel pelos
comandos SQLs que montaremos para serem
executados (juntamente com a varivel do tipo
TSQLQuery). Campos do tipo ClientDataSet o cadastro que passaremos, por exemplo, o cadastro
de clientes, passaremos o cdsCliente presente no
DataModule criado anteriormente.
Por fim, temos a sNmTabela, que indicar a
tabela que estamos manipulando. Essas propriedades devem ser configuradas antes de chamarmos
os mtodos Salvar ou Excluir. O Salvar recebe como
parmetro a indicao se estamos inserindo ou
atualizando um registro. O Excluir, obviamente,
elimina um registro no banco.
Caso queira, pode adaptar da maneira que desejar. Vamos entender como funciona os mtodos.
Primeiramente, conheceremos o Excluir, presente
na Listagem 2.
Listagem 2. Mtodo Excluir
function TBaseCadastro.
Excluir(): Boolean;
var
sSQL: string;
sNmChave, sVlChave:
string;
i: integer;
begin
if sNmTabela = then
Exception.
Create(Propriedade
sNmTabela no definida);
for i := 0 to Campos.
FieldCount - 1 do
begin
//procura pelo campo
chave configurado no
ClientDataSet
if (pfInKey in Campos.
Fields[i].ProviderFlags)
then
begin
sNmChave :=
06

dezembro 2011

Campos.Fields[i].
FieldName;
sVlChave :=
Campos.Fields[i].AsString;
end;
end;
if (sNmChave = ) or
(sVlChave = ) then
Exception.
Create(Campo chave no
encontrado);
sSQL := DELETE FROM +
sNmTabela + where +
sNmChave + = +
QuotedStr(sVlChave);
FQuery.SQLConnection :=
Conection;
FQuery.SQL.Clear;
FQuery.SQL.Add(sSQL);
Result := FQuery.
ExecSQL() > 0;
end;

O mtodo verifica primeiramente se a propriedade sNmTabela possui algum valor e emite


uma mensagem de erro caso a mesma esteja vazia.
A seguir, percorremos a propriedade Campos,
procurando pelos Fields configurados como chave
(pfInKey).
Note que isso extremamente importante
quando configurarmos o ClientDataSet que retorna os dados para nossos cadastros (vide artigo
anterior). Precisamos configurar corretamente o
ProviderFlags dos campos no ClientDataSet para
que os mtodos funcionem corretamente.
Aps percorrer os campos, fazemos mais uma
verificao para saber se foi encontrado o nome do
campo chave e seu valor, para evitarmos erros na
execuo do SQL. Caso o cdigo passe pela verificao, montamos o SQL que executara o comando
Delete no banco de dados.
A seguir, configuramos nossa varivel e executamos o comando no banco. O Excluir retorna um
boolean para indicar se o comando foi executado
com sucesso no banco. Isso ajudar para podermos
retornar uma mensagem de OK para o usurio, na
tela de cadastro.
Na Listagem 3 temos o mtodo Salvar.

Listagem 3. Mtodo Salvar


function TBaseCadastro.
Salvar(bInsert: Boolean):
Boolean;
var
sSQLValores: string;
sSQLCampos: string;
sSQLWhere: string;
sSQL: string;
i: integer;
begin
for i := 0 to Campos.
FieldCount - 1 do
begin
//se for insero
if bInsert then
begin


//no adiciona
a chave, pois autoincremento
if (pfInKey
in Campos.Fields[i].
ProviderFlags) then
Continue
else
sSQLValores :=
sSQLValores +
QuotedStr(Campos.
Fields[i].AsString) + ,;
sSQLCampos :=
sSQLCampos + Campos.
Fields[i].FieldName + ,;
end
else //se for
atualizao
begin
//se o campo
chave
if (pfInUpdate
in Campos.Fields[i].
ProviderFlags) and
(pfInKey
in Campos.Fields[i].
ProviderFlags) then
sSQLWhere :=
Campos.Fields[i].FieldName
+ = +
QuotedStr(Campos.
Fields[i].AsString)
else
begin
//para
campos a serem atualizados

if
pfInUpdate in Campos.
Fields[i].ProviderFlags
then
begin
sSQLValores := sSQLValores
+
Campos.
Fields[i].FieldName + =
+
QuotedStr(Campos.
Fields[i].AsString) + ,;
sSQLCampos
:= sSQLCampos +
Campos.
Fields[i].FieldName + ,;
end;
end;
end;

end;
//remove as vrgulas (,)
sSQLCampos :=
Copy(sSQLCampos, 0,
Length(sSQLCampos) - 1);
sSQLValores :=
Copy(sSQLValores, 0,
Length(sSQLValores) - 1);
if bInsert then
sSQL := INSERT INTO
+ sNmTabela +
( + sSQLCampos +
) VALUES ( + sSQLValores
+ )
else
sSQL := UPDATE
+ sNmTabela + SET +
sSQLValores +
where +
sSQLWhere;
FQuery.SQLConnection :=
Conection;
FQuery.SQL.Clear;
FQuery.SQL.Add(sSQL);
Result := FQuery.
ExecSQL() > 0;
end;

O mtodo tem a mesma premissa do Excluir,


percorrer o ClientDataSet, montar o SQL e executar
no banco. Claro, agora temos algumas regras a
serem seguidas. Primeiramente, percorremos os

campos para pegar seus nomes e valores.


Na idia inicial, a consulta traria apenas os
campos preenchidos, mas no faz sentido, pois o
usurio pode estar editando um registro e resolver
apagar os dados de um determinado campo. O
Salvar deve persistir no banco que o campo no
possui mais valor.
Continuando o cdigo, verificamos se estamos
inserindo um registro, por que o comando SQL para
inserir diferente do atualizar. No pegamos o
campo chave, por que o mesmo auto-incremento
no banco. Pegamos o valor e o campo, em variveis
distintas, separando os mesmos por vrgula (,). Se
estivermos inserindo, apenas essas duas variveis
sero preenchidas.
Caso estejamos editando, precisamos montar
o where da consulta. Novamente, precisamos
verificar se o Field que estamos percorrendo,
uma chave, atravs da propriedade ProviderFlags
do TField.
Assim, pegamos o nome do campo e seu valor
para ser nossa condio. Se o campo no for chave,
ele entrar nas variveis para atualizao. Aps
percorrer os campos, precisamos apenas remover
as vrgulas (,), que ajudaram a separar os campos.
Em seguida, montamos o comando SQL de
acordo com o parmetro bInsert. Veja que o comando precisa ser montado corretamente, onde
usamos a definio do nome dos campos no Insert,
prtica correta.
No Update no podemos esquecer a varivel
sSQLWhere que possui o nome e o valos do campo chave do nosso registro. Por fim, executamos
o comando SQL no banco. Veja que o exemplo
simples, mas eficaz. Precisamos apenas de um
componente para executar os comandos no banco
e um para indicar a lista de campos que precisamos
para montar o comando SQL.
Voc pode adaptar a classe para a maneira que
lhe convier em seus projetos. Note que a mesma
genrica, se a configurao for executada de forma
correta, qualquer tabela do banco pode ser usada.

Modificando a aplicao
Precisamos agora, modificar o nosso cadastro
base para executar os mtodos existentes na classe.
Primeiramente, declare duas variveis na seo
public do formulrio:

FClasseBase:
TBaseCadastro;
FNomeTabela: string;

A primeira, nossa varivel da classe recm


criada. A segunda ser responsvel por armazenar
o nome da tabela que iremos executar no comando de Excluir e Salvar. Ela dever ser preenchida
no evento FormShow dos formulrios herdados.
Lembre-se bem disso, nos formulrios herdados:
procedure TfrmCliente.
FormShow(Sender: TObject);
begin
inherited;
FNomeTabela :=
CLIENTE;
end;

A FClasseBase tambm deve ser criada a sua


instncia no evento FormShow, mas no formulrio
base:
procedure TfrmCadastro.
FormShow(Sender: TObject);
begin
FClasseBase :=
TBaseCadastro.Create;
end;

Precisamos liberar da memria a instncia da


classe, quando fecharmos o formulrio, portanto,
usamos o evento FormClose:
procedure TfrmCadastro.
FormClose(Sender: TObject;
var Action: TCloseAction);
begin
FClasseBase.Free;
end;

Por fim, precisamos codificar os botes de


Salvar e Excluir. Na Listagem 4 vemos o cdigo do
boto Excluir.
Listagem 4. Boto Excluir do formulrio base
uses uDM;
...
dezembro 2011

07

procedure TfrmCadastro.
ExcluirExecute(Sender:
TObject);
begin
{: deleta se houver
dados no DataSet }
if (dsCadastro.DataSet.
Active) and (dsCadastro.
DataSet.RecordCount > 0)
then
begin
if MessageDlg(Tem
certeza que deseja
excluir o registro
?, mtConfirmation,
[mbYes,mbNo], 0) = mrYes
then
begin
FClasseBase.
Conection := DM.SysCar;
FClasseBase.
sNmTabela := FNomeTabela;
FClasseBase.Campos
:= (dsCadastro.DataSet as
TClientDataSet);
if FClasseBase.
Excluir() then
begin
MessageDlg(Registro
excludo com sucesso,
mtInformation,
[mbOk], 0);
dsCadastro.
DataSet.Close;
(dsCadastro.
DataSet as
TClientDataSet).Params[0].
AsInteger := 0;
dsCadastro.
DataSet.Open;
end;
end;
end;
end;

Fazemos uma verificao se podemos excluir o


registro e em seguida, pedimos a confirmao para
o usurio. Aps, preenchemos as propriedades e
executamos o Excluir da classe. Para a propriedade
Campos, fizemos um cast do ClientDataSet para a
propriedade DataSet do DataSource presente no
formulrio base.
Assim, sabemos que em todos os formulrios
herdados os campos do cadastro esto presentes
08

dezembro 2011

nesse componente. Caso o Excluir execute corretamente, mostramos uma mensagem ao usurio. Por
fim, fechamos o componente e repassamos zero (0)
para seu filtro, apenas para limpar o ClientDataSet
da memria.
Veja como ser fcil criarmos cadastros. Bastar herdar do nosso formulrio base, configurar o
nome da tabela e o mtodo de excluso esta pronto. Na Listagem 5 temos o cdigo do boto Salvar.
Listagem 5. Boto Salvar do formulrio base
procedure TfrmCadastro.
btnSalvarClick(Sender:
TObject);
begin
{: salvo as dados
se os campos estiverem
preenchidos}
if CamposObrigatorios
(dsCadastro) and
(dsCadastro.State in
[dsEdit, dsInsert]) then
begin
FClasseBase.
Conection := DM.SysCar;
FClasseBase.
sNmTabela := FNomeTabela;
FClasseBase.Campos
:= (dsCadastro.DataSet as
TClientDataSet);
if (FClasseBase.
Salvar(bFlInsert) then
begin
MessageDlg(Registro
salvo com sucesso,
mtInformation,
[mbYes], 0);
dsCadastro.
DataSet.Close;
(dsCadastro.
DataSet as
TClientDataSet).Params[0].
AsInteger := 0;
dsCadastro.
DataSet.Open;

bFlInsert :=
false;
end;
end;
end;

O cdigo muito semelhante a do Excluir,


apenas com a diferena que chamamos o mto-

do Salvar e que verificamos antes, se os campos


obrigatrios esto preenchidos, assim como se o
cadastro esta sendo editado ou inserido, usando
uma varivel privada do tipo boolean.
A varivel configurada quando clicamos no
boto Novo e quando salvamos o cadastro. No
cdigo-fonte voc pode verificar onde a varivel
preenchida. Caso o comando seja executado com
sucesso, emitimos uma mensagem ao usurio e
fechamos o cadastro, onde novamente passamos
o valor 0 para o parmetro do ClientDataSet.
Execute a aplicao e faa o teste. Adicione,
atualize e exclua registros (Figura 1).

Figura 1. Manipulando o cadastro de clientes

Agora estamos prontos a criar novos cadastros


em nossa aplicao. Veja na Figura 2 o cadastro de
peas criado facilmente.

Figura 2. Cadastro de peas

Cadastro com consulta auxiliar


Vamos criar agora o cadastro de veculos, que
tambm simples, mas tem uma caracterstica
diferente da mostrada at agora. Ele possui um
relacionamento com o cliente, ento precisamos
ter uma pesquisa auxiliar no cadastro.
Na edio de Maro de 2010 da The Club,
mostrei como criar um componente para consul-

tas auxiliares. Usaremos esse controle em nosso


projeto. Veja na Figura 3 o cadastro em execuo.

Apenas verificamos se a busca retornou


algum valor, e configuramos o respectivo cdigo
do cliente para o cadastro de veculos. Colocamos
o nome do cliente, filtrando o ClientDataSet do
cadastro de cliente para pegar seu nome e indicar
o mesmo no Edit.
Veja na Figura 4 o cadastro em execuo.

DM.cdsCliente.Close;
DM.cdsCliente.
Params[0].AsInteger
:= dsCadastro.DataSet.
FieldByName(nCdCliente).
AsInteger;
DM.cdsCliente.Open;
edtCliente.Text :=
DM.cdsClientesNmCliente.
AsString;
DM.cdsCliente.Close;
end;

Figura 3. Cadastro de veculos com pesquisa auxiliar

A diferena fica por conta da configurao do


cdigo do cliente quando executamos o localizar.
Veja na Listagem 6, o que precisamos fazer quando o usurio escolher um cliente no cadastro de
veculos.
Listagem 6. Mtodo para modificar o cdigo
de cliente no cadastro de veiculo
procedure TfrmVeiculo.
btnPesquisarClick(Sender:
TObject);
begin
inherited;
if locCliente.Execute
then
begin
if (dsCadastro.State
in [dsEdit, dsInsert])
then
begin
dsCadastro.DataSet.
FieldByName(nCdCliente).
AsInteger :=
locCliente.
ReturnValue;
DM.cdsCliente.Close;
DM.cdsCliente.
Params[0].AsInteger :=
locCliente.ReturnValue;
DM.cdsCliente.Open;
edtCliente.Text :=
DM.cdsClientesNmCliente.
AsString;
DM.cdsCliente.Close;
end;
end;
end;

Figura 4. Cadastro de veculos em execuo

Quando carregamos o cadastro, precisamos


novamente, filtrar o nome do cliente para ser
mostrado no Edit (evento DblClick do DBgrid). Para
isso, usamos o cdigo da Listagem 7.
Listagem 7. Filtrando o nome do cliente no
cadastro de veculos
procedure TfrmVeiculo.
DBGrid1DblClick(Sender:
TObject);
begin
inherited;

Veja que as configuraes extras que precisamos so bem fceis de serem usadas. No prximo
artigo, veremos os cadastros de Oramento e
Ordem de servio, onde no usaremos o formulrio base, mas poderemos usar a nossa classe
de cadastro.

Concluses

Vimos nesse artigo a criao da nossa classe


para manipulao de dados no banco, apenas
repassando um ClientDataSet. Com essa classe,
precisamos de apenas algumas configuraes para
podermos ter um cadastro funcional da aplicao.
Fica a dica para voc aprofundar seus conhecimentos e quem sabe melhorar a mesma, diminuindo a quantidade de configuraes (propriedades)
necessrias para a execuo dos mtodos Salvar
e Excluir. No prximo artigo, continuaremos com
nossa aplicao.
Um grande abrao a todos e at a prxima!

Sobre o autor
Luciano Pimenta
Tcnico em Processamento de Dados, desenvolvedor Delphi/C# para aplicaes
Web com ASP.NET e Windows com Win32 e Windows Forms. Palestrante da 4 edio
da Borland Conference (BorCon).
Autor de mais de 60 artigos e de mais de 300 vdeos aulas publicadas em revistas
e sites especializados. consultor da FP2 Tecnologia (www.fp2.com.br) onde ministra
cursos de programao e banco de dados. desenvolvedor da Paradigma Web Bussiness em Florianpolis-SC.

www.lucianopimenta.net

dezembro 2011

09

Intruduo ao
Android com o
SQLite
Neste artigo abordarei um pouco das caractersticas do SQLite, junto
com alguns exemplos prticos utilizando o Android.

Uma introduo ao SQLite


SQLite um Banco de Dados Open Source que j vem embutido no
Sistema Android. um Banco de Dados relacional suportando a sintaxe
SQL, operaes e instrues, requerendo pouca memria em tempo de
execuo. Sua estrutura est contida em apenas em um nico arquivo
no sistema e o acesso aos dados implemetado por uma biblioteca de
funes escritas em C.
um gerenciador de banco de dados auto-suficiente, ou seja, independente de uma estrutura cliente-servidor. Neste caso ele necessita
de um apoio mnimo de bibliotecas externas ou at mesmo do Sistema
Operacional, se tornando muito fcil para ser adaptado para o uso de
dispositivos embarcados. Isto o torna flexvel para muitas plataformas.
muito utilizado em Dispositivos e sistemas embarcados (telefone
celular, PDAs, MP3, entre outros), Aplicaes Desktop, Sites com poucos
acessos e tambm pode ser til para o aprendizado.

Tipos de Campos
10

dezembro 2011

Na realidade no SQLite, o tipo de dado de um valor est associado com


o valor propriamente dito, diferente de outros Bancos de Dados, se tornando
um sistema de tipos dinmicos.
Um campo de uma tabela em SQLite pode receber qualquer tipo de dado,
ignorando o tipo informado no comando CREATE TABLE.
Em poucas palavras, podemos dizer que no SQLite existem classes de
armazenamento, veja a seguir para maiores detalhes.
NULL: O campo no deve ser Nulo, caracterstica encontrada como
em qualquer outro Banco de Dados.
INTEGER: inteiro com sinal, armazenado em 1, 2, 3, 4, 6 ou 8 bytes
dependendo da grandeza do valor.
REAL: valor de ponto flutuante armazenado em 8 bytes.
TEXT: uma string armazenada usando UTF-8, UTF-16BE ou UTF-16LE.
BLOB: armazena campos do tipo Blob.

Como posso utilizar campos do tipo Booleano e Data/Hora?


Na realidade no existe nenhuma classe do tipo Booleana, podemos
considerar tipos inteiros 0 e 1, respectivamente como Verdadeiro e Falso.
o mesmo caso para tipos de campos Data ou Hora, no existem classes
para armazenamento destes tipos. O SQLite possui funes capazes de tratar
os tipos citados acima.

Funes disponveis
Date: Retorna a data no formato YYYY-MM-DD.
Time: Retorna a hora no formato HH:MM:SS.
Datetime: retorna data e hora no formato YYYY-MM-DD HH:MM:SS.
Strftime: retorna a data formatada de acordo com o formato especificado.

Exemplos de Utilizaes
SELECT date(now) Retorna a Data Atual.
SELECT time(now) Retorna a Hora Atual.
SELECT datetime(now) Retorna a Data/Hora Atual.

Criando um Exemplo Bsico


Seguindo os passos do artigo do ms de Novembro, teremos o Eclipse
Instalado corretamente com todas as configuraes prontas para o nosso
exemplo. A inteno ser de criar uma tela simples de insero de dados. Para
isto ser necessrio criar uma classe para manipulao e acesso aos dados.
Abra o Eclipse criando um novo projeto em Android, clique em File/New/
Android Project. No meu caso defini como:
Project Name: TheClub_Artigo
Build Target: Android 2.2
Application Name: TheClub_Artigo
Package Name: Pacote. TheClub_Artigo
Create Activity: TheClub_ArtigoActivity
Min SDK Version: 8
Depois de criado nosso Pacote, em Package Explorer escolha o caminho
src/Pacote.TheClub e com o boto direito criaremos uma Classe, para isto basta
escolher New/Class. Esta classe responsvel por trabalhar com o SQLite.

Figura 01: Criao da Classe DataHelper.

A tela acima nos proporciona realizar inmeras atribuies na criao de


uma classe, deixaremos com a seguinte configurao:
Source folder: TheClub/src
Package: Pacote.TheClub
Name: DataHelper
Modifiers: public
Superclass: java.lang.Object
Cheque os itens: Inherited abstract methods e Generate comments
para podermos herdar os mtodos abstratos e gerar comentrios respectivamente. Veja abaixo o cdigo gerado:
package Pacote.TheClub;
/**
* @author Thiago
*
*/
public class DataHelper
{
}

Implementando uma Classe de Dados


Nos prximos passos irei criar a classe e darei uma breve explicao do
cdigo. Primeiramente utilizaremos o comando import para nos dar acesso
a algumas classes necessrias para o funcionamento e em seguida definir
alguns atributos necessrios.
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.
SQLiteDatabase;
import android.database.sqlite.
SQLiteOpenHelper;
import android.database.sqlite.
SQLiteStatement;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
.
.
private static final String DATABASE_NAME
= DB_THECLUB.db;
private static final int DATABASE_VERSION
= 1;
private static final String TABLE_NAME =
TB_CLIENTE;
private Context context;
private SQLiteDatabase db;
private SQLiteStatement insertStmt;
private static final String INSERT =
insert into + TABLE_NAME + (name)
values (?);
dezembro 2011

11

Notem que estes atributos so do tipo private, ou seja, so utilizveis


apenas dentro de nossa classe DataHelper.
Logo em seguida programaremos o mtodo Construtor recebendo como
parmetro um Contexto de informaes e mais abaixo Implementamos o
Mtodo insert para inserir dados, deleteAll para excluso, selectAll para
consultas e por final inclumos uma inner-classe importante que nos d acesso
a um SQLiteOpenHelper.
public DataHelper(Context context)
{

this.context = context;

OpenHelper openHelper = new
OpenHelper(this.context);

this.db = openHelper.
getWritableDatabase();

this.insertStmt = this.
db.compileStatement(INSERT);
}
public long insert(String name)
{
this.insertStmt.bindString(1, name);
return this.insertStmt.
executeInsert();
}
public void deleteAll()
{
this.db.delete(TABLE_NAME, null,
null);
}
public List<String> selectAll()
{
List<String> list = new
ArrayList<String>();
Cursor cursor = this.db.query(TABLE_
NAME, new String[] { cod_cli, nom_cli
},
null, null, null, null, cod_
cli);
if (cursor.moveToFirst()) {
do {
list.add(cursor.getString(0)
+ - + cursor.getString(1));
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.
isClosed()) {
cursor.close();
}
return list;
}
private static class OpenHelper extends
SQLiteOpenHelper
12

dezembro 2011

{
OpenHelper(Context context)
{
super(context, DATABASE_NAME,
null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase
db) {
db.execSQL(CREATE TABLE + TABLE_
NAME + (cod_cli INTEGER PRIMARY KEY, nom_
cli TEXT));
}
@Override
public void onUpgrade(SQLiteDatabase
db, int oldVersion, int newVersion) {
Log.w(Example, Upgrading
database, this will drop tables and
recreate.);
db.execSQL(DROP TABLE IF EXISTS
+ TABLE_NAME);
onCreate(db);
}
}

Uma informao para quem no sabe, Inner Class so classes internas


declaradas dentro de outras classes.
Percebam que criamos uma tabela de clientes com apenas dois campos
para nosso artigo, mas com certeza este exemplo cobre todos os conceitos
bsicos de manipulao de dados do Android. No entraremos em muitos
detalhes em relao a esta classe.

Criando um layout de Cadastro


Para isto navegue at o caminho res/layout/main.xml e na Paleta Form
Widgets adicione um TextView, um Button e um EditText da paleta Text
Fields.
Defina suas propriedades em seguida como:
TextView1
Id: @+id/textView1
Text: Nome:
Layout Height: wrap_content
Layout Width: wrap_content
EditText1
Id: @+id/editText1
Input type: textPersonName
Layout Height: wrap_content
Layout Width: wrap_content
Button1
Id: @+id/button1
Text: Inserir
Layout Height: wrap_content
Layout Width: 104dp

interessante observar que o trecho do cdigo abaixo foi adicionado para


exibir a sada dos dados cadastrados.
.

.
<TextView android:id=@+id/out_text
android:layout_width=fill_parent
android:layout_height=wrap_
content
android:text= />

A Figura 03 ilustra nossa tela em Run-Time.

Figura 02: Layout da Tela.

O arquivo de layout main.xml ficou da seguinte maneira:


<?xml version=1.0 encoding=utf-8?>
<ScrollView
xmlns:android=http://schemas.android.
com/apk/res/android
android:layout_width=fill_parent
android:layout_height=wrap_
content>
<LinearLayout xmlns:android=
http://schemas.android.com/apk/res/
android
android:orientation=vertical
android:layout_width=fill_
parent android:layout_height=19dp
android:weightSum=1>
<TextView android:id=@+id/
textView1 android:layout_width=wrap_
content android:layout_height=wrap_
content android:text=Nome:></TextView>
<EditText android:layout_
height=wrap_content android:id=@+id/
editText1 android:inputType=textPersonNa
me android:layout_width=300dp>
</EditText>
<Button android:text=Inserir
android:id=@+id/button1 android:layout_
height=wrap_content android:layout_
width=104dp></Button>
<TextView android:id=@+id/out_text
android:layout_width=fill_parent
android:layout_height=wrap_
content
android:text= />
</LinearLayout>
</ScrollView>

Figura 03: Tela de Cadastro.

Codificando o Boto Inserir


Primeiramente localize a classe TheClubActivity em src/Pacote.TheClub
e logo em seguida adicionaremos algumas classes, veja abaixo:
import
import
import
import
import
import
import
import
import
import

Pacote.TheClub.DataHelper;
Pacote.TheClub.R;
android.app.Activity;
android.app.AlertDialog;
android.os.Bundle;
android.view.View;
android.widget.Button;
android.widget.EditText;
android.widget.TextView;
java.util.List;


Definimos alguns atributos, como:
TextView saida;
DataHelper db;
Button btn1;
EditText edt1;
dezembro 2011

13

E no mtodo OnCreate programaremos o seguinte cdigo


public void onCreate(Bundle
savedInstanceState)
{
super.onCreate (savedInstanceState);
setContentView(R.layout.main);

btn1 = (Button) findViewById(R.
id.button1);

saida = (TextView) this.
findViewById(R.id.out_text);

db = new DataHelper(this);

edt1 = (EditText) findViewById(R.
id.editText1);


btn1.setOnClickListener(new View.
OnClickListener()
{
@Override

public void onClick(View v)

{



db.insert(edt1.getText().
toString());


List<String> names =
db.selectAll();


StringBuilder sb = new
StringBuilder();


sb.append(Clientes
Cadastrados:\n);


for (String name : names)


{


sb.append(name +
\n);


}




saida.setText(sb.
toString());



}

});
}

Figura 04: Dados Inseridos no SQLite.


Observem que a Classe DataHelper possui o mtodo DeleteAll que no foi
utilizado especificamente neste artigo. Os mtodos criados podem e devem
ser melhorados de acordo com a necessidade do sistema. Uma dica seria criar
um Mtodo que Exclusse apenas um registro passado por parmetro, ou criar
um que selecionasse apenas um registro para mostrar na tela. Fica a a dica.
Concluses
Podemos dividir este artigo em duas partes, a primeira como uma teoria
destacando informaes e dicas referentes ao SQLite do Android e a segunda
uma prtica com um exemplo simples utilizando a linguagem Java para trabalhar com dados.
A linguagem Java nos proporciona um leque de aprendizado, um prato
cheio para quem est aprendendo Orientao a Objetos pelo fato de ser
totalmente desta maneira.
Espero que este artigo proporcione aos senhores um pontap inicial para
trabalhar com a Tecnologia Android.
Um Forte abrao e at o ms que vem!

Referncias
No cdigo acima estamos usando o mtodo findViewById, que tem como
objetivo atribuir o objeto da tela pelo localizado pelo Id a uma varivel do mesmo tipo. Desta forma conseguimos manipular toda informao ali trabalhada.
Para utilizar a classe criada anteriormente devemos instanci-la como um
objeto qualquer passando o parmetro this que seria o contexto em geral
da aplicao. Veja abaixo novamente:
db = new DataHelper(this);

Utilizamos o Mtodo OnClick do Boto para Inserir os Dados com o mtodo


db.Insert e selecion-los em seguida com o db.SelectAll. A Classe StringBuilder
serve para armazenar os registros e mostr-los na tela.
14

dezembro 2011

http://www.sqlite.org/datatype3.html
http://www.screaming-penguin.com

Sobre o autor
Thiago Cavalheiro Montebugnoli
Thiago Cavalheiro Montebugnoli tecnlogo, formado pela Faculdade
de Tecnologia de Botucatu SP (FATEC) foi consultor tcnico do The Club, j
desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco
de Dados SQL Server e Firebird. Atualmente trabalha no Centro de Processamento de Dados da Prefeitura Municipal de Ita-SP. Possui as seguintes
certificaes: MCP - Microsoft Certified Professional, MCTS - Microsoft Certified Technology Specialist, MCAD - Microsoft Certified Application Developer
e MCSD - Microsoft Certified Solution Developer.

thiago@theclub.com.br

Streams e compresso de
arquivos com ZipMaster em
Delphi

Quando se trabalha com transferncias


de arquivos em aplicativos, sejam feitos em
Delphi ou outras ferramentas, as vezes necessria a compresso desses arquivos para
aumentar a performance.
Comprimir um arquivo codific-lo em
outro padro para reduzir seu volume na
memria do computador.
Atualmente existem vrios padres de
compresso de arquivos. O mais conhecido
em ambiente Windows sem dvida o .zip.
Semelhante ao .zip temos o .rar. Tanto os
formatos zip quanto rar criam uma pasta
compactada que contm os arquivos originais. Esse formato de pasta facilita a descompresso dos arquivos j que a estrutura
de diretrios bem familiar aos usurios da

plataforma Windows.
Ainda no assunto de padres de compresso, um padro bem conhecido e que muitos
no sabem que se trata de um formato comprimido so os arquivos com a extenso .iso.
Esses arquivos so muito populares quando
temos a gravao de CDs e DVDs, pois em
geral as imagens das mdias na pr-gravao
esto comprimidas em formato .iso.
Na rea de multimdia, temos o tambm
bastante conhecido padro .mp3. O mp3
um arquivo de udio do qual so eliminadas frequncias ou faixas de frequncias
desnecessrias. Isso torna o arquivo menor.
O formato mp3 se tornou muito popular a
partir da expanso do compartilhemento de
msicas via internet.

O formato .mp4 bem semelhante ao


.mp3, porm foi desenvolvido para suportar
arquivos de vdeo. No formato .mp4, os
vdeos ocupam um espao bem menor se
comparado aos formatos tradicionais como
.wmv e .avi. claro que tanto a compresso
no s formatos .mp3 como .mp4 implicam em
alguma perda de qualidade, porm o ganho
em espao e performance nas transferncias
acaba por justificar a adoo desses formatos
em muitos casos.
Claro que para trabalharmos com compresso de arquivos, precisamos de programas que faam o trabalho de comprimir. Em
ambiente Windows, sem dvida os programas
mais utilizados hoje so o Winrar e WinZip. O
Winrar se caracteriza por trabalhar com vrios
formatos, alm de possuir ferramentas que
dezembro 2011

15

permitem criar pastas auto-extraveis, muito


teis em instaladores que apenas necessitam
fazer cpias para uma pasta em especfico,
como o caso dos famosos SDKs, ou kits de
desenvolvimento de softwares. Alm disso,
com o Winrar podemos separa arquivos muito
grandes em partes durante a compresso.
Alm dos programas que trabalham
com compresso de arquivos, em algumas
situaes necessitamos comprimir arquivos
diretamente em nossas aplicaes Delphi.
dessa forma de compresso que falaremos
nesse artigo.

diversos formatos. Para a compresso de dados,


TfileStream melhor pois podemos trabalhar com
a mesma independente do formato de arquivo que
ser compactado.
TBlobStream Quando se trabalha com armazenamento de dados binrios direto no banco
de dados, importante que possamos recuperar
os dados da forma mais limpa possvel, eviatndo
discrepncias. A classe TblobStream possui justamente como especialidade trabalhar com dados
provenientes de campos binrios em datasets.
Atravs de TblobStream podemos tanto trazer
como enviar dados binrios para o dataset e depois
ao banco de dados.

Quando trabalhamos com compresso


de dados, consequentemente temos de trabalhar com arquivos e em Delphi a classe que
manipula arquivos a Tstream. Um stream
representa um fluxo de dados, com tamanho
definido. Quando trabalhamos com a classe
Tstream e suas descendentes, precismos ter
em mente que sempre estaremos em algum
ponto definido, representado por um cursor. A
lgica semelhante a compararmos o Stream
como um disco e esse cursor seria a agulha
de leitura desse disco. Nas transferncias de
arquivos, o cursor vai realizando a leitura do
Stream que contm o arquivo bit a bit at
completar o tamanho do arquivo.

TWinSocketStream Esse formato especializado para a troca de informaes via sockets.


bem pouco utilizado.

A classe Tstream dificilmente utilizada


em Delphi. No lugar da mesma, so utilizadas
suas descendentes. Essas classes descendentes possuem cada uma uma especialidade,
sendo utilizadas para situaes especficas.

Salvando componentes no Stream

Vejamos quais so as pricipais descendentes


de TStream:
TStringStream Essa classe trabalha com
strings, armazenando as mesmas para que possam
ser manipuladas como arquivos. Essa classe muito
til em descargas de dados provenientes da Web,
como na implementao da Nota Fiscal Eletrnica,
onde necessitamos enviar o xml e receb-lo em
formato de string.
TFileStream Para nosso artigo, o descendente mais relevante. atravs de TFileStream
que abrimos e manipulamos arquivos nos mais
16

dezembro 2011

TOleStream Stream para manipulao de


dados provenientes de objetos OLE. A tecnologia
OLE (Object Linking and Embeding) o que permite
a troca de dados entre diferentes aplicaes em
ambiente Windows, como por exemplo quando
recortamos um texto do navegador de internet e
colamos o mesmo no editor de textos. Em Delphi
temos objetos para o trabalho com a tecnologia
OLE e ToleStream pode ser um excelente aliado na
manipulao desses objetos.

Quando falamos dos dados manipulados pela


classe TStream e suas descendentes, no precisa
necessariamente ser dados provenientes de um
arquivo. Podemos trabalhar com qualquer tipo de
dado. At mesmo componentes do Delphi podem
ser salvos atravs de Streams.
Veja o exemplo abaixo:

procedure SalvaComponente;
// Essa procedure carrega
o componente
// para dentro de um
stream e salva
// o componente em arquivo
var
stListBox:TFileStream;
begin

try
stListBox:=TFileStream.
Create(c:\minhalista.
dat,fmOpenReadWrite);
stListBox.
WriteComponent(ListBox1);
finally
stListBox.Free
end;
end;
procedure
CarregaComponente;
// Aqui recuperamos
o componente salvo
anteriormente
var
stListBox:TFileStream;
begin
if(FileExists(c:\
minhalista.dat))then
try
stListBox:=TFileStream.
Create(c:\minhalista.
dat,fmOpenReadWrite);
stListBox.
ReadComponent(ListBox1);
finally
stListBox.Free
end;
end;

Como vimos, armazenar um componente


em um arquivo e depois recuper-lo atravs dos
Streams no nada complexo. E alm de simples,
essa prtica pode ser muito til.

Manipulando Imagens com TStream


Em Delphi, um dos grandes usos da classe
Tstream para a manipulao de imagens. Entre
esses usos, podemos citar a converso de imagens.
O exemplo que faremos a seguir faz uso de
Tstream para converter um bitmap para o formato
Jpeg.
O layout da aplicao ser composto de dois
componentes Image; Dois componentes Button

alm de duas labels.


Veja a imagem 01 do Layout:
Agora o cdigo do exemplo.

unit Unit1;
interface
uses
Windows, Messages,
SysUtils, Variants,
Classes, Graphics,
Controls, Forms,
Dialogs,Jpeg, StdCtrls,
ExtCtrls;
type
TForm1 = class(TForm)
Image1: TImage;
Label1: TLabel;
Label2: TLabel;
Image2: TImage;
btnSalvarJpeg:
TButton;
btnCarregarImagem:
TButton;
Label3: TLabel;
Label4: TLabel;
procedure
btnCarregarImagemClick
(Sender: TObject);
procedure
btnSalvarJpegClick
(Sender: TObject);
private
{ Private declarations
}
public
{ Public declarations
}
end;
var
Form1: TForm1;
procedure
ConverteBMPparaJPG
(Instream: TStream);
implementation
{$R *.dfm}
procedure
ConverteBMPparaJPG
(Instream: TStream);

Imagem 01

var
JpegImage: TJpegImage;
Bitmap: TBitmap;
begin
JpegImage := TJpegImage.
Create;
Bitmap := TBitmap.
Create;
try
// Carrega e exibe a
imagem Bitmap
Bitmap.
LoadFromStream(InStream);
Form1.Image1.Canvas.
Draw(0,0,Bitmap);
Form1.Label1.Caption
:= Imagem Bitmap;
// Converte para Jpeg
JpegImage.
Assign(Bitmap);
Form1.Image2.Canvas.
Draw (0,0,JpegImage);
Form1.Label2.Caption
:= Imagem Jpeg;
finally
JpegImage.Free;
Bitmap.Free;
end;
end;
procedure TForm1.
btnCarregarImagemClick

(Sender: TObject);
var
InStream: TFileStream;
begin
try
//Salvamos o bitmap
como Jpeg atravs da
converso
InStream :=
TFileStream.Create
(imagem.bmp,fmOpenRead);
ConverteBMPparaJPG
(Instream);
finally
InStream.Free;
end;
end;
procedure TForm1.
btnSalvarJpegClick
(Sender: TObject);
var
OutStream: TFileStream;
JpegImage: TJpegImage;
begin
// Salvamos o Jpeg
anteriormente criado na
converso
JpegImage := TJpegImage.
Create;
JpegImage.Assign
(Image2.Picture.Bitmap);
try
OutStream :=
dezembro 2011

17

TFileStream.Create
(imagem.jpg,fmOpenWrite
or fmCreate);
JpegImage.SaveToStream
(OutStream);
finally
OutStream.Free;
JpegImage.Free;
end;
end;
end.

Compresso de arquivos e diretrios


com ZipMaster
Vamos agora trabalhar com a compresso de
arquivos. O Delphi possui uma bibloteca nativa para
compresso de arquivos, chamada Zlib. Alm dessa
biblioteca , existem componentes de terceiros que
realizam compresso de dados, como o ZipForge
e o ZipMaster. o componente ZipMaster que
abordaremos na sequncia.

Imagem 02

O download do componente ZipMaster pode


ser realizado no seguinte endereo:
http://www.delphizip.org/download/zm190setup0116.zip.
Aps o download, extraia e execute o instalador. Ser solicitada uma pasta de destino. Essa
pasta importante porque nela que estar a
package para instalao aps o termino da execuo do instalador.
O componente ZipMaster compatvel com
diversas verses do Delphi, como podemos ver
na pasta Delphi dentro do diretrio de instalao:

duas Edits, dois Buttons, alm do componente


ZipMaster.
O layout dever ficar como na imagem 03:

Veja a imagem 02.


Para adicionar o componente a IDE do Delphi,
abra a dpk correspondente a verso do Delphi,
compile e depois instale. Ser criada a aba DelphiZip19 na IDE do Delphi.
Aps a instalao, estamos aptos a criar nosso
primeiro exemplo com o ZipMaster.
Inicie uma nova aplicao no Delphi e adicione
18

Imagem 03

dezembro 2011

with TOpenDialog.
Create(nil) do
try

No evento Onclick do boto Selecionar Arquivo, faa:

if(Execute)then
edtArquivoSelecionado.
Text:=FileName;

procedure TForm1.
Button1Click(Sender:
TObject);
begin

finally
Free;
end;
end;

E no OnClick do boto Comprimir com ZipMaster, faa:

procedure TForm1.
Button2Click(Sender:
TObject);
begin
ZipMaster191.FSpecArgs.
Add(edtArquivoSelecionado.
Text);
with TSaveDialog.
Create(nil) do
try
if(Execute)then
begin
ZipMaster191.
ZipFileName:=FileName;
ZipMaster191.
Add;
end;
finally
lblMensagem.
Caption:=Concludo !;
Free;
end;

Imagem 04

end;

Veja o exemplo em execuo na imagem 04:


Podemos utilizar o componente ZipMaster
na compactao de no apenas um arquivo mas
tambm de todo um diretrio.
Para compactarmos um diretrio, no utilizaremos o OpenDialog mas em seu lugar o DirectoryOutline da aba Samples. O procedimento de
compactao bem semelhante ao que fizemos
h pouco. Nesse procedimento, vale lembrar que a
estrutura interna da pasta, caso a mesma contenha
subpastas ser mantida.
Veja o cdigo a seguir:

procedure TForm1.
Button3Click(Sender:
TObject);
begin

Imagem 05

ZipMaster191.FSpecArgs.
Add(DirectoryOutline1.
Directory);
with TSaveDialog.
Create(nil)do
try
if(Execute)then
begin
ZipMaster191.
ZipFileName:=FileName;
ZipMaster191.
AddOptions:=ZipMaster191.
AddOptions+
[AddDirNames,
AddRecurseDirs];

ZipMaster191.
Add;
end;
finally
ZipMaster191.
FSpecArgs.Clear;
Free;
end;
end;

Em todos os exemplos, o formato de sada das


compresses ser .zip, o que ir facilitar a posterior
leitura desses arquivos por outros programas na
plataforma Windows.
Aps compactarmos o diretrio, podemos
utilizar o ZipMaster para exibir o contedo do
dezembro 2011

19

arquivo Zip.
o que faremos no exemplo a seguir.
Crie uma nova aplicao no Delphi e monte o
layout conforme a imagem 05:
Essa aplicao ser utilizada para carregarmos
um arquivo .zip e listar quais arquivos compoem o
mesmo no ListBox. Essa listagem proporcionada
pelo componente ZipMaster.
Veja que temos apenas um boto no exemplo.
nele que ficar todo o cdigo necessrio, que
bem simples.
Inicialmente criaremos um OpenDialog filtrado
para exibir somente arquivos .zip.
No execute desse OpenDialog pegaremos o
caminho do arquivo .zip e carregaremos o mesmo
no componente ZipMaster. Aps isso listaremos os
arquivos no componente ListBox.
Veja o cdigo:

procedure TForm1.
Button1Click(Sender:
TObject);
var
i:integer;
sFileName:string;
begin
listboxarquivos.Items.
Clear;
with TOpenDialog.
Create(nil)do
try
Filter:=Zip
Files|*.zip;
if(Execute)then
sFileName:=FileName;
finally
Free;
end;
edtArquivo.
Text:=sFileName;

20

dezembro 2011

Imagem 06

Concluso
ZipMaster191.
ZipFileName:=sFileName;
for i:=0 to
ZipMaster191.Count-1 do
listboxarquivos.
Items.Add(ZipMaster191[i].
FileName);

Vimos neste artigo que Streams e o componente ZipMaster podem ser excelentes aliados em
nosso dia a dia quando necessitamos trabalhar com
arquivos. Tanto nos casos de transferncias dos
mesmos como para operaes mais complexas
como converses.
Por enquanto isso. At a prxima !

end;

Veja o aplicativo em execuo na imagem 06:

Sobre o autor
Antonio Spitaleri Neto
Consultor Tcnico The Club.

antonio@theclub.com.br

dezembro 2011

21

MTODOS RAVEReport
de A a Z

P
PRINT IMAGE RECT Este mtodo vai
chamar ImageStream na tela da impressora,
esticado ou encolhido para caber dentro do
retngulo definido pelos pontos (X1, Y1) e
(X2, Y2).

Create;
try
Image.
LoadFromFile(image1.
jpg);
Image.
SaveToStream(Stream);
Stream.Position := 0;
PrintImageRect(1,1,3,3,
Stream,JPG);
finally
Image.Free;
Stream.Free
end; {tryf}
end; {with}

Example (Delphi)
with Sender as TBaseReport
do begin
Stream := TMemoryStream.
Create;
Image := TJPEGImage.
22

dezembro 2011

PRINT JUSTIFY Este mtodo imprime esquerda, direita, centro ou bloco de


texto justificado. O texto deve ser justificado

dentro de um retngulo de medio a partir


de Pos e com um tamanho horizontal de largura. A margem o espao entre o texto e os
lados do retngulo de medio em unidades.
Example (Delphi)
PrintJustify(Centered
Text,
SectionLeft,pjCent
er,0.0,SectionRight SectionLeft);
{ Same as
PrintCenter(Centered
Text,
(SectionLeft +
SectionRight) / 2.0); }

PRINT LEFT este mtodo imprime

a strint Texto na linha atual, justificado


esquerda, na posio POS.
Example (Delphi)
RvNDRWriter1.PrintLeft(
Text left at 4.0, 4.0);

PRINT LINES Esse mtodo imprime

o buffer de memria para o nmero de linhas


especificadas por Lines. Se Lines 0, ento todas as linhas no buffer nota sero impressas.
Se PrintTabs for verdadeiro, ento PrintMemo
vai imprimir as linhas de guias em branco para
cada linha que o buffer de memria imprime.
Nota: se todo o buffer de memria no
impresso, a posio interna de MemoBuf
ser definida para o ltimo caractere que
foi impresso. Isso permitir que o buffer de
memoria seja continuado em outra pgina.
Nota: deve-se inicializar o TMemoBuf.
BaseReport antes de chamar esse mtodo

PRINT LN este mtodo imprime a


string Texto da mesma forma que o mtodo
Print faz, porm ele tambm chama NewLine
para ir para a prxima linha.

de tabs vazias para cada linha que o buffer de


memria imprime.

PrintTab(FieldByName
(Name));

Example (Delphi)
SetColumns(3,0.25);
MemoBuf.PrintStart :=
ColumnStart;
MemoBuf.PrintEnd :=
ColumnEnd;
PrintMemo(MemoBuf,
ColumnLinesLeft, false);
ClearColumns;

PRINT X,Y este mtodo imprime a


string Texto no local especificado pelo ponto
(X,Y).
Nota: a posio Y determina o local da
linha de base do texto impresso.
Example (Delphi)

PRINT PAGE este mtodo imprime


a pgina especificada pelo PageNum para a
janela de pr-visualizao. O evento OnPageChange chamado se mudar o nmero
atual de pginas.
Example (Delphi)
RvRenderPreview1.
PrintPage( 2);

PRINT RIGHT este mtodo imprime a


string Texto na linha atual, justificada direita,
na posio Pos.

RvNDRWriter1.PrintXY( 1.0,
2.0, Text above (1.0,
2.0));

PUSH FONT Este mtodo empurra


a fonte atual para uma pilha interna para
posterior recuperao pelo PopFont

PUSH POS este mtodo empurra a


posio atual do cursor de texto para uma
pilha interna para posterior recuperao
pelo PopPos.

Example (Delphi)
Example (Delphi)
RvNDRWriter1.Println(
Text on a line);
RvNDRWriter1.PrintLn(
Text on another line);

PRINT MEMO este mtodo impri-

me o buffer de memria, MemoBuf, para o


nmero de linhas especificado por Lines. Se
Lines 0, ento todas as linhas do buffer de
memria sero impressas. Se PrintTabs
verdadeiro, ento PrintMemo imprime linhas

RvNDRWriter1.
PrintRight(Right
justified at 3.0,3.0 );

PRINT TAB Este mtodo de imprime


a configurao de tabulao seguinte e, em
seguida, imprime texto dentro dessa caixa
de guia. Isso equivalente a impresso (# 9
+ texto), com a ressalva de que, se for muito
longo, oTexto truncado.

PUSH TABS Este mtodo empurra


as configuraes da guia atual em uma pilha
interna para posterior recuperao pelo
PopTabs.

Example (Delphi)

dezembro 2011

23

RECOVER PRINTER Este mtodo

recupera o identificador de impressora que


foi perdido por uma chamada anterior ao
mtodo ReleasePrinter.

RECTANGLE este mtodo desenha


um retngulo definido pelos pontos (X1, Y1)
E (X2, Y2).
O retngulo desenhado com uma
borda da caneta atual e preenchido com o
pincel atual.
Example (Delphi)
RvNDRWriter1.
Rectangle(1.0, 1.0, 4.0,
5.0);

cuo de um relatrio atravs TRvNDRWriter.


Example (Delphi)
Bitmap := TBitmap.Create;
with Sender as TBaseReport
do try
Bitmap.LoadFromFile(
LOGO.BMP );
UnregisterGraphic( 1 );
while not Table1.EOF do
begin
ReuseGraphic( 1 );
PrintBitmapRect(
1,1,2,2,Bitmap );
RegisterGraphic( 1 );
{ other printing code
}
end; { while }
finally
Bitmap.Free;
end; { with }

MemoBuf.ReplaceAll(ame,
Name, false);
MemoBuf.
ReplaceAll(ddress,
Address, false);

REPORT DESC TO MEMO inicializa


o componente Memo para o contedo atual
do relatrio selecionado.

RESET este mtodo retorna certas


configuraes (pena, pincel, origens, colunas,
tabs, sections e posio do cursor) para seus
valores padro.
Example (Delphi)
RvNDRWriter1.Reset;

REDRAW PAGE este mtodo redesenha a pgina atual para uma tela de
pr-visualizao.
Example (Delphi)
RvRenderPreview1.
RedrawPage;

RELEASE PRINTER Este mtodo

libera o identificador de impressora do


Rave, para que outros componentes, tais
como TPrinterSetupDialog, possam acessar
a impressora. Usar RecoverPrinter para re-inicializar o Rave e recuperar o identificador
de impressora.
Example (Delphi)

REGISTER GRAPHIC Este mtodo


vai ajudar a gerenciar a repetio de bitmaps
grandes em um trabalho de impresso. Pode-se registrar at 10 bitmaps de uma s vez,
passando o valor do ndice de 1 para 10. Com
este mtodo, apenas uma cpia do bitmap
armazenado no arquivo com todas as outras
funes de impresso fazendo referncia
mesma cpia.
Nota: Use UnregisterGraphic (n) para se
certificar de que o ndice de grfico que voc
est usando est limpo.
Nota: Este mtodo s vai otimizar a exe24

dezembro 2011

RvNDRWriter1.
ReleasePrinter;
PrinterSetupDialog1.
Execute;
RvNDRWriter1.
RecoverPrinter;

REPLACE ALL Este mtodo substitui

todas as ocorrncias de SearchText com ReplaceText. Se CaseMatters for verdadeiro, ento o caso dos caracteres deve corresponder.
Example (Delphi)

RESET LINE HEIGHT Este mtodo


redefine a propriedade LineHeight para a
fonte atual se a propriedade LineHeightMethod igual a lhmFont. Caso contrrio,
ResetLineHeight configura LineHeight para o
valor de 1,0 LinesPerInch ou deix-lo sozinho
se LineHeightMethod lhmUser.
Example (Delphi)
RvNDRWriter1.
ResetLineHeight;

RESET PRINTER Este mtodo ir


redefinir a impressora atual para as definies
dadas na estrutura DevMode bem como outras configuraes da impressora. Essa funo
chamada automaticamente sempre que
for alterada a impressora atual ou alterada
a orientao.

Example (Delphi)
RvNDRWriter1.ResetPrinter;

RESET SECTION Este mtodo re-

define os valores de seo, SectionLeft, SectionRight, SectionTop e SectionBottom para


ser igual s configuraes de margem atual.

RESTORE POSITION Este mtodo


define a posio do cursor de texto para a
configurao que foi armazenada por ltimo
no ndice ndice, pelo SavePos. Os valores
vlidos para ndice so de 1 a 10.
Example (Delphi)
RvNDRWriter1.
RestorePos(1);

RESET TABS Este mtodo redefine

a guia atual para o comeo. NewLine chama


essa funo para redefinir a guia atual.

RESTORE STATE Este mtodo restaura a posio do cursor e outras informaes de


estado do buffer de memria de volta ao que
era quando SaveState foi chamado.
Nota: Isso no afeta o contedo do
buffer de memria.

RESTORE BUFFER este mtodo

restaura o buffer de memria para o estado


em que estava durante a ltima chamada do
SaveBuffer.

RESTORE TABS Este mtodo restau-

ra as configuraes da guia, salvas por uma


chamada anterior a SaveTabs, usando um
ndice 1-10. O resultado desta funo ser
verdadeiro se a chamada for bem-sucedida.
Example (Delphi)
// Restaure as
configuraes da tab na
posio 3.
RestoreTabs(3);

RESTORE FONT Este mtodo restau-

ra as configuraes de fonte, salvo por uma


chamada anterior a SaveFont, usando um
ndice de 1 a 10. O resultado desta funo ser
verdadeiro se a chamada for bem-sucedida.
Example (Delphi)
// Restaura a fonte salva
na posio 10.
RestoreFont(10);

RTF LOAD FROM FILE carrega

um arquivo de texto RTF para o buffer de


memria.
Example (Delphi)

Example (Delphi)
RvNDRWriter1.ResetTabs;

Example (Delphi)
RoundRect
1.125,3.5,3.125,5.
0,0.25,0.25);

Example (Delphi)
RvNDRWriter1.ResetSection;

ROUND RECT este mtodo desenha


um retngulo definido pelos pontos (X1,Y1) e
(X2,Y2). Os cantos do retngulo sero desenhados como quartos de uma elipse com uma
largura de X3 e uma altura de Y3. O retngulo
ser desenhado com uma borda da caneta
atual e preenchido com o pincel atual.

MemoBuf1.RTFLoadFromFile(
Letter.RTF);

RTF LOAD FROM STREAM Carrega

um texto RTF de um processo para o buffer de


memria. Se BufSize 0 ento o comprimento
restante do processo lido, caso contrrio,
BufSize bytes que so lidos.

SAVE este mtodo salva o projeto

atual para o arquivo especificado pela propriedade ProjectFile.

REUSE GRAPHIC este mtodo permite o uso de um bitmap grande e repetido


em uma impresso que tenha sido registrada
com o mtodo RegisterGraphic. Com este
mtodo, somente uma cpia do bitmap ser
armazenada no arquivo com todas as outras
funes de impresso referentes mesma
cpia.
Nota: este mtodo somente otimiza a
execuo de um relatrio atravs de TRvNDRWriter.

SAVE BUFFER este mtodo salva o


buffer de memria atual para um buffer salvo
que pode ser recuperado mais tarde com RestoreBuffer. Pode ser til para imprimir cartas
que se deseja modificar em cada impresso,
mas que se deseja retornar s configuraes
originais no incio de cada pgina.

dezembro 2011

25

SAVE STATE este mtodo salva a posi-

Example (Delphi)
// Salva contedo
original.
MemoBuf.SaveBuffer;

SAVE FONT este mtodo salva as

configuraes atuais de fonte utilizando um


valor de ndice de 1 a 10. Estas configuraes
podem ser restauradas mais tarde, por uma
chamada ao mtodo RestoreFont. O resultado
desta funo ser true se a chamada foi bem
sucedida.
Example (Delphi)
// Salva as configuraes
de fonte atuais na posio
2.
SaveFont(2);

SAVE POS este mtodo armazena


a posio atual do cursor de texto em um
array de ndices, Index. Os valores vlidos
so de 1 a 10.

o atual do cursor, Pos, e outras informaes


de estado. Pode-se restaurar o estado anterior
do buffer de memria, chamando o mtodo
RestoreState.

SAVE TABS este mtodo limpa as


configuraes atuais de tabulao assim
como todas as salvas. No necessrio fazer
a chamada a este mtodo uma vez que as
tabulaes so limpas assim que o relatrio
esteja terminado.
Example (Delphi)
// Limpar todas as
tabulaes, inclusive as
salvas.
ClearAllTabs;

SAVE TO FILE este mtodo salva o


projeto de relatrio em um arquivo especificado pelo FileName.
Example (Delphi)
RvProject1.
SaveToFile(Project1.
Rav);

Example (Delphi)

Example (Delphi)
MemoBuf1.SaveToStream(
MyStream );

SEARCH FIRST Este mtodo inicia um


processo de pesquisa, procurando SearchText
desde o incio do buffer. Se CaseMatters for
verdadeiro, ento o caso dos caracteres deve
corresponder, de outra forma, o caso no
ser um fator para combinar. Esta funo ir
retornar true se ele encontrar uma correspondncia e false, se no. Usar SearchNext
para continuar a pesquisa aps a primeira
ocorrncia.
Example (Delphi)
// Armazena o nmero de
ocorrncias de APPLES in
apples
Apples := 0;
Found := MemoBuf.
SearchFirst(APPLE,
false);
while Found do begin
Inc(Apples);
Found := MemoBuf.
SearchNext;
end; { while }

RvNDRWriter1.SavePos(1);

SAVE RAVE BLOB Este mtodo salva

o projeto do relatrio atualmente carregado a


partir do formulrio da aplicao para Stream.
No preciso chamar essa funo uma vez
que o mtodo normal de salvar o projeto do
relatrio carregado feito atravs do editor
de propriedades TRvProject.StoreRAV.

SAVE TO STREAM este mtodo


salva o buffer de memria para o processo.

Sobre o autor
Leonora Golin
Consultora Tcnica The Club.

Example (Delphi)
RvProject1.SaveRaveBlob(
MyStream );

antonio@theclub.com.br

26

dezembro 2011

dezembro 2011

27

Dicas DELPHI
Criptografando dados de arquivos
Um recurso pra quem precisa utilizar arquivos externos e deseja proteg-los de usurios indevidos a criptografia de dados e registros. So conhecidas
muitas maneiras de se criptografar, porm algumas mais eficientes outras nem
tanto, uma referencia so os modelos de criptografia que seguem padres
especficos, o MD5 e o SHA1, que tratam exclusivamente de criptografia de
registros, convertendo os dados em uma sequencia numrica padro, mas o
grande problema dos sistemas criptografadores so que seus registros reais
se tornam no-identificveis pelo mtodo tradicional de leitura, dependendo
de seu mtodo criptografado para que possa ser lido, o que causa muitos
transtornos caso haja perda ou troca de senha.
Essa dica til para transferncia de registros que precisam estar ocultos
e inviolveis, onde transformado todo e qualquer caractere conhecido em
linhas no interpretveis.
O primeiro passo declarar a procedure que ter como parmetro de entrada o arquivo de entrada e o de sada, sendo do tipo String e a chave (do tipo
Word), que servir como controle para gerao da quantidade de caracteres
criptografados a partir dos arquivos de entrada e sada.

procedure TForm1.
Encriptar(arqEntrada, arqSaida:
String; Chave: Word);

Declaramos tambm 4 variveis, sendo duas do tipo MemoryStream, que


serviro de para o controle de entrada e sada, alm de uma do tipo Inteira,
que servir como contadora e outra do tipo Byte, que armazenar os valores
criptografados.

var
msEntrada, msSaida :
TMemoryStream;
I : Integer;
C : byte;

O primeiro passo inicializar as duas variveis do tipo MemoryStream, e na


varivel que recebera os registros de entrada, carregamos o arquivo informado
no parmetro para entrada e deixando na posio 0.

begin
msEntrada := TMemoryStream.
Create;
28

dezembro 2011

msSaida := TMemoryStream.Create;
try
msEntrada.
LoadFromFile(arqEntrada);
msEntrada.Position := 0;

Agora necessrio que seja realizado um loop de controle para que seja
verificado o tamanho do valor de memria, onde ser lido o valor em memria,
convertendo os caracteres para valores chave e escrevendo no MemoryStream
de sada, salvando o valor criptografado no arquivo de sada dos dados

for I := 0 to msEntrada.Size 1 do
begin
msEntrada.Read(C, 1);
C := (C xor not(ord(chave
shr I)));
msSaida.Write(C,1);
end;
msSaida.SaveToFile(arqSaida);

E por fim liberamos as duas variveis MemoryStream da memria

finally
msEntrada.Free;
msSaida.Free;
end;

E, para que seja chamado o arquivo no momento em que seja feita a criptografia pegando os dados de um arquivo de texto para outro basta chamar
a funo com os arquivos de entrada e sada dos dados e a quantidade de
caracteres gerados na criptografia.

procedure TForm1.
Button1Click(Sender: TObject);
begin
Encriptar(1.txt, 2.txt, 26);
end;

Concluso
Essa uma tcnica muito utilizada em softwares para aumentar a proteo
de dados contra o acesso indevido, e evitar perda ou desencontro de dados
de registros, ideal quando utilizados arquivos de textos simples para que no
sejam acessados e seus dados facilmente consultados.

Listando todas as urls visitadas no Internet Explorer


Uma das maneiras mais fceis de verificar e controlar o acesso a sites a
listagem de todas as URLs acessadas naquele computador, o que nos possibilita
com essa dica fazer com que o Delphi liste todos os links acessados para assim
possamos utilizar esta lista para controle de acesso a sites, contedo proibido
e downloads indevidos, baseados nesta listagem.
Para criarmos esse controle, primeiramente criaremos uma procedure
que nesta dica recebe o nome de ListaURL, e seu parmetro de retorno da
listagem sendo do tipo TStrings

Caso no tenha nenhum registro, primeiro instanciamos o objeto TStringList com o mtodo create, limpamos o componente ListBox, que ir receber
a listagem de URLs, pegando a listagem com os nomes da urls e inserindo na
StringList, e, caso no haja nenhum registro, ele ir dentro do comando de repetio FOR, pegar todos os nomes das URLs acessadas a partir deste momento.

begin
S := TStringList.
Create;
try
ListBox1.Clear;
reg.GetValueNames(S);
for i := 0 to S.Count
- 1 do

procedure TForm1.ListaURL(Urls:
TStrings);

Declaramos 3 variaveis, uma do tipo TRegistry, que far o acesso aos dados
de registros do Editor de Registros do Windows, uma do Tipo TStringList, que
armazenar a listagem de todas as URLS visitadas, e uma do tipo Integer que
ir auxiliar no controle de loops da procedure

begin
Urls.Add(reg.
ReadString(S.Strings[i]));
end;

Por fim liberamos da memria as variveis do tipo TStringList e TRegistry

finally
S.Free;
end;
Reg.CloseKey;
end;
finally
Reg.Free;
end;

var
Reg: TRegistry;
S: TStringList;
i: Integer;

Primeiro inicializamos o Tipo TRegistry com o mtodo create, instanciando


e preparando para que possaser utilizada

begin
Reg := TRegistry.Create;

end;

Para que seja executada esta funo basta chamar no evento OnClick a
procedure, informando como parmetro o objeto onde ser listado as URLs

ListaURL (ListBox1.Items);

Logo acessamos os ns dos Registros do Windows para encontrar o campo


TypedURLs, que a responsvel por controlar a listagem de todos os dados de
URL do Internet Explorer, fazendo uma verificao se sua chave est aberta.

Concluso
try
Reg.RootKey := HKEY_CURRENT_
USER;
if Reg.OpenKey(Software\
Microsoft\Internet Explorer\
TypedURLs, False) then

Essa uma funo bem simples mais muito utilizada em softwares que
fazem a verificao de controle de acesso a websites, sendo de fundamental utilizao, pois se baseiam nessa listagem permitir ou restringir os seus usurios.

dezembro 2011

29

Horizontal

30

dezembro 2011

Vertical

dezembro 2011

dezembro 2011