Você está na página 1de 32

janeiro 2012

janeiro 2012
índiceEditorial Delphi Delphi

04 05 12
2012 está aí e o mês de janeiro é o mês Criando uma aplicação Client- Android – Carregando um database
onde mais do que em server no Delphi do SQLite
qualquer época do - Parte 3
ano precisamos estar
Autor:Thiago Cavalheiro
animados para que Montebugnoli
comecemos bem... Autor:Luciano Pimenta

Delphi Delphi

17
Criando os primeiros aplicativos Métodos RAVReport - de A a Z -

22
com Lazarus parte 4

Autor: Antonio
Autor: Leonora Golin
Spitaleri

Dicas Desafio The Club

28 30
- Dicas Delphi - Cruzada

Legenda
Iniciante
Intermediário
Avançado

janeiro 2012 03
Bem-vindo Av. Profº Celso Ferreira da Silva, 190
Jd. Europa - Avaré - SP - CEP 18.707-150
Informações e Suporte: (14) 3732-1529
2012 está aí e o mês de janeiro é o mês onde mais do que em
qualquer época do ano precisamos estar animados, para que co- Internet
mecemos bem o ano. E como todos sabem, o que começa bem http://www.theclub.com.br

tem tudo para acabar melhor ainda. Cadastro: cadastro@theclub.com.br


Suporte: suporte@theclub.com.br
Informações: info@theclub.com.br

Para cumprirmos a meta de começar bem o ano então, prepa- Skype Cadastro: theclub_cadastro
Skype Suporte: theclub_linha1
ramos quatro artigos excelentes para esse mês: theclub_linha2

Começamos com a terceira parte da matéria de Luciano Pimen- theclub_linha3

ta: “Criando uma aplicação Client – Server em Delphi”. Essa matéria


sem dúvida ao longo dos últimos meses vem desmitificando a
lógica Client – Server em Delphi.
www.twitter.com/theclubbr

Na sequência Thiago Montebugnoli segue nos apresentando


a plataforma Android no artigo “Carregando uma base de dados
SqlLite”.
Esse mês apresento a vocês uma nova ferramenta aqui na re-
vista The Club. Trata-se do Lazarus, uma ferramenta baseada em Copyright The Club Megazine 2009
Delphi e que possui foco na multiplataforma, no artigo “Criando
as primeiras aplicações em Lazarus”. Diretor Técnico
Marcos César Silva

Para fechar temos a quarta parte da viagem de nossa colabo-


radora Leonora Golin pelos métodos do Rave Report no artigo Diagramação e Arte
Vitor M. Rodrigues
“Métodos Rave Report de A a Z”.
Revisão
Eliziane Valentim

É isso.Bom início de ano a todos e até fevereiro ! Colunistas


Antonio Spitaleri Neto
Bruno Alcarás
Eduardo Massud
www.datasmart.com.br Leonora Golin
Luciano Pimenta
Thiago Cavalheiro Montebugnoli
www.theclub.com.br
Impressão e acabamento:
GRIL - Gráfica e Editora
Taquarituba-SP - Tel. (14) 3762-1345

Reprodução
A utilização, reprodução, apropriação, armazenamento em banco
de dados, sob qualquer forma ou meio, de textos, fotos e outras
criações intelectuais em cada publicação da revista “The Club

Antonio Spitaleri Neto - Editor Chefe Megazine” são terminantemente proibidos sem autorização
escrita dos titulares dos direitos autorais.
antonio@theclub.com.br Delphi é marca registrada da Borland International,
as demais marcas citadas são registradas
pelos seus respectivos proprietários.

04 janeiro 2012
Delphi

Criando uma aplicação client-


server no Delphi
Parte III

Continuaremos neste artigo a criação da


nossa aplicação cliente-server com Delphi.
Até agora, já criamos os cadastros necessá-
rios para clientes, peças e veículos. Agora,
precisamos criar os cadastros referentes aos
serviços que a oficina realizará.

Primeiramente vamos criar o cadastro de


orçamento. A lógica do sistema indica que o
cliente chega e pretende fazer um serviço,
portanto, a oficina cadastra um orçamento
para ele. Não vamos usar agora, nosso for-
mulário base de cadastro. Teremos outro for-
mulário para isso, também herdado, mas com
características diferentes do que já vimos.
Figura 1. Formulário base da aplicação
Poderíamos usar o formulário visto até
aqui, mas teríamos que fazer adaptações e
deixo a cargo do leitor, se preferir, fazer isso.
novo. Ele tem características simples e alguns méto- Vamos criar o formulário de cadastro de or-
dos pré-definidos (veja o fonte que esta disponível çamento, que funcionará da seguinte maneira: o
para download). cliente chega e precisa ser cadastrado. Se o mesmo
Criando formulário já for cadastrado, basta digitar seu nome na caixa
Veja a figura 1. de texto e apertar ENTER.
Na Figura 1 podemos ver nosso formulário

janeiro 2012 05
Mostraremos uma tela com uma consulta
baseada no valor digitado pelo usuário. Essa tela
de consulta pode ser genérica e usarmos em ou-
tros pontos do sistema. Basta o usuário escolher o
valor desejado na tela de consulta que o sistema
irá preencher os dados do usuário e seu veículo.

No primeiro momento, imaginamos que o


cliente possua apenas um veículo, mas ele pode
ter mais de um. Assim, faça a adaptação necessária
para se o cliente tiver mais, seja mostrada uma tela
para o usuário escolher o veículo a ser arrumado.
Veja na Figura 2 a tela de orçamento.

Veja a figura 2.

Note que além da opção de digitação para


o cliente, que comentei a pouco, temos ainda o Figura 2. Tela de orçamento do sistema
botão para pesquisa de cliente (igual ao usado no
cadastro de veículos) e também o botão para incluir
um novo cliente.
O código SQL do cdsUltimoCliente, é simples:
Nesse botão, abrimos o cadastro de clientes e Create(self);
depois, filtramos os dados do último cliente inse-
rido, usando o MAX(nCdCliente) em um consulta select max(nCdCliente) as try
auxiliar. Veja o código na Listagem 1. nCdCliente from CLIENTE field :=
TIntegerField.Create(cds);
Listagem 1. Filtrando o novo registro field.FieldName :=
Para filtrar os dados do veículo, criamos mais ‘nCdVeiculo’;
um ClientDataSet para retornar os dados, de acordo field.DataSet := cds;
//abre o cadastro de com o cliente passado por parâmetro (filtrado no
clientes método FiltrarVeiculo). Como comentei anterior- field := TStringField.
AbreForm(TfrmCliente, mente, em uma aplicação real, teríamos que esco- Create(cds);
frmCliente); lher o veículo, já que o cliente pode ter mais de um. field.Name :=
‘sNmCliente’;
//após inserir, atualiza Depois da tela pronta e dos filtros configura- field.FieldName :=
com o último cliente dos, precisamos salvar o cadastro. Vamos utilizar ‘sNmCliente’;
criado a mesma classe criada anteriormente e usada nos field.Size := 50;
DM.cdsUltimoCliente.Open; cadastros. Poderíamos criar um ClientDataSet no field.DataSet := cds;
Data Module, e apenas preencher o mesmo com
DM.cdsCliente.Close; os valores digitados pelo usuário e executar o field :=
DM.cdsCliente.Params[0]. salvar da classe. TDateTimeField.
AsInteger := Create(cds);
DM.cdsUltimoClienten Nesse exemplo, vamos fazer diferente, vamos field.Name :=
CdCliente.AsInteger; criar o ClientDataSet em tempo de execução. Veja ‘tDtOrcamento’;
DM.cdsCliente.Open; o código na Listagem 2. field.FieldName :=
‘tDtOrcamento’;
edtCliente.Text := Listagem 2. Criando o ClientDataSet e salvando field.DataSet := cds;
DM.cdsClientesNmCliente. o orçamento
AsString; field := TStringField.
Create(cds);
//filtra o veículo procedure TfrmOrcamento. field.Name :=
FiltrarVeiculo(DM. Salvar; ‘sDsProblema’;
cdsClientenCdCliente. var field.FieldName :=
AsInteger); cds: TClientDataSet; ‘sDsProblema’;
field: TField; field.Size := 400;
DM.cdsCliente.Close; begin field.DataSet := cds;
cds := TClientDataSet.

06 janeiro 2012
field :=
TIntegerField.Create(cds);
field.Name :=
‘nIdStatus’;
field.FieldName :=
‘nIdStatus’;
field.DataSet := cds;

//preenche Cds
cds.CreateDataSet;
cds.Insert;
//variável auxiliar,
preenchida na filtragem do
veículo
cds.
FieldByName(‘nCdVeiculo’).
AsInteger := nCdVeiculo;
cds.
FieldByName(‘sNmCliente’). Figura 3. Cadastro de orçamento
AsString := edtCliente.
Text; Note que com a utilização da nossa classe,
cds.FieldByName fica simples, salvar o orçamento. Pode parecer Text;
(‘tDtOrcamento’). trabalhoso, e é, criar o ClientDataSet em tempo DM.cdsOrcamentotDt
AsDateTime := de execução, mas usamos aqui, apenas para fins Orcamento.AsDateTime :=
dtDataOrcamento.Date; didáticos. dtDataOrcamento.Date;
cds.FieldByName
(‘sDsProblema’).AsString Criamos o ClientDataSet, os campos neces- DM.cdsOrcamentosDsProblema.
:= mmProblema.Text; sários e preenchemos o valor do mesmo. Depois AsString := mmProblema.
cds.FieldByName apenas configuramos a classe, como já fizemos na Text;
(‘nIdStatus’).AsInteger := tela de cadastro. Simples e prático. Veja na Figura
1; //orçamento ativo 3 o cadastro em execução. DM.cdsOrcamentonIdStatus.
cds.Post; AsInteger := 1;
Veja a figura 3.
FClasseBase.Conection DM.cdsOrcamento.Post;
:= DM.SysCar; Caso você deseje não usar esse método onde
FClasseBase.sNmTabela criamos o ClientDataSet em tempo de execução, FClasseBase.Conection
:= ‘ORCAMENTO’; basta colocar um componente no DataModule, := DM.SysCar;
FClasseBase.Campos := criar os campos e alterar o Salvar para o código FClasseBase.sNmTabela
cds; da Listagem 3. := ‘ORCAMENTO’;
if FClasseBase. FClasseBase.Campos :=
Salvar(true) then Listagem 3. Alterando o método Salvar para o DM.cdsOrcamento;
begin ClientDataSet do DataModule if FClasseBase.
MessageDlg( Salvar(true) then
‘Registro salvo com ...
sucesso’, mtInformation, procedure TfrmOrcamento. end;
[mbOk], 0); Salvar;
//limpa tela e begin
fecha DataSet DM.cdsOrcamento. Temos ainda que fazer a validação dos campos
LimparCampos; CreateDataSet; obrigatórios. Então, criei um método, que verifica
dsVeiculo.DataSet. DM.cdsOrcamento.Insert; os campos obrigatórios não preenchidos e emite
Close; uma mensagem. Veja o código na Listagem 4.
nCdVeiculo := 0;
end; DM.cdsOrcamentonCdVeiculo. Listagem 4. Validando campos obrigatórios
finally AsInteger := nCdVeiculo;
field.Free;
cds.Free; DM.cdsOrcamentosNmCliente. function TfrmOrcamento.
end; AsString := edtCliente. Validar: boolean;
end;

janeiro 2012 07
begin
if edtCliente.Text = ‘’
then
MessageDlg(‘Campo:
Nome do cliente.
Preenchimento
obrigatório.’,
mtWarning,[mbOk], 0)
else if mmProblema.Text
= ‘’ then
MessageDlg(‘Campo:
Problema indicado pelo
cliente. Preenchimento
obrigatório.’, Figura 4. Tela de pesquisa genérica do sistema
mtWarning,[mbOk],
0);

Result := (edtCliente. Listagem 5. Codificando o end;


Text <> ‘’) and KeyPress do Edit end;
(mmProblema.Text <> ‘’); if Key = #13 then
end; begin //se preencheu nome,
DM.cdsPesquisaCliente. então filtra o veiculo
Close; if edtCliente.Text <>
No evento do botão, basta executar o código: DM.cdsPesquisaCliente. ‘’ then
Params[0].AsString := FiltrarVeiculo(DM.
UpperCase(edtCliente. cdsPesquisa
if Validar then Text+’%’); ClientenCdCliente.
Salvar; DM.cdsPesquisaCliente. AsInteger);
Open; end;

if
Pesquisa genérica DM.cdsPesquisaCliente. Note que passamos para o componente de
RecordCount = 1 then pesquisar clientes o valor digitado pelo usuário.
edtCliente.Text := Se o resultado da pesquisa retornar um registro,
Como comentei, uma funcionalidade que te-
DM.cdsPesquisaClientesNm preenchemos o valor do nome do cliente com esse
remos no orçamento é a do usuário digitar o nome
Cliente.AsString registro. Caso a quantidade de registros encontra-
do cliente, apertar ENTER e será mostrada uma else if dos, for maior, então mostramos a tela de pesquisa.
tela de pesquisa de clientes com os parâmetros DM.cdsPesquisaCliente.
digitados pelo usuário. RecordCount > 1 then Veja que não usamos nosso código de abrir
begin formulário, por que precisamos configurar algumas
A tela de pesquisa em si, será simples. Basta try propriedades do formulário de pesquisa. Assim,
um grid e um botão de confirmação. A boa notícia, frmPesquisa := passamos o DataSet que será mostrado, bem como
que podemos utilizar a mesma em outros pontos TfrmPesquisa.Create(self); o nome da coluna de descrição de registros.
da aplicação, apenas mudando o DataSet esperado frmPesquisa.
pelo Grid. Veja na Figura 4 a tela de pesquisa. dsPesquisa.DataSet := Caso deseje usar a tela em outro formulário,
DM.cdsPesquisaCliente; basta mudar o DataSet e a variável do nome da
frmPesquisa. coluna. Bem simples, com muito reaproveitamento
Veja a figura 4.
Descricao := ‘Nome do de código. Veja na Figura 5 a tela em execução.
cliente’;
Ao olhar o código, você irá notar que temos if frmPesquisa. Veja a figura 5.
configuração para o nome das colunas do Grid, ShowModal = mrOk then
além de mostrar a quantidade de registros encon- edtCliente.
trados. A tela é bastante semelhante a da pesquisa Text := Pesquisando orçamentos
do componente Localizar. DM.cdsPesquisaClientesNm
Cliente.AsString Após a criação do orçamento, os funcionários
No Edit da tela de orçamento, vamos codificar finally da oficina, irão verificar os problemas do veículo.
seu evento OnKeyPress com o código da Listagem 5. frmPesquisa.Free; Assim, necessitam preencher o parecer do orça-
mento. Precisamos criar uma tela de pesquisa de

08 janeiro 2012
orçamentos para o usuário escolher o orçamento,
salvar os dados do parecer e indicar se deseja que
o orçamento, se “transforme” em uma ordem de
serviço. Veja na Figura 6 a tela.

Veja a imagem 6.

A consulta que retorna os dados do orçamento


esta no código a seguir:

select ORC.nCdOrcamento,
ORC.nCdVeiculo, ORC.
sNmCliente,
ORC.tDtOrcamento,
VE.sNrPlaca, VE.sNmModelo
from ORCAMENTO ORC
inner join VEICULO VE
on VE.nCdVeiculo = ORC.
nCdVeiculo
where ORC.nIdStatus = 1
Figura 5. Tela de pesquisa sendo usada no orçamento

Estamos trazendo os dados do orçamento que


estejam ativos (nIdStatus = 1). Para filtrar os dados
pela placa, não refaremos a consulta, usaremos o
ClientDataSet para isso. Ou seja, teremos os dados
em memória, sem precisar “ir” no servidor para o
novo filtro.

Veja no código da Listagem 6 o código.

Listagem 6. Filtrando os dados do ClientData-


Set em memória

if edtPlaca.Text <> ‘’
then
begin

DM.cdsPesquisaOrcamento.
Filter := ‘sNrPlaca = ‘ + Figura 6. Tela de pesquisa de orçamentos
QuotedStr(edtPlaca.
Text);
fazendo uma pesquisa aproximada, mas sim, exata.
DM.cdsPesquisaOrcamento.
Filtered := true; A propriedade Filtered “ativa” o filtro. Assim,
end caso você deseje retornar para a pesquisa total,
else basta limpar a caixa de texto e clicar no botão.
Para editarmos o orçamento, bastará dar um duplo
DM.cdsPesquisaOrcamento. clique no registro no Grid.
Filtered := false; Figura 7. Editando o orçamento
Aqui, vamos apenas alterar o valor do parecer
na tabela, não editaremos nenhum outro dado. O DBText1 nada mais é do que campo calcula-
Verificamos se foi digitado algum valor na caixa Você pode adaptar para editar os registros que do que concatena os campos nome do cliente, placa
de texto. Caso positivo, passamos para a proprieda- desejar. Vamos criar um formulário com os dados e modelo. Para criar o campo calculado, acesse o
de Filter do ClientDataSet o que desejamos filtrar, do orçamento e um campo para edição. Veja na componente de pesquisa de orçamentos. Abra o
no caso o número da placa. Note que não estamos Figura 7 o formulário. editor de campos e aperte Ctrl + N. Adicione as

janeiro 2012 09
configurações, conforme a Figura 8.

Veja a figura 8.

Para que possamos mostrar a concatenação


dos campos, devemos usar o evento OnCalcFields
do ClientDataSet. Adicione o seguinte código:

cdsPesquisaOrcamentos
DsMensagem.AsString :=
cdsPesquisaOrcamentos
NmCliente.AsString + ‘ - ‘
+
cdsPesquisaOrcamentos
NrPlaca.AsString + ‘ - ‘ +
cdsPesquisaOrcamentos Figura 8. Configurando um campo calculado no ClientDataSet
NmModelo.AsString;

No código, estamos preenchendo o campo, Query.Free;


com a “junção” dos campos que queremos mostrar. end;
Devemos agora, configurar a edição do orçamen- end;
to, com o parecer. Não vamos usar a classe que
estamos acostumados. Vamos alterar apenas um
campo, acredito que não vale a pena o esforço. Para testar, apenas chamamos o método no
Salvar do formulário, conforme a Listagem 8. igura 9. Cadastro em execução
Portanto, vamos apenas atualizar o parecer,
usando um comando SQL simples em um método Listagem 8. Salvando o parecer
no DataModule. Veja o código na Listagem 7. Conclusões

Listagem 7. Método para atualizar parecer if mmParecer.Text = ‘’


Vimos nesse artigo a criação da tela de orça-
then
do Orçamento mento da aplicação. Também criamos algumas
MessageDlg(‘Campo:
Parecer. Preenchimento funcionalidades interessantes na mesma, como a
obrigatório.’, tela de pesquisa, que pode ser genérica e ser usada
procedure TDM. mtWarning,[mbOk], 0) em vários locais da nossa aplicação.
AtualizarParecer(sDs else
Parecer: string; begin No próximo artigo, vamos começar a criar a
nCdOrcamento: integer); DM.AtualizarParecer tela de ordem de serviço que terá peculiaridades
var (mmParecer.Text,
sql: string; interessantes, pois precisaremos adicionar peças/
DM.cdsPesquisaOrcamen serviços em memória para depois, quando o usu-
Query: TSQLQuery; tonCdOrcamento.AsInteger);
begin ário confirmar, todos os itens serem adicionados
MessageDlg(‘Registro
sql := ‘update ORCAMENTO no banco.
salvo com sucesso’,
set sDsParecer = ‘ + mtInformation, [mbOk], 0);
QuotedStr(sDsParecer) Close; Um grande abraço a todos e até a próxima!
+ ‘ where nCdOrcamento =
end;
‘ +

IntToStr(nCdOrcamento);

Query := TSQLQuery.
Sobre o autor
Create(nil); Luciano Pimenta
É Técnico em Processamento de Dados, desenvolvedor Delphi/C# para aplicações
Web com ASP.NET e Windows com Win32 e Windows Forms. Palestrante da 4ª edição
try da Borland Conference (BorCon).
Query.SQLConnection := Autor de mais de 60 artigos e de mais de 300 vídeos aulas publicadas em revistas
e sites especializados. É consultor da FP2 Tecnologia (www.fp2.com.br) onde ministra
SysCar; cursos de programação e banco de dados. É desenvolvedor da Paradigma Web Bussi-
Query.SQL.Clear; ness em Florianópolis-SC.
Query.SQL.Add(sql); www.lucianopimenta.net
Query.ExecSQL();
finally

10 janeiro 2012
janeiro 2012 11
Android – Carregando
um database do SQLite
“Professional” é paga, portanto com alguns recursos adicionais, mas no nosso
No artigo deste mês continuaremos falando do pequeno e notável caso que não queremos gastar nada utilizaremos a versão “Personal” que pode
Sistema Android junto com o SQLite. Pudemos conferir no mês anterior ser baixada no seguinte endereço:
um exemplo simples de cadastro utilizando uma classe para acesso a
dados. Criamos na mesma classe os comandos DML(Data Manipulation http://www.sqliteexpert.com/download.html
Language) e os DDL(Data Definition Language), ou seja, definimos nossa
Base de Dados e manipulamos nossos dados via código.
A instalação
Neste artigo irei explorar um gerenciador do Banco de Dados SQLite
chamado “SQLite Expert Personal” e depois criaremos um projeto para A instalação é bem fácil e prática, Next, Next, Next e Install, a Figura 01
carregar os dados inseridos pelo mesmo. Tenho como objetivo carregar nos proporciona a conclusão da mesma.
um arquivo .db do SQLite que já está pronto, com suas tabelas definidas e
com dados. Isto se faz necessário, pois torna fácil a manipulação e criação
de estruturas para o Banco de Dados deixando a parte da programação
no Android apenas para comando de Manipulação de Dados.

SQLite Expert Personal

Este gerenciador de Banco de Dados possui várias funções disponíveis


suportando visualizações de várias Bases de Dados simultaneamente, permite
gerenciar campos de índice e chaves primárias. Possui também ferramentas
para criação de gatilhos e visões.

O “SQLite Expert Personal” tem uma interface bem simples e intuitiva para
que qualquer pessoa possa utilizá-lo. É interessante informar que a versão Figura 01: Instalação do SQLite Expert Personal.

12 janeiro 2012
Criando uma Base de Dados
[EST_CLI] VARCHAR(2),
[CEP_CLI] VARCHAR(15),
Veremos como é fácil a manipulação no SQLite Expert Personal, depois
CONSTRAINT [] PRIMARY KEY ([COD_CLI]));
de iniciado clique em File/New database para podermos criar nossa base de
Dados, defina as seguintes configurações,
Logo em seguida armazenaremos alguns dados para prosseguirmos nosso
Ver Imagem 02. exemplo prático.

Database File: C:\Users\THIAGOO\Desktop\DBTHECLUB


Database Alias: DBTHECLUB
Encoding: UTF-8
Page Size: 1024
Auto Vacuum: 0

Figura 04: Exemplo de inserção de Dados na tabela TB_CLIENTE.

Criando a tabela de Metadados


Figura 02: Propriedades. Para podermos trabalhar com o SQLite precisamos criar uma tabela de
controle interno denominada “android_metadata” com o seguinte campo
“locale” do tipo TEXT e atribuir um registro “en_US”.
Criando uma Tabela
Veja a instrução SQL para isto:
Para isto clique com o botão direito em cima do “DBTHECLUB” e escolha
“New Table”. Em Table Name defina como TB_CLIENTE e no botão ADD adi-
cionaremos os seguintes campos, veja abaixo: CREATE TABLE android_metadata (locale
TEXT);

Figura 05: Exemplo de inserção de Dados na Tabela android_metadata.

Criando uma Classe para acesso

Figura 03: Campos Necessários. Para isto precisamos criar um exemplo básico em Android clicando em
“File/New/ Android Project” e logo em seguida crie também uma classe e
O comando para criar a tabela ficou da seguinte maneira: importe alguns pacotes para podermos prosseguir nosso exemplo.

CREATE TABLE [TB_CLIENTE] ( package Pct.BancoDados;


[COD_CLI] INT NOT NULL,
[TIP_CLI] VARCHAR(20), import java.io.FileOutputStream;
[NOM_CLI] VARCHAR(50), import java.io.IOException;
[END_CLI] VARCHAR(50), import java.io.InputStream;
[BAI_CLI] VARCHAR(50), import java.io.OutputStream;
[CID_CLI] VARCHAR(40), import java.util.ArrayList;

janeiro 2012 13
import java.util.List; if (!dbExist)
{
import android.content.Context; this.getReadableDatabase();
import android.database.Cursor;
import android.database.SQLException; try
import android.database.sqlite. {
SQLiteDatabase; this.copiarDataBase();
import android.database.sqlite. }
SQLiteException; catch (IOException e)
import android.database.sqlite. {
SQLiteOpenHelper; throw new Error(“Erro ao
import android.database.sqlite. copiar o Banco de Dados!”);
SQLiteStatement; }
}
public class Base extends SQLiteOpenHelper }
{

} Este Método é responsável por criar nossa Base de Dados, ou seja, uti-
liza a função copiarDataBase(); para obter os dados que está na nossa pasta
“assets” e jogar para nosso Sistema Android. Verifiquem que utilizamos mais
É interessante lembrar que esta classe herda da SQLiteOpenHelper. Para uma função para checar se nossa Base de Dados já está criada, denominada
entendermos melhor, iremos utilizar o arquivo gerado pelo “SQLite Expert Per- checkDataBase() .
sonal”. Copie o arquivo localizado em C:\Users\THIAGOO\Desktop\DBTHECLUB
ou no lugar que foi criado e cole no diretório “assets” do nosso exemplo. Neste Abaixo as duas importantes funções que utilizaremos ao decorrer do artigo.
caso programaremos uma rotina para copiar a base de dados para dentro do
exemplo em questão.
private void copiarDataBase() throws
Voltando a criação de nossa classe, definiremos logo em seguida alguns IOException
atributos para a mesma, veja abaixo o código completo com uma breve expli- {
cação de seus métodos para melhores detalhes:
InputStream myInput = dbContexto.
getAssets().open(DB_NAME);
public class DataBaseHelper extends String outFileName = DB_PATH + DB_
SQLiteOpenHelper NAME;
{ OutputStream myOutput = new
FileOutputStream(outFileName);
private static String DB_PATH=”/data/data/
Pct.BancoDados/databases/”; private
byte[] buffer = new byte[1024];
static String DB_NAME = “DBTHECLUB.db”;
private SQLiteDatabase dbQuery; int length;
private final Context dbContexto; while ((length = myInput.
read(buffer))>0)
{
myOutput.write(buffer, 0,
O primeiro atributo armazenará o caminho do Banco de Dados, o segundo length);
o Nome e as duas últimas são variáveis para controle interno sendo uma o }
Cursor de Nossa Classe SQLiteDatabase e outra o nosso Contexto em si.
myOutput.flush();
myOutput.close();
public DataBaseHelper(Context context) myInput.close();
{
super(context, DB_NAME, null, 1); }
this.dbContexto = context;
}
private boolean checkDataBase()
{

Este é o Construtor de nossa classe DataBaseHelper, ele captura e mantém SQLiteDatabase checkDB = null;
uma referência do contexto passado para ter acesso aos recursos da aplicação.
try
{
public void CriarDataBase() throws String myPath = DB_PATH + DB_
IOException NAME;
{ checkDB = SQLiteDatabase.
openDatabase(myPath, null, SQLiteDatabase.
boolean dbExist = checkDataBase();

14 janeiro 2012
mesma posteriormente.
OPEN_READONLY);

} Já o Método selecionaTodos() nos devolve uma lista de strings para poder-
catch (SQLiteException e) mos trabalhar, falaremos um pouco mais deste método quando chamarmos o
{} mesmo pela nossa IDE do Android.

if (checkDB != null) E por final finalizamos nossas variáveis com o método Close().
{
checkDB.close();

} Criando um exemplo Básico

return checkDB != null ? true : Depois de Criarmos nossa classe de acesso, finalizamos criando um exem-
false; plo para selecionar todos os clientes cadastrados no SQLite, adicionamos então
} apenas um Label em nossa tela principal e definimos sua ID para out_text, Ver
Figura 06 e logo abaixo o código fonte.
public void abrirDataBase() throws
SQLException
{
String myPath = DB_PATH + DB_NAME;
dbQuery = SQLiteDatabase.
openDatabase(myPath, null,
SQLiteDatabase.OPEN_READONLY);
}

public List<String> selecionaTodos(String


NomeTabela, String OrdemCampo, String...
TipoCampos)
{
List<String> list = new
ArrayList<String>();
Cursor cursor = dbQuery.
query(NomeTabela, TipoCampos,
null, null, null, null, OrdemCampo);
if (cursor.moveToFirst())
{
do {
list.add(cursor.getString(0) +” - “ +
cursor.getString(1) + “ - “+ cursor.
getString(2));
}
while (cursor.moveToNext());
}
Figura 06: Tela.
if (cursor != null && !cursor.
isClosed())
{ <?xml version=”1.0” encoding=”utf-8”?>
cursor.close(); <LinearLayout xmlns:android=”http://
} schemas.android.com/apk/res/android”
return list; android:orientation=”vertical”
} android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
@Override >
public synchronized void close() <TextView
{ android:id=”@+id/out_text”

if (dbQuery != null) android:layout_width=”fill_parent”

dbQuery.close(); android:layout_height=”wrap_content”

super.close(); android:text=”@string/hello”
} />
} </LinearLayout>
No evento OnCreate é onde programaremos
nossa rotina para chamar o método
O método abrirDataBase() permite que armazenemos todas as informa- SelecionarTodos(), abaixo o código fonte
ções referentes ao Banco de Dados em uma variável, possibilitando o uso da completo para melhores detalhes:

janeiro 2012 15
package Pct.BancoDados; Campos para Selecionar: COD_CLI, NOM_CLI,
TIP_CLI
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle; E por final armazenaremos em uma StringBuilder para podermos jogar
import android.widget.TextView; em nossa variável “output”.
import java.util.List;

public class BancoDadosActivity extends


Activity {

TextView output;
@Override
public void onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

output = (TextView) this.


findViewById(R.id.out_text);

DataBaseHelper db = new
DataBaseHelper(this);

try
{
db.createDataBase();
} Figura 07: Exemplo em Run Time.
catch (IOException e)
{
e.printStackTrace(); Conclusões
}
Pudemos aprender neste artigo um pouco da utilização da ferramenta
db.openDataBase(); “SQLite Expert Personal”. Vimos que a mesma possibilita a manutenção e a
List<String> names = administração tanto da parte de criação quanto na manipulação de dados.
db.selecionaTodos(“TB_CLIENTE”,”COD_CLI”,
“COD_CLI”, “NOM_CLI”, “TIP_CLI”); O objetivo deste artigo foi de demonstrar a possibilidade de ter um ban-
StringBuilder sb = new co de dados já criado e usá-lo em uma aplicação Android. Percebemos que
StringBuilder(); isto é possível e muito prático em alguns casos específicos e se torna muito
sb.append(“Clientes viável para o desenvolvedor, pois o Banco de Dados é facilmente manipulado
Cadastrados:\n”); por fora do sistema, se tornando independente da aplicação. A criação de
for (String name : names) Classes e métodos específicos torna o sistema mais genérico e de uma fácil
{ implementação futura.
sb.append(name + “\n”);
} Espero que este exemplo básico seja de grande ajuda,

output.setText(sb.toString());
}
Um forte abraço e até o mês que vem!
}

Sobre o autor
Primeiro definimos uma variável para armazenar nosso resultado, denomi-
nada “output”, logo em seguida instanciamos nossa classe “DataBaseHelper” Thiago Cavalheiro Montebugnoli
criada anteriormente. Utilizaremos o método “criarDatabase()” e depois o Thiago Cavalheiro Montebugnoli é tecnólogo, formado pela Faculdade
de Tecnologia de Botucatu – SP (FATEC) foi consultor técnico do The Club, já
abrirDataBase(). desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco
de Dados SQL Server e Firebird. Atualmente trabalha no Centro de Proces-
samento de Dados da Prefeitura Municipal de Itaí-SP. Possui as seguintes
O método selecionaTodos() possui os seguinte parâmetros: certificações: MCP - Microsoft Certified Professional, MCTS - Microsoft Certi-
fied Technology Specialist, MCAD - Microsoft Certified Application Developer
e MCSD - Microsoft Certified Solution Developer.
thiago@theclub.com.br
Nome da Tabela: TB_CLIENTE
Ordenação: COD_CLI

16 janeiro 2012
Criando os primeiros
aplicativos com
Lazarus
Os programadores Delphi que antes de se Não iremos propor nesse artigo a substi- Nesse site são encontradas a documentação
“aventurarem” pelo mundo da programação tuição do Delphi pelo Lazarus. Ao contrário. disponível sobre o Lazarus e na seção Downloads,
visual, com janelas, botões, etc... passaram Iremos mostrar que o uso integrado de ambas as diversas opções:
pela programação modo console com certeza as ferramentas pode ser possível e até reco-
se não trabalharam, ouviram falar do compi- mendado em alguns casos. Veja a imagem 01.
lador FreePascal e sua IDE.
O que facilita e muito a vida dos progra- Veja que o Lazarus está disponível não só para
FreePascal é hoje um compilador que madores Delphi que pensam em conhecer o Windows, como também para Linux, Solaris, Mac
evoluiu bastante e teve incoraporadas Lazarus é o fato de 90% ou mais dos códigos OS entre outros. Escolha a opção que se adequa a
diversas melhorias, inclusive a capacidade Delphi serem compatíveis com Lazarus. Além seu sistema operacional e faça o download.
de compilação para Linux, MacOs e outras disso a própria ferramenta possui um Wizard
plataformas, até mesmo móveis. para conversões de projetos Delphi para Para usuários Windows, a instalação segue o
Lazarus e vice-versa. padrão de instalação, com a execução de um insta-
Você deve estar se perguntando porque lador que fará algumas perguntas sobre localização
estou falando de FreePascal se o mesmo não O Lazarus também conta hoje com acesso de arquivos entre outras.
possui boas funcionalidades para aplicações nativo aos principais bancos de dados Open
comerciais. Isso está correto, porém existe um Source: Firebird, MySql e SqlLite. Para Linux, existe a opção de baixar os pacotes
excelente projeto OpenSource que se destina RPM, para OpenSuse, Mandriva e outras distros
a aplicações comerciais e que faz uso do Outra característica importante a se derivadas do Red Hat ou então os pacotes Deb,
compilador FreePascal. Trata-se do Lazarus. destacar no Lazarus é que podemos instalar a para as distribuições baseadas em Debian, como
principal suíte de componentes para automa- o Ubuntu.
Quando surgiu, em suas primeiras ver- ção comercial existente hoje: ACBr. Isso sem
sões, a comunidade Delphi não deu muita dúvida é de grande ajuda para quem trabalha Após concluir a instalação, já podemos exe-
importância ao Lazarus, devido ao fato de com ECF’s e Nota fiscal eletrônica. cutar o Lazarus. A tela inicial, que pode variar
possuir muitos bugs e ter um visual de IDE dependendo do sistema operacional utilizado, será
pouco atrativo. Porém ao longo dos últimos semelhante a vista na imagem 2:
releases , esses problemas tem sido gradual-
mente solucionados e hoje podemos afirmar Download e Instalação Veja a imagem 02.
que Lazarus é sim uma alternativa muito boa
ao Delphi nas situações em que o custo da O site oficial do projeto é: Veja que a IDE é bem semelhante ao Delphi.
licença do mesmo se torna inviável. Assim que abrimos o aplicativo, nos é dado um
http://www.lazarus.freepascal.org/
janeiro 2012 17
projeto já carregado com um formulário. Temos o
Object Inspector à esquerda e acima a paleta de
componentes.

É na paleta de componentes que está a princi-


pal diferença inicial entre Delphi e Lazarus, já que
muitos componentes que temos no Delphi não
temos em Lazarus. Não temos por exemplo as di-
versas abas de componentes de acesso a banco de
dados: DbExpress, ADO, etc... As conexões a banco
estão agupadas na aba SqlDB. Uma característica
interessante é que temos acesso nativo ao banco
de dados SqlLite.

A aba mais semelhante sem dúvida é a Stan-


dard, onde temos os componentes mais básicos:
Edit, Label, ComboBox, entre outros.
Imagem 01.
Lembrando que não temos, devido ao fato da
ferramenta ser multiplataforma, os componentes
que são característicos do Windows e que em
Delphi ficam na aba Win32, como por exemplo
o ListView.

Em artigos posteriores estaremos estudando


em maiores detalhes os componentes do Lazarus.

Criando as primeiras aplicações.


Para começar, iremos criar uma aplicação que
pedirá um valor ao usuário e retornará esse valor
por extenso.

Na barra de menus do Lazarus, selecione


File – New.

Na janela mostrada na imagem 3. Selecione Imagem 02.


Application.

Veja a imagem 03. FileUtil, Forms, Controls,


Graphics, Dialogs,
Será aberta a janela inicial do projeto. StdCtrls;

Iremos utilizar três componentes da aba type


Standard:
{ TForm1 }

Edit(Aba Standard): TForm1 = class(TForm)


Button1: TButton;
Name:Edit1; Edit1: TEdit;
Text:’Digite o valor aqui’ Label1: TLabel;
Imagem 04. procedure
Label(Aba Standard): Button1Click(Sender:
Name:Label1; Vamos agora ao código da aplicação: TObject);
Caption:Valor por extenso private
{ private declarations
Button(Aba Standard): }
unit Main; public
Name: Button1;
Caption:’Extenso’ { public declarations
{$mode objfpc}{$H+} }
end;
interface
Monte o Layout do formulário conforme a var
imagem 4: uses Form1: Tform1;
Classes, SysUtils,

18 janeiro 2012
// Os três arrays a seguir
são os valores por extenso
que serão utilizados para
a construção da
// string de resultado da
função extenso

Dezenas:array[0..9]ofstrin
g=(‘Dez’,’Vinte’,’Trinta’,
’Quarenta’,’Cinquenta’,’Se
ssenta’,’Setenta’,’Oitenta
’,’Noventa’,’Cem’;

UnidadesDez:array[0..4]of
string=(‘Onze’,’Doze’,’Tre
ze’,’Quatorze’,’Quinze’);

Unidades:array[0..8]of str
ing=(‘Um’,’Dois’,’Três’,’Q
uatro’,’Cinco’,’Seis’,’Set
e’,’Oito’,’Nove’);

implementation

{$R *.lfm}
Imagem 03.
// Na sequência a função
que receberá um valor
inteiro e o devolverá por array Unidades unidadesdez
extenso
Result:=Unidades[Valor-1] if(Fator=0)
function Extenso(Valor: else then
Integer): String; begin
var if(Dezena=1) Result:=Dezenas[Dezena-1]
Fator, then else
Dezena:Integer; begin
begin Result:=Dezenas[Dezena-1]+’
// Se o e ‘+Unidades[Fator-1];
if not(Valor valor estiver entre 10 e end;
in[0..100])then 19, retornamos a string end;
// Limitamos o fazendo uso do end;
valor a ser digitado pelo //array end;
usuário, gerando uma UnidadesDez end;
exceção caso o mesmo seja
// maior que 100 { TForm1 }
if(Fator=0)
raise Exception. then // Aqui o evento OnClick
Create(‘Escolha um valor do Button1, onde pegamos
entre 0 e 100 !’) Result:=’Dez’ o valor digitado pelo
else else usuário e utilizamos
begin begin // a função extenso para
if(Valor=0)then retornar a string com o
Result:=’Zero’ if(Fator<=5)then valor por extenso.
// Retorna ‘zero’ caso procedure TForm1.
o número escolhido pelo Result:=UnidadesDez Button1Click(Sender:
usuário seja 0 [Fator-1] TObject);
else else begin
begin Label1.Caption:=Extenso
Fator:=Valor mod Result:=Dezenas[Dezena- (StrToInt(Edit1.Text));
10; // Pegamos o resto da 1]+’e’+LowerCase(Unidades[ end;
divisão do valor por 10 Fator-1]);
Dezena:=Valor div end; end.
10; // Pegamos a parte end
inteira da divisão acima else
begin Na sequência, vamos criar uma aplicação para
if(Dezena=0)then exibirmos uma imagem.
// Se o valor for // Caso o
menor que 10, retornamos a valor esteja acima de 19,
string correspondente do não faremos uso do array Vamos utilizar quatro componentes:

janeiro 2012 19
OpenDialog(Aba Dialogs)

Image(Aba Additional):
Name:Image1;
Stretch:True

Button(Aba Standard):
Name:Button1;
Caption:’Selecione a imagem’;

Label(Aba Standard):
Name:Label1;
Caption:’Caminho da imagem’

O layout deverá ficar como na imagem 5:

Na sequência, o código da aplicação:

uses
Classes, SysUtils, Imagem 05.
FileUtil, Forms, Controls,
Graphics, Dialogs,
ExtCtrls, Caption:=OpenDialog1. Edit(Aba Standard):
StdCtrls,JPEGLib; FileName; Name:edtValor1;
Image1.Picture. Text:’Valor 1’
type LoadFromFile(OpenDialog1.
FileName);
{ TForm1 } Edit(Aba Standard)
end;
end; Name:edtValor2
TForm1 = class(TForm) Text:’Valor 2’
Button1: TButton;
end.
Image1: TImage; Veja o Layout da aplicação:
Label1: TLabel;
OpenDialog1:
TOpenDialog; Veja que para a carga da imagem não temos
procedure muita diferença entre o código que utilizaríamos no
Button1Click(Sender: Delphi. Apenas a unit necessária para a leitura dos
TObject); arquivos Jpeg, que no Delphi seria Jpeg, no Lazarus
private é JpegLib. Isso mostra que a adaptação de progra-
{ private declarations
madores Delphi ao Lazarus será bem tranquila.
}
public
{ public declarations Veja o aplicativo em execução:
} Vamos ao código deste exemplo:
end; Veja a imagem 06.

var Para finalizar e demonstrar a compatibilidade


Form1: TForm1; unit Unit1;
de código entre Delphi e Lazarus, criaremos uma
calculadora bem simples. {$mode objfpc}{$H+}
implementation
Iremos utilizar os seguintes componentes: interface
{$R *.lfm}

{ TForm1 } Button(Aba Standard): uses


Name:btnCalcula; Classes, SysUtils,
procedure TForm1. Caption: Calcular FileUtil, Forms, Controls,
Button1Click(Sender: Graphics, Dialogs,
TObject); ComboBox(Aba Standard) StdCtrls;
begin Name:cmbOperacoes;
OpenDialog1. type
Items:’Adição’, ‘Subtração’,’Multiplicação’,
Filter:=’Jpeg Files|*. ‘Divisão’;
jpg’; { TForm1 }
ItemIndex:0
if(OpenDialog1.Execute) TForm1 = class(TForm)
then Label(Aba Standard): btnCalcula: TButton;
begin Name:Label1; ComboBox1: TComboBox;
Label1. Caption:’Escolha a operação’ edtValor1: TEdit;

20 janeiro 2012
edtValor2: TEdit;
Label1: TLabel;
procedure
btnCalculaClick(Sender:
TObject);
private
{ private declarations
}
public
{ public declarations
}
end;

var
Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.
btnCalculaClick(Sender:
TObject);
var
Result,
Valor1, Imagem 06.
Valor2:Extended;
begin
Valor1:=StrToFloat Conclusão Na parte de conexão a bancos de dados, em-
(edtValor1.Text); bora ainda não possua drivers de alto desempenho,
Valor2:=StrToFloat A ferramenta Lazarus, além de seu grande Lazarus possui conexão nativa e fácil a Firebird e
(edtValor2.Text); crescimento nos últimos tempos, está tendo MySql e além disso, para melhor desempenho,
grandes avanços na parte de multiplataforma, podemos instalar a suíte Zeos no mesmo, o que
// Testamos os valores área onde o Delphi também começa a se destacar gera um ganho de desempenho em acesso a dados.
do combobox para obter a com o Firemonkey e a possibilidade de compilação
operação para MacOs. Como dissemos no começo do artigo, não
// a ser feita estamos aqui propondo a substituição de Delphi
Para usuários Linux e que precisam desenvol- pelo Lazarus e sim apresentar uma alternativa
case ComboBox1.
ItemIndex of ver para Windows também, Lazarus é altamente viável para as situações em que Delphi não puder
0: recomendado, já que é em Linux que Lazarus alcan- ser utilizado, seja por uma questão de licença ou
ça melhor desempenho. Lazarus hoje é compatível devido a restrições do sistema operacional.
Result:=Valor1+Valor2; com as principais distros Linux, tanto nas versões
1: 32 quanto 64 bits. Nos próximos artigos estarei detalhando a
Result:=Valor1- ferramenta e mostrando os poderosos recursos
Valor2; Lembrando que o compilador FreePascal já que a mesma oferece.
2: compila para 64 bits. Isso é ideal quando precisa-
mos criar dll’s cujo alvo serão sistemas operacionais Por enquanto é isso. Espero que tenham gos-
Result:=Valor1*Valor2;
3: 64 bits. tado e até a próxima!
if(Valor2<>0)
then // Para evitar erro
de divisão por zero

Result:=Valor1/Valor2; Sobre o autor


end; Antonio Spitaleri Neto
Consultor Técnico The Club.
// Exibimos o
resultado
ShowMessage(‘O
resultado é:
‘+FloatToStr(Result));
end;
antonio@theclub.com.br
end.

janeiro 2012 21
MÉTODOS RAVEReport
de A a Z

SelectBin(‘UPPER’);
um valor False.

Example (Delphi)

S
SelectPrinter(‘Laser’,
false);
SELECT PAPER – este método se-
leciona um tamanho de papel contendo
PaperName em sua descrição e retorna um
valor booleano se foi bem sucedido ou não.

Example (Delphi) SELECT REPORT – este método sele-


SEARCH NEXT – este método continua ciona o relatório especificado por ReportNa-
a pesquisa iniciada pelo SearchFirst. Esta fun- SelectPaper(‘LEGAL’);
me. Se FullName é True, a função pesquisa o
ção retorna True se encontra uma combinação relatório cujo nome completo combina. De
e False, se não. outra forma, pesquisa os apelidos. O resul-
tado da função é se a seleção do relatório
ReportName foi bem sucedida ou não.
SELECT PRINTER – Este método
define a impressora atual para a primeira im-
SELECT BIN – este método seleciona pressora em Printers que contém a substring
um bin contendo BinName em sua descrição SubStr em seu nome. ExactMatch determi-
e retorna um valor Booleano se foi bem su- na se é necessário uma correspondência SET BRUSH – este método configura
cedido ou não. exata ou não no nome da impressora. Se o pincel atual para parâmetros dados. Se ne-
nenhuma impressora for encontrada, então nhum bitmap é desejado, o valor deve ser nil.
Example (Delphi) a impressora atual não é alterada e retorna
Example (Delphi)

22 janeiro 2012
RvNDRWriter1.
longas strings que são mais de 255 caracteres. ao aplicativo passar parâmetros de projeto
SetBrush(clBlack, bsClear, para o projeto Rave atualmente carregado.
nil);
Example (Delphi) Estes parâmetros podem ser usados para
controlar layouts dinâmicos, parâmetros SQL
// Atribuir um PChar a um ou outros itens para imprimir em um relatório
buffer de memória. criado visualmente.
MemoBuf.SetData(PCharVar^,
StrLen(PCharVar)); Example (Delphi)
SET COLUMNS – este método con-
figura um número específico de colunas,
NewColumns, com uma separação Between, RvProject1.SetParam
entre cada coluna. A largura da coluna é (‘UserName’,UserName);
calculado para caber dentro da SectionLeft
atual e SectionRight. SET FONT – este método configura a
fonte corrente para os parâmetros dados.
Example (Delphi) NewSize é o tamanho do ponto da fonte (1/72
de uma polegada). SET PEN – Este método define a pena
// Este código mostra atual para os parâmetros dados. O parâmetro
como criar 4 colunas e
Nota: Se estiver sendo usado um conjun- NewWidth, se positivo, é a largura da caneta
enviar saída para elas.
to de símbolos, é preciso usar FontCharSet em unidades de impressão (pontos) e, se
SetColumns(4,0.5);
depois do método SetFont. negativo, é a largura da caneta em 1/100ths
while ColumnLinesLeft > 0 de uma polegada.
do begin
Example (Delphi)
PrintLn(IntToStr(LinesLeft) Example (Delphi)
RvNDRWriter1.SetFont(
+ ‘/’ +
‘Arial’, 10 ); RvNDRWriter1.
IntToStr(ColumnLinesLeft) SetPen(clBlack,psSolid,-
+ ‘/’ + 2,pmCopy);
IntToStr(LineNum)
+ ‘/’ +
IntToStr(ColumnNum));
SET PAPER SIZE – Este método define
end; { while }
o tamanho de papel atual da impressora se-
lecionada para as configurações de uma API SET PI VAR – Este método permite
do Windows, Size constante (ver TDevMode. inicializar o valor de um PIVar (Post Initialize
dmPaperSize) ou se Widht e Height são dife- Variável). Qualquer PIVars de mesmo nome,
rentes de zero, então ele irá tentar definir um que foi previamente impressa irá mostrar esse
SET COLUMN WIDTH – este método tamanho de papel personalizado. valor. Um uso comum para PIVars é imprimir
configura a coluna para uma largura especí- um total em uma faixa de cabeçalho que seria
fica, Width, com uma separação, Between, Nota: Nem todos os drivers de impres- inicializado depois na banda de rodapé. Isso
entre cada coluna. O número de colunas é sora suportam tamanhos de página perso- funciona mesmo através de várias páginas.
calculado para caber dentro das atuais Sec- nalizados e a maioria tem valores mínimos e TRvSystem.SystemOptions.soUserFiler deve
tionLeft e SectionRight. máximos aceitáveis. ser verdade se se estiver usando PIVars no
relatório.
Example (Delphi) Example (Delphi)

// Configurar papersize
// Criar colunas de 2
para 10 polegadas por
polegadas de largura e
meia polegada à parte.
12 polegadas e depois SET RTF – funciona exatamente como
configurar para 8.5 e 14 SetData, com exceção dos dados armazena-
RvNDRWriter1.
polegadas. RvNDRWriter1. dos em Buffer que são RTF texto.
SetColumnWidth( 2.0, 0.5
SetPaperSize(0,10,12);
);
RvNDRWriter1.
SetPaperSize(DMPAPER_
LEGAL,0,0);
SET TAB – este método adiciona uma
SET DATA – Este método atribui os configuração de tabulação.
dados em Buffer (para BufSize bytes) para
o buffer de memória. Isto pode ser útil para NewPos Define a posição inicial da
SET PARAM – SetParam permite que
janeiro 2012 23
tabulação. Se NewPos está configurada para da linha corrente. método inicia uma sessão de visualização e
a constante NA, então a tabulação começa chama a primeira página para a tela de visuali-
imediatamente depois da caixa de tabulação Example (Delphi) zação. Usar os métodos, PrevPage, NextPage,
anterior. PrintPage, ZoomIn e ZoomOut para interagir
RvNDRWriter1.SetTopOfPage; com o usuário da tela de visualização após
NewJustify define se a tabulação Start ter sido chamado. Para TRvNDRWriter,
está à esquerda (pjLeft), de centro-direita estes métodos iniciar um trabalho de im-
(pjRight) ou (pjCenter) justificada. Se uma pressão que deve ser encerrado mais tarde,
largura diferente de zero é dada, então uma com uma chamada para Concluir. Todos os
caixa de separador é definida e o texto deve SHADE TO COLOR – esta função cria manipuladores de eventos são ativos, exceto
ser justificado dentro da caixa de tabulação uma cor que somente tem um valor Shade- para OnPrint e OnPrintPage que são usados
ao invés de justificar a posição da tabulação. Percent de Shadecolor. apenas com Execute.

Example (Delphi)
NewMargin define a distância entre
o lado da caixa de tabulação e o texto em RvRenderPreview1.Start;
1/100ths de uma polegada SHOW PRINT DIALOG – traz uma
caixa PrintDialog padrão do Windows. Usar
esta função ao Invés do componente TPrin-
NewLines usa as constantes BoxLi- tDialog do Delphi.
neXxxx para definir em torno do que as linhas STRETCH DRAW – este método dese-
serão desenhadas. Example (Delphi) nha o objeto gráfico Graphic, esticado ou en-
colhido, para caber dentro do retângulo Rect.
NewShade define o percentual de if RvNDRWriter1. Nota: StretchDraw não deve ser usado
sombreamento de fundo para usar nessa ShowPrintDialog then begin para bitmaps. Ao invés disso, usar PrintBitmap
caixa de tabulação. RvNDRWriter1.Execute; ou PrintBitmapRect.
end; { if }

Example (Delphi)

ClearTabs; SUPPORT BIN – este método retor-


SetPen(clBlack, psSolid,1, SHOW PRINTER SETUP DIALOG na True se o número bin (ver TDevMode.
pmCopy); – traz uma caixa PrinterSetupDialog padrão dmDefaultSource no Help API do Windows)
SetTab(0.5,pjCenter,3.5,0, do Windows. Usar esta função ao invés do especificado pelo BinNum é suportado pela
BOXLINEALL,0); componente TPrinterSetupDialog do Delphi. impressora. De outra forma, retorna False.
SetTab(NA, pjCenter,1.0,0,
BOXLINEALL,0); Example (Delphi)
SetTab(NA, pjCenter,1.5,0,
BOXLINEALL,0); if RvNDRWriter1.
SetTab(NA, pjCenter,1.5,0, ShowPrinterSetupDialog SUPORT COLLATE – este método
BOXLINEALL,0); then begin retorna True se a impressora suporta agrupa-
Bold := true; RvNDRWriter1.Execute; mento. De outra forma, retorna False.
Tab(-2,NA,-2,-2,NA); end; { if }
Print(‘Name’);
Tab(NA,NA,-2,-2,NA);
Print(‘Number’);
Tab(NA,NA,-2,-2,NA); SUPPORT DUPLEX – este método re-
Print(‘Amount 1’); SOFT LINE – Este método deve ser torna True se a impressora suporta impressão
Tab(NA,-2,-2,-2,NA); chamado para ir para a próxima linha em um em duas faces.
PrintLn(‘Amount 2’); documento RTF exportado sem inserir um
Bold := false; retorno de carro. Para saída baseada na im-
pressora (TRvRenderPrinter, TRvNDRWriter),
este método executa o mesmo que NewLine.
SUPPORT ORIENTATION – este
método retorna True se a impressora suporta
SET TOP OF PAGE – este método mudança de orientação.
configura a SectionTop para a parte de baixo
START – Para TRvRenderPreview, este

24 janeiro 2012
SUPPORT PAPER – este método re- TAB START – este método TEXT WIDTH – este método retorna o
torna True se o número do papel especificado retorna a posição horizontal inicial da caixa tamanho da string Text.
em PaperNum é suportado pela impressora. de tabulação especificada pelo Índice. Se o
De outra forma, retorna False. Índice é 0 então o resultado será a tabulação Example (Delphi)
atual e se o Índice for maior que o número de
tabulações definidas então será retornado um var TxtLen: double;
valor de 0.0. begin
TxtLen := TextWidth(
TAB – Este método define as configu- Example (Delphi) “How long am I?” );
rações da tabulação atual para a próxima end;
tabulação disponível. Se a próxima tab é uma // Inicia região de
caixa de tab, então as linhas para aquela tab tabulação atual
são desenhadas neste momento, bem como CurrStart := RvNDRWriter1.
qualquer sombra que se possa aplicar. O Lef- TabStart( 0);
tWidth, RightWidth, TopWidth e BottomWi- UNREGISTER GRAPHIC – Este méto-
dth são substituições para a largura da lateral do ajuda a gerenciar a repetição de grandes
da caixa de tab em 1/100ths de uma polegada, bitmaps em um trabalho de impressão. É
mas deve ser passado como a constante NA, usado para garantir que o índice usado pelo
para a largura da caneta padrão. Se os pa- TAB WIDTH – este método retorna a RegisterGraphic é claro. Deve-se chamar este
râmetros LeftWidth, RightWidth, TopWidth largura da caixa de tabulação especificada método se um gráfico já foi previamente
ou BottomWidth (s) são positivos, então é a pelo Índice. Se o Índice for 0 então o resultado registrado naquele índice. Porém, é seguro
largura da caneta em unidades de impressão será a tabulação atual e se Índice for maior e recomendado sempre chamar Unregiste-
(pontos) e, se negativo, é a largura da caneta que o número de tabulações definidas, então redGraphic antes de usar estes métodos de
na 1/100ths de uma polegada. ShadeOverride retornará um valor 0.0. índices de gráficos.
é uma porcentagem de sombreamento para
desenhar o fundo da caixa de tab e substitui Example (Delphi)
TabShade ou a configuração original do som-
breamento de uma caixa de tabulação. // Largura da região de
tabulação atual. UPDATE STATUS – Este método atuali-
Example (Delphi) CurrWidth := RvNDRWriter1. zará o rótulo definido pelo StatusLabel com a
TabWidth( 0); informação atual definida pelo estado do re-
with RvNDRWriter1 do begin latório ou pelos itens contidos em StatusText.
Tab(-2,NA,-2,-2,NA);
Print(‘First tab’); Example (Delphi)
Tab(NA,NA,-2,-2,NA);
Print(‘Second tab’); TEXT RECT – Este método irá desenhar // Depois da execução do
end; { with } texto cortado dentro do retângulo definido relatório, dependendo
por Rect. O ponto (X, Y) define o ponto de se o usuário abortou a
partida do texto. Use CreateRect para ini- criação dos relatórios ou
cializar Rect. não, a barra de status é
atualizada com a mensagem
TAB END- este método retorna a po- Example (Delphi) apropriada
sição final horizontal da caixa de tabulação if Aborted then begin
especificada pelo Índice. Se o Índice é 0 então var TxtRect: TRect; StatusFormat := #13’Report
o resultado será para a tabulação corrente e TxtXPos: double; Canceled!’;
se Índice for maior que o número de tabula- TxtYPos: double; UpdateStatus;
ções definidas, então retorna um valor de 0.0. Txt: string; end else begin
begin StatusFormat := #13’Report
Example (Delphi) TxtRect := CreateRect( Completed!’;
1.00,1.00,3.00,3.00); UpdateStatus;
// Fim da região da TxtXPos := 0.95; end; { else }
tabulação atual. TxtYPos := 0.95;
CurrEnd := RvNDRWriter1. Txt := ‘Text is clipped
TabEnd( 0); off!’;
TextRect(TxtRect, TxtXPos,
TxtYPos, Txt); WRITEBCD DATA – Este método
end; escreve o conteúdo de um campo BCD per-

janeiro 2012 25
sonalizado (do tipo dtBCD) dentro do evento WRITE CURR DATA – Este método WRITE FLOAT DATA - Este método
OnGetRow de um componente data connec- grava o conteúdo de um campo de moeda grava o conteúdo de um campo BCD perso-
tion. Os dados para o campo customizado personalizado (de tipo dtFloat) dentro do nalizado (de tipo dtFloat) dentro do evento
deve ser escrito na mesma ordem em que evento OnGetRow de um componente de OnGetRow de um componente de conexão de
os campos foram definidos no evento OnGe- conexão de dados. Os dados para campos dados. Os dados para campos personalizados
tCols. O parâmetro FormatData define o valor personalizados devem ser escritos na mesma devem ser escritos na mesma ordem em que
formatado do campo, mas pode ser branco ordem em que os campos foram definidos no os campos foram definidos no evento OnGe-
se uma saída não formatada for necessária. evento OnGetCols. Os parâmetros formatdata tCols. Os parâmetros formatdata definem
O parâmetro NativeData deve conter o con- definem o valor formatado do campo, mas o valor formatado do campo, mas podem
teúdo não modificável do campo. podem ficar em branco se não for necessá- ficar em branco se não for necessária uma
ria uma saída pré-formatada. Parâmetros saída pré-formatada. Parâmetros NativeData
Example (Delphi) NativeData devem conter o conteúdo não devem conter o conteúdo não modificável
modificável do campo. do campo.
Connection.WriteBCDData( ‘
‘,InvoiceAmount ); Example (Delphi) Example (Delphi)

Connection.WriteCurrData( Connection.WriteFloatData(
‘’,InvoiceAmount ); ‘’,CustomerBudget );

WRITE BLOB DATA – Este método


escreve o conteúdo de um campo blob
personalizado (do tipo dtBlob / dtGraphic /
dtMemo) dentro de um evento OnGetRow WRITE DATE TIME – Este método WRITE INT DATA – Este método grava
de um componente data connection. Os da- grava o conteúdo de um campo DateTime o conteúdo de um campo integer persona-
dos para os campos personalizados deve ser personalizado (de tipo dtDate / dtTime / lizado (de tipo dtInteger) dentro do evento
escrito na mesma ordem em que os campos dtDateTime) dentro do evento OnGetRow OnGetRow de um componente de conexão de
foram definidos no evento OnGetCols. de um componente de conexão de dados. Os dados. Os dados para campos personalizados
dados para campos personalizados devem ser devem ser escritos na mesma ordem em que
Example (Delphi) escritos na mesma ordem em que os campos os campos foram definidos no evento OnGe-
foram definidos no evento OnGetCols. Os tCols. Os parâmetros formatdata definem
Connection.WriteBlobData( parâmetros formatdata definem o valor o valor formatado do campo, mas podem
‘’,CustomerPict ); formatado do campo, mas podem ficar em ficar em branco se não for necessária uma
branco se não for necessária uma saída pré- saída pré-formatada. Parâmetros NativeData
-formatada. Parâmetros NativeData devem devem conter o conteúdo não modificável
conter o conteúdo não modificável do campo. do campo.

WRITE BOOL DATA – Este método Example (Delphi) Example (Delphi)


escreve o conteúdo de um campo boolean
personalizado (do tipo dtBoolean) dentro de Connection.WriteDateTime( Connection.WriteIntData(
um evento OnGetRow de um componente ‘’,Now ); ‘’,CustomerCount );
data connection. Os dados para os campos
personalizados deve ser escrito na mesma
ordem em que os campos foram definidos no
evento OnGetCols. Os parâmetros FormatDa-
ta define o valor formatado do campo, mas
pode ser branco se uma saída não formatada
for necessária. O parâmetro NativeData deve
conter o conteúdo não modificável do campo. Sobre o autor
Example (Delphi) Leonora Golin
Consultora Técnica The Club.
Connection.WriteBoolData(
‘’,CustomerActive );

antonio@theclub.com.br

26 janeiro 2012
janeiro 2012 27
Dicas DELPHI SELECT EXTRACT(DAY FROM CURRENT_
DATE) AS Dia,
EXTRACT(MONTH FROM
ALTERANDO TRECHO ESPECIFICO DE UMA INSTRUÇÃO SQL CURRENT_DATE) AS Mes,
EXTRACT(YEAR FROM
CURRENT_DATE) AS Ano
As vezes precisamos trabalhar com as instrução SQL em um determinado FROM RDB$DATABASE;
trecho, para que não tenha que ser refeita essa instrução podemos alterar de
acordo com a linha a que precisa ser modificada, para isso utilizamos a seleção
da linha da instrução, para isso utilizamos a referencia da linha a ser alterada.
Nesta instrução SQL estamos retornando como resultado o dia, mês e
ano atual, de acordo com as informações extraídas do campo RDB$DATABASE,
SELECT ID_CLIENTE, que irá trazer os dados da data atual através da tabela CURRENT_DATE, que
NOME, será informada pelos dados do servidor, que é de onde está executando o
DATA_NASCIMENTO, serviço firebird.
SEXO
FROM CLIENTE
WHERE ( ID_CLIENTE < 1000 )
AND ( SEXO = ‘M’ )
ORDER BY NOME
EXTRAINDO TODOS OS CAMPOS DE CHAVE PRIMÁRIA
DE UMA TABELA
Como exemplo é utilizado uma instrução SQL simples, como exemplo
iremos mudar a categoria do campo sexo, somente alterando a linha corres-
Uma função importante realizada pelas tabelas do sistema é a listagem da
pondente.
quantidade de chaves primárias existentes em uma tabela para isso utilizamos
uma função SQL que irá exibir todos os campos da tabela selecionada e filtrando
pelo índice de listagem das chaves primárias e a tabela RDB$INDEX_SEGMENTS
serve para resgatar o tipo de campo como chave primária e listando os seus
if cdsCliente.Active then
Close;
índices
cdsCliente.SQL[6] := ‘AND (SEXO =
‘F’)’;
cdsCliente.Open;
SELECT RDB$FIELD_NAME AS CHAVES
FROM RDB$RELATION_CONSTRAINTS,
RDB$INDEX_SEGMENTS
WHERE RDB$RELATION_CONSTRAINTS.
Basta utilizar esta simples função que fecha a conexão e altera a linha
RDB$RELATION_NAME = ‘MOTORES’
indicada, lembrando que a contagem destas linhas é iniciada à partir da linha
AND RDB$RELATION_
0, capturando a instrução indicada, sobrescrevendo a anterior no momento CONSTRAINTS.RDB$CONSTRAINT_TYPE =
em que é reaberta a conexão com o banco de dados ‘PRIMARY KEY’
AND RDB$INDEX_SEGMENTS.
RDB$INDEX_NAME = RDB$RELATION_
CONSTRAINTS.RDB$INDEX_NAME
ORDER BY RDB$FIELD_POSITION
EXTRAINDO CONTEÚDO DE UM CAMPO DATA

Para extrair um campo com dia, mês e ano atuais utilizamos as System Esta instrução irá gerenciar e listar todos os campos de chave primária
Tables, que são as tabelas do sistema, propriamente ditas, elas nos dão à opção existentes na tabela, facilitando a busca pelos dados da tabela.
de controlar todos os registros autônomos, que não dependem dos registros
disponíveis pelo usuário, isso é, são independentes das tabelas definidas pelo
usuário e seus dados, um exemplo é o controle de Data e Hora extraindo suas
propriedades de dia mês e ano através destas tabelas auto-geradas pelo sistema
na hora em que é criado o banco.

28 janeiro 2012
EXECUTANDO THREADS EM PROCESSOS SEPARADOS
NA APLICAÇÃO Priority := TpLower;

E por fim inicia o Thread para que seja executado em segundo plano
Nessa dica, iremos criar um thread que servirá para ser executada em
segundo plano assim que o processo principal esteja rodando no computador.
O primeiro passo é criar um tipo que herdará a classe TThread, em que seu
método protegido será criado o procedimento Executar, utilizando a palavra Resume;
reservada override que servirá para sobrescrever o método, além do método end;
público onde será definido seu método de criação

E para que possamos executar nosso Thread, devemos


type
TThreadBack = class(TThread)
private
procedure ThreadBack.Execute;
protected begin
procedure Executar; override; // Aqui será executando as funções
public do Thread que estará em segundo
constructor Create(); plano
end; end;

O próximo passo é criar e instanciar o método construtor

BLOQUEAR A TECLA TAB


constructor TThreadBack.Create();
begin
Para bloquear a tecla TAB devemos verificar se as teclas ALT ou o próprio
TAB pressionado, caso tenham sido pressionados, zeramos o valor da chave
da tecla e a propriedade, e habilitando o uso com a propriedade Handled,
Agora estaremos colocando o método em estado de espera temporaria- para que não ocorra erros
mente, para que seja executado no momento necessário.

if (Msg.Message = WM_KEYDOWN) AND


inherited Create(True); (Msg.wParam = VK_TAB) then
begin
Msg.wParam:= 0;
Handled:= True;
Libera o objeto da memória assim que terminado, para que não compro- end;
meta o processo do CPU para um objeto inutilizado end;

FreeOnTerminate := True;

Precisamos também definir a prioridade para o CPU, sendo do tipo TpLo-


wer, que deixará o sistema trabalhando com o processo no método com sua
prioridade baixa

janeiro 2012 29
Horizontal Vertical

30 janeiro 2012
janeiro 2012
janeiro 2012

Você também pode gostar