Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
2013
julho
2013
04
Editorial
05
FastReport no Delphi
Autor: Luciano Pimenta
11
TConexao:
19
Android
Trabalhando com o TouchScreen
ndice
27
2013
03
Editorial
Caro Leitor!
sempre com muita alegria e satisfao que finalizamos mais uma revista aos senhores. Aproveito tambm para agradecer s pessoas que vem
acessando o contedo de nosso site, portanto a cada dia que passa estamos
adquirindo mais acessos e cadastros. Que continuemos assim!
Para este ms, nosso consultor tcnico Jos Antonio nos trouxe direto
do forno as principais novidades do Delphi XE4 com o intuito de sempre
mant-los bem informados com as ltimas tecnologias lanadas no mercado. Nosso colunista mensal Luciano Pimenta aborda o uso do gerador de
relatrios FastReport, uma boa opo para quem trabalha com o Delphi.
Podemos considerar esta ferramenta como a opo oficial para quem
utiliza as novas verses do Delphi. J nosso colaborador Hamden Voguel
desenvolveu um componente prprio para gerenciar projetos em ambientes
Multi-Plataforma, o TConexao. Nesta primeira parte ele ir nos auxiliar
na gerncia de Projetos utilizando diversos tipos de Banco de Dados. Importante salientar que este componente est disponvel gratuitamente em
nosso site. Eu continuo apresentando recursos do Sistema Android, sendo
que neste ms ensino a trabalhar com o TouchScreen, descrevendo suas
principais classes e mtodos para realizar esta tarefa. Recomendo a leitura
deste artigo para quem est comeando a desenvolver aplicativos e para
quem deseja aprimorar seus conceitos em relao a este artifcio.
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
Reproduo
04
julho
2013
FastReport no
Delphi
F
Conhecendo a ferramenta
Ao abrir o Delphi e criar um projeto VCL Foms, podemos visualizar a aba
FastReport 4.0 (Figura 1).
2013
05
Primeiro exemplo
Volte ao Delphi e adicione um frxDBDataSet (um frxReport tambm deve
estar no formulrio). Crie uma conexo com o banco de dados de sua preferencia (usarei no artigo, o Firebird). Usarei no artigo um Data Module para conter
os componentes de conexo com o banco, pois usaremos vrios exemplos.
Adicione os tipos: Page Header, Page Footer e Master Data. O Master Data,
abre um editor, solicitando o respectivo DataSet da aba. Selecione frxDBDataSet1. Existem duas maneiras de adicionar os campos na banda Master Data
para exibir os dados.
Arraste os campos da janela Data tree para o relatrio. Note que aps
inserir os campos, ao passar o mouse, mostrado uma seta, onde podemos
clicar e ser exibido um menu com os campos do DataSet, assim fica fcil
modificar o objeto para outro campo da consulta (Figura 5).
Vincule o frxDBDataSet com o DataSet que retorna os dados da sua consulta. D um duplo clique no frxReport para abrir o editor. Primeiramente, vamos
vincular o frxDBDataSet com o nosso relatrio, acessando o menu Report>Data.
No editor que abrir, escolha o respectivo controle de dados (Figura 3).
06
julho
2013
Formatao de objetos
Como podemos ver no relatrio que criamos, o campo Salary, esta como
texto, sem a devida formatao. Para ajustar isso, abra o relatrio e d um
duplo clique no campo. No editor, acesse a aba Format e configure, conforme
a Figura 10, onde indicamos o tipo de formatao e o separador decimal
(vrgula) do formato.
Podemos usar o editor do Text Object para apenas adicionar rtulos (textos) no relatrio, onde basta digitar o texto desejado na aba Text. Na barra
de ferramentas temos as funcionalidades necessrias para formatar os textos
digitados nesse objeto.
Note que ao adicionarmos um Text Object ou mesmo adicionar um campo
usando a janela Data tree, existem linhas que nos auxiliam para que os controles fiquem alinhados tanto horizontalmente, como verticalmente (Figura 8).
2013
07
Arquivos de relatrios
Para voc que estava acostumado com o Rave Reports, vai notar uma
diferena interessante no FastReport. Cada relatrio um arquivo FR3. No
Rave, o arquivo RAV era de projeto e dentro poderamos ter vrios relatrios.
No FastReport, cada FR3, apenas um relatrio. Salve o arquivo e modifique o cdigo do boto para o seguinte cdigo:
Cdigo 02
select EMPLOYEE.first_name,
EMPLOYEE.last_name,
employee.salary, DEPARTMENT.
department
from EMPLOYEE
inner join DEPARTMENT on
DEPARTMENT.dept_no = EMPLOYEE.
dept_no
order by DEPARTMENT.department
Crie um novo frxReport (se desejar, em outro formulrio). Caso seja carregado o relatrio anterior, crie um novo. No esquea de modificar o Data
do relatrio. Caso tenha criado um novo formulrio, atende para o nome do
formulrio no editor de seleo de DataSets (Figura 3).
De um duplo clique no Master Data e vincule com o DbDataSet. Adicione
uma banda Group Header. Um editor aberto para configurarmos a banda do
grupo. Vamos indicar que o agrupamento se dar pelo campo Department.
Podemos ainda indicar uma expresso para o agrupamento.
Nas opes de agrupamento, podemos configurar para que a cada grupo,
seja mostrado em uma nova pgina ou drill-down, onde clicamos sobre o grupo
para mostrar os dados.
Cdigo 01
frxReport1.
LoadFromFile(Listagem.fr3);
frxReport1.ShowReport();
Arraste a banda para que fique acima da Master Data. Veja na Figura 13
o relatrio agrupado em execuo.
Agrupamento
Outro exemplo muito usado em relatrios o de agrupamento de dados.
Neste exemplo, vamos fazer a mesma listagem anterior, com a diferena que
vamos retornar todos os empregados, agrupados pelo seu departamento.
Veja o SQL da consulta:
08
julho
2013
Somatrio
Master/detail
Outro exemplo muito comum em relatrio e de mostrar os dados master e os details. Exemplo clssico: nota fiscal, os dados referente ao cliente
(comprador) podemos considerar o master, e as informaes dos produtos
da nota, so o detail.
Exportao de relatrios
Uma caracterstica interessante que observei no FastReport a quantidade
de opes de tipos de exportaes para os relatrios. Veja na Figura 17 a aba
de exportaes do FastReport.
2013
09
Concluses
Vimos nesse artigo como trabalhar com o FastReport, a nova ferramenta
para gerar relatrios no Delphi. Existem muitas outras possibilidades para
criarmos relatrios profissionais para suas aplicaes Delphi, assim, no prximo artigo veremos como criar grficos, cross-tab, trabalhar com templates
(semelhante herana) etc.
Um grande abrao a todos e at a prxima!
Sobre o autor
Luciano Pimenta
Luciano Pimenta (NOVO DOMINIO: www.lucianopimenta.com) desenvolvedor Delphi/C#
para aplicaes Web com ASP.NET, Windows com Win32 e Windows Forms com .NET. Palestrante
da 4 edio da Borland Conference (BorCon) e da 1 Delphi Conference.
MVP Embarcadero, grupo de profissionais que ajudam a divulgar o Delphi no mundo.
Atualmente desenvolvedor da SoftDesign fbrica de softwares em Porto Alegre-RS.
Autor de mais de 90 artigos e de mais de 600 vdeos aulas publicadas em revistas e sites
especializados, alm de treinamentos presenciais e multimdias. consultor da FP2 Tecnologia
(www.fp2.com.br) onde ministra cursos de programao e banco de dados.
www.lucianopimenta.net
10
julho
2013
TConexao: Gerenciando
magino que muitos desenvolvedores j experimentaram a situao de avaliar um prottipo em mais de um ambiente, talvez ao
mesmo tempo (homologao em um ambiente em uma mquina
local e entrega em outro ambiente atravs de uma build). Nestes
casos, pode um mesmo Banco de Dados satisfazer tais requisitos
de performance e regras negociais exigidas, executando comumente um
CRUD sem comprometer a rapidez do trfego de dados atualizando de
forma imperceptvel os controles projetados na camada de apresentao do
seu aplicativo at a tudo bem mas e se houver a necessidade negocial
de evolutivamente abstrair a camada de dados ? O seu aplicativo decide
qual base ele ir rodar e sem prejuzo de instabilidade este processo ser
transparente para o usurio final.
Porque no implantar uma forma otimizada de se obter eficientemente
esta caracterstica de multiplataforma? O Framework Itil j dizia: As Empresas
buscam inovar seus processos para se tornarem mais eficientes e competitivas. Inovaes que do certo transformam-se em melhores prticas. Esta
implementao j foi devidamente testada, livre, tem uma boa resposta de
execuo, acessvel a todos e por isso justifica-se em uma boa prtica de
servio. Ambiciosamente podemos entregar este valor em potencial levando
ao aumento dos resultados desejados dos clientes. Em suma, mais do que
funciona.
O cliente tem uma exigncia que crescente; ns devemos estar sempre
preparados para prontamente atend-las; podemos no caso de um entrega
rod-la localmente em um pen-drive ou em seu prprio HD com um baixo volume de dados utilizando um arquivo XML (apenas para verificar basicamente
seu funcionamento e sem muitos requisitos de software), ou execut-la em um
ambiente de desenvolvimento cliente-servidor exigindo todos os requisitos implementados at o momento, simulando realmente sua performance e demais
quesitos (disponibilidade, confiabilidade, sustentabilidade, etc) escalando
qual dataset ele ir acessar e em tempo de execuo! Portanto, imagine um
software ser independente do seu banco de dados - e aqui referido de forma
abstrata valendo-se tanto de um mero arquivo XML (constru um parser para
isso), tanto para um Sistema baseado em Arquivos ou um Sistema Gerenciador
de Banco de Dados: tem para estas trs finalidades - e finalmente o sistema
est independente de tudo: nasce a classe Tconexao.
Esta funcionalidade interessante pela praticidade, como dito anteriormente, pois o aplicativo fica livre de implementaes distintas de acesso aos
dados; apenas a nossa classe de conexes far este trabalho de carregamento e alterao deles toda visualizao produzida pelo carregamento do
componente TClientDataSet ele sempre ser alimentado pela nossa classe
portanto eles sempre andaro juntos um sempre se comunicando com o
outro e consequentemente a base em que ele acessar ser sempre desligada, esperando algum evento do usurio ou sistema, como por exemplo de
comitar um update ou carregar uma lista (para inicializao de uma tela
ou um refresh).
Abaixo pode ser visualizado o diagrama de sequncia do componente, a
fim de exemplificar o seu funcionamento na prtica; no complicado perceber
sua idia bsica de funcionamento.
2013
11
12
julho
2013
Cdigo 01
function TConexaoFirebird.
CarregarBanco(const cDiretorio:
string): Boolean;
begin
Result := True;
if (cDiretorio = EmptyStr)
then
begin
fVendorLib
:=
FMyGDSVendorLib;
fLibraryName
:=
FMyDBXExpress
FirebirdLibraryName;
fPathDataBase
:=
FUsuariosFDB;
end
else if (cDiretorio =
default) then
begin
fVendorLib
:=
FMyGDSVendorLib;
fLibraryName
:=
ExtractFilePath(Application.
ExeName) +
IncludeTrailingPathDelimiter
(BD\FIREBIRD) +
FMyDBXExpressFire
birdLibraryName;
fPathDataBase
:=
ExtractFilePath
(Application.ExeName) +
IncludeTrailingPathDelimiter
(BD\FIREBIRD) + fPathDataBase;
end
else
begin
fVendorLib
:=
cDiretorio + FMyGDSVendorLib;
fLibraryName
:=
cDiretorio + FMyDBXExpress
FirebirdLibraryName;
fPathDataBase
:=
cDiretorio + fPathDataBase;
end;
Result := ( (DirectoryExists
(fPathDataBase)) and
(FileExists (fLibraryName)) );
if not Result then Exit;
dmFirebird := TdmFirebird.
Create(nil);
try
try
with dmFirebird.
SQLConnection do
begin
Connected
:= False;
VendorLib
:=
dbVendorLib;
LibraryName :=
dbLibraryName;
Params.
Values[Database] :=
fPathDataBase + FUsuariosFDB;
end;
finally
dmFirebird.SQLConnection.
Connected := True;
dmFirebird.SQLQuery.Open;
end;
except
on E: Exception do
begin
Raise EInvalidDataBase.
Create (EErroGeralBancoDeDados
+ #13#10 + E.Message);
Result := False;
end;
end;
end;
XML
DBISAM
FIREBIRD
No nosso projeto foram criados campos dos tipos String, Integer, Float e
Blob. Todos os tipos sero validados de acordo com o formato suportado pelo
banco isto nem todos possuem as mesmas validaes para data, ponto
flutuante, etc. Um ponto importante a ser mencionado que todos os setters
so do tipo String isso facilita os testes de validao de tipo de dados antes
de sua converso para o seu formato original.
Alguns campos so obrigatrios, requeridos nos setters e retornando um
campos de mensagens de retorno (FCodigoMensagem e FMensagem).
Uma amostra do fonte da propriedade da data de nascimento (mtodo
write):
Cdigo 02
procedure TUsuario.
setDataNascimento(const Value:
String); //obrigatrio
var
AuxDia, AuxMes, AuxAno,
fValue: string;
begin
fValue := Value;
fValue := Conexao.
GetDateFormat(Value);
if not (Biblioteca.
EmptyDate(fValue)) then
julho
2013
13
begin
if not Biblioteca.
IsValidDate(fValue) then
begin
FCodigoMensagem
:=
CodMensagemCampoInvalido;
FMensagem
:=
Campo Data Nascimento
Invlido!;
FDataNascimento
:=
;
end
else
begin
FCodigoMensagem
:=
CodMensagemNormal;
FMensagem
:=
EmptyStr;
FDataNascimento
:= Conexao.
FormatDefaultDate(fValue); //
Trim(Value);
end;
end
else
begin
FDataNascimento
:=
fValue;
FCodigoMensagem
:=
CodMensagemCampoEmBranco;
FMensagem
:=
Campo Data Nascimento em
Branco!;
Alterou
:=
False;
end;
end;
, CIDADE = +
QuotedStr(Cidade) + , ESTADO =
+ QuotedStr(Estado) +
, CEP = + QuotedStr(CEP)
+ , CARGO = +
QuotedStr(Cargo) + , SETOR =
+ QuotedStr(Setor) +
, TELEFONE = +
QuotedStr(Telefone) + ,
VLR_SALARIO = + (Conexao.
FormatFloat(Salario)) +
, NR_MATRICULA
= + (Conexao.
FormatInteger(Matricula)) +
WHERE NOME = +
QuotedStr(Nome);
Conexao.Executar(Query);
end
Explicao: A classe TConexao, atravs de GetConexao, e utilizando o
type tBDConexao (type tBDConexao = (bdConexaoXML, bdConexaoDBISAM,
bdConexaoFirebird) far a instanciao com a subclasse desejada de acesso
ao banco, e a melhor de todas as coisas que em runtime os bancos podem
ser trocados selecionando, alterando, etc com a maior versatilidade!
Em suma, toda vez que uma classe quiser acessar um banco, ela na verdade
acessa uma instncia da classe de conexo (TConexao), onde esta por sua vez
referenciar-lo em memria. Toda a interface de comunicao e operacionalizao ser realizada somente atravs dela, estando disponvel at ser destruda.
Abaixo, uma seleo de alguns mtodos importantes utilizados na classe
TConexao - detalhe para os mtodos ObterDataSet, CarregarFoto e GetConexao (sintaxe: Conexao := Conexao.GetConexao(fbdConexao)) - que so os
mtodos mais importantes do processo de comunicao entre os objetos de
negcio e dados.
Cdigo 04
14
julho
2013
procedure TConexao.
ObterDataSet(const myDataSet:
TDataSet; var myClientDataSet:
TClientDataSet);
var
fDataSet: TDataSet;
i {, k}: integer;
FName: string;
begin
if not Assigned(myDataSet)
then Exit;
if not Self.BancoInstanciado
then
begin
Application.MessageBox(PCha
r(Format(EBancoNaoInstanciado,
[FUsuariosFDB])), ETituloErro,
MB_OK + MB_ICONERROR);
Abort;
end;
fDataSet :=
TClientDataSet(myDataSet);
fDataSet.First;
if not myClientDataSet.Active
then
myClientDataSet.
CreateDataSet
else
myClientDataSet.
EmptyDataSet;
myClientDataSet.
DisableControls;
try
while not fDataSet.Eof do
begin
myClientDataSet.Insert;
for i := 0 to fDataSet.
FieldCount - 1 do
begin
// myClientDataSet.
Fields[i].Assign(fDataSet.
Fields[i]);
myClientDataSet.
FieldDefs.Items[i].DataType :=
(fDataSet.FieldDefs.Items[i].
DataType);
myClientDataSet.
FieldDefs.Items[i].DisplayName
:= (fDataSet.FieldDefs.
Items[i].DisplayName);
case myClientDataSet.
FieldDefs.Items[i].DataType of
ftString:
myClientDataSet.Fields[i].
AsString := Self.
DefaultDateFormat2(fDataSet.
Fields[i].AsString);
ftDate:
myClientDataSet.Fields[i].
AsString := Self.
DefaultDateFormat2(fDataSet.
Fields[i].AsString);
ftFloat:
myClientDataSet.Fields[i].
AsFloat := Biblioteca.
ArredondaComDecimais( fDataSet.
Fields[i].AsFloat, 2);
else
myClientDataSet.
Fields[i].AsString :=
fDataSet.Fields[i].AsString;
end;
end;
myClientDataSet.Post;
fDataSet.Next;
end;
finally
myClientDataSet.
EnableControls;
end;
end;
procedure TConexao.
ObterDataSet(const myDataSet:
TDataSet; var myStringList:
TStringList);
var
fDataSet: TDataSet;
i: integer;
begin
if not Assigned(myDataSet)
then Exit;
fDataSet :=
TClientDataSet(myDataSet);
fDataSet.First;
if not Assigned(myStringList)
then myStringList :=
TStringList.Create;
while not fDataSet.Eof do
begin
myStringList.Add(fDataSet.
Fields[0].AsString);
fDataSet.Next;
end;
end;
function TConexao.
RecordCount(Query: String):
integer;
begin
if Self is TConexaoDBISAM
then
Result :=
TConexaoDBISAM(Self).
RecordCount(Query)
else if Self is TConexaoXML
then
Result := TConexaoXML(Self).
RecordCount(Query)
else if Self is
TConexaoFirebird then
Result :=
TConexaoFirebird(Self).
RecordCount(Query);
end;
function TConexao.
julho
2013
15
RecordCount(const myDataSet:
TDataSet): integer;
begin
Result :=
(TDataSet(myDataSet).
RecordCount);
end;
function TConexao.
RetornaDataSet(Query: String):
TDataSet;
begin
if Self is TConexaoDBISAM
then
Result :=
TConexaoDBISAM(Self).
RetornaDataSet(Query)
else if Self is TConexaoXML
then
Result := TConexaoXML(Self).
ExecutaSelect(Query)
else if Self is
TConexaoFirebird then
Result :=
TConexaoFirebird(Self).
RetornaDataSet(Query);
end;
function TConexao.
CarregarFoto(const MyFile:
string; const myDataSet:
TDataSet; const MyFieldName:
string = FOTO): Boolean;
function
GetTableNameFromXMLSyntax(const
mySQLXML: string): string;
begin
if System.
Pos(AnsiUpperCase(where),
AnsiUpperCase(mySQLXML)) > 0
then
Result := trim(Before(af
ter(AnsiUpperCase(mySQLXML),
FROM), WHERE));
end;
var
S: TFileStream;
fClientDataSet:
TClientDataSet;
auxTableName: string;
auxFilterFields: string;
begin
if Self is TConexaoXML then
begin
if (Self.FiltroXML = )
then Exit;
16
julho
2013
auxTableName :=
GetTableNameFromXMLSyntax(Self.
FiltroXML);
auxTableName :=
auxTableName + .xml;
fClientDataSet
:= TConexaoXML(Self).
CarregarBanco(auxTableName);
auxFilterFields :=
Before(after(AnsiUpperCase(Self.
FiltroXML),WHERE), ORDER);
fClientDataSet.Filter :=
auxFilterFields;
fClientDataSet.Filtered
:= True;
try
fClientDataSet.Close;
fClientDataSet.Open;
if not (fClientDataSet.
state in dsEditModes) then
fClientDataSet.Edit;
TBlobField(fClientDataSet.
FieldByName(MyFieldName)).
LoadFromFile(MyFile);
fClientDataSet.Post;
fClientDataSet.
SaveToFile(TConexaoXML(Self).
CaminhoXMLAtual, dfXML);
except
on E: Exception do
begin
Raise EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
Result := False;
end;
end;
end
else
if Self is TConexaoDBISAM
then
begin
S := TFileStream.
Create(MyFile ,fmOpenRead);
with (myDataSet) do
begin
try
try
Edit;
TBlobField(Fie
ldByName(MyFieldName)).
LoadFromStream(S);
Post;
except
on E: Exception do
begin
Raise
EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
Result := False;
end;
end;
finally
S.Free;
end;
end;
end
else if Self is
TConexaoFirebird then
begin
fClientDataSet :=
dmFirebird.ClUsuario;
try
fClientDataSet.Close;
fClientDataSet.Open;
fClientDataSet.Refresh;
if not (fClientDataSet.
state in dsEditModes) then
fClientDataSet.Edit;
TBlobField(fClientDataSet.
FieldByName(MyFieldName)).
LoadFromFile(MyFile);
fClientDataSet.Post;
fClientDataSet.
ApplyUpdates(0);
except
on E: Exception do
begin
Raise EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
Result := False;
end;
end;
end;
end;
function TConexao.
GetConexao(const typeConexao:
tBDConexao): TConexao;
begin
if Assigned(Result) then
closeConexao;
case typeConexao of
bdConexaoDBISAM:
Result
:= TConexaoDBISAM.create;
bdConexaoXML:
Result
:= TConexaoXML.create;
bdConexaoFirebird: Result
:= TConexaoFirebird.create;
end;
end;
function TUsuario.
AbreTabelaUsuarios: TDataSet;
begin
Result := Conexao.RetornaData
Set(sqlSelectAllFieldsOrderByNo
me);
end;
Abaixo mostrado o mtodo
SetDataBase, onde solicitada
a troca de um banco. Note que
o nome dos bancos fazem parte
julho
2013
17
function TConexaoFirebird.
GetNextId(const fFieldName:
string; const fTable: string):
string;
18
julho
2013
var
fId: string;
begin
fId :=
TCustomSQLDataSet(Self.Retorna
DataSet(Format(sqlMaxIndexFrom
FieldNameFormat1, [fFieldName,
fTable]))).Fields[0].AsString;
if (fId = ) then fId :=
1;
Result := fId;
end;
Finalmente, o mtodo CarregaUsuarios alimenta um objeto TClientDataSet de retorno, onde como j mencionado anteriormente armazenar dados
apenas read-only: a aplicao jamais sensibilizar-los diretamente na base
de dados. Todo este acesso somente a classe TConexao realizar e de forma
abstrata. E isso um dos pontos mais interessantes deste projeto: imagina
trocar um banco de dados com sua aplicao rodando, ou envi-la ao cliente
em uma demonstrao do produto com algumas funcionalidades disponveis
e na verso paga alterar o banco de dados para uma nova base de dados mais
robusta e profissional; esta funcionalidade tornar sem dvida sua aplicao
isenta de implementaes amarradas de dentro da camada de apresentao
(mtodo tradicional de programao), trazendo mais produtividade em termos
de manuteno e desenvolvimento, e consequentemente mais agilidade e
praticidade durante todo o ciclo de vida da aplicao.
Com isso, finaliza-se a primeira parte deste artigo. Na prxima revista
falaremos sobre a implementao de um parser SQL para XML, utilizao
do componente de minha autoria para visualizao e validao de dados,
interagindo por debaixo dos panos o TMaskeditHV (explicado em edies
anteriores), explicao sobre importantes mtodos da nossa classe e finalmente o desenvolvimento de nosso programa de exemplo utilizando esta nossa
classe, em uma simulao real de sua implementao, obtendo e alternando
bases de dados distintas em tempo de execuo. At a prxima, e boa leitura!
Sobre o autor
Hamden Vogel
Analista de Sistemas ps-graduado em Engenharia de Software pela
UPIS e Programador Delphi com larga experincia desde 2000, tem desenvolvido e vendido softwares em Delphi para a frica e Estados Unidos,
alm do mercado nacional. Colaborou com dicas e componentes para sites
especializados em Delphi. Tambm desenvolve em outras linguagens como
C/C++, ASP, PHP e .NET.
suporte@theclub.com.br
Android
Trabalhando com o TouchScreen
m dos recursos mais poderosos e fascinantes no desenvolvimento utilizando o sistema android a possibilidade de
poder interceptar eventos na tela com o toque do dedo, o
TouchScreen. Temos classes especficas para este trabalho,
a minha idia neste ms descrever as principais funcionalidades destas classes junto com seus mtodos criando exemplos didticos e
de grande utilidade no dia-a-dia.
2013
19
Classe CriarImagem.java
Antes de iniciarmos a codificao desta classe ser necessrio adicionar
uma imagem qualquer em nosso aplicativo. Basta copiar e colar no diretrio
res/drawable-hdpi. Ver Imagem 03.
Observao Importante:
Esta imagem dever ser do tipo .png ou jpg possuindo o nome escrito
especificamente em caixa baixa para assim evitar problemas de compilao.
Logo em seguida importaremos as bibliotecas que sero utilizadas ao
decorrer do desenvolvimento.
Cdigo 01
package pct.Android_
OnTouchEvent;
20
julho
2013
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.
drawable.Drawable;
import android.util.
AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CriarImagem
extends View
{
private Drawable imagem;
private int x, y, largura,
altura;
private boolean Clicou;
public int movimento = 12;
A classe principal CriarImagem herdar da classe View. Utilizaremos
algumas variveis privadas, sendo uma do tipo Drawable responsvel por
trabalhar com a imagem, outras do tipo int onde definimos a largura, altura,
as coordenadas X, Y e uma booleana indicando se clicamos ou no na imagem.
Cdigo 02
public CriarImagem(Context
context, AttributeSet attrs)
{
super(context, attrs);
imagem =
context.
getResources().getDrawable(R.
drawable.theclub);
largura = imagem.
getIntrinsicWidth();
altura = imagem.
getIntrinsicHeight();
x = 150;
y = 300;
setFocusable(true);
}
No mtodo Construtor passamos dois parmetros: o Context o Contexto
da aplicao e o AttributeSet que significa uma coleo de atributos que podem ser utilizados dentro deste mtodo. O mtodo context.getResources().
getDrawable() ir recuperar a imagem, os mtodos getIntrinsicWidth() e
getIntrinsicHeight() iro retornar a largura e altura respectivamente, x e y
sero as coordenadas para posicionamento da imagem em relao a tela do
dispositivo. J o mtodo setFocusable() definir se a view ir ou no receber
o foco enquanto estiver em modo TouchScreen. Deixaremos como true
Cdigo 03
@Override
protected void onDraw(Canvas
canvas)
{
super.onDraw(canvas);
imagem.setBounds(x,y,x+largura
,y+altura);
imagem.draw(canvas);
}
public boolean
onTouchEvent(MotionEvent
motionEvent)
{
this.x = (int)motionEvent.
getX();
this.y = (int) motionEvent.
getY();
switch(motionEvent.
getAction())
{
case MotionEvent.ACTION_
DOWN:
{
Clicou = imagem.
copyBounds().contains(x,y);
break;
}
case MotionEvent.ACTION_
MOVE:
if (Clicou)
{
this.x = x (largura/2);
this.y = y (altura/2);
break;
}
case MotionEvent.ACTION_
UP :
{
Clicou = false;
break;
}
}
invalidate();
return true;
}
Este o principal evento que iremos trabalhar. Ele tem como parmetro
de entrada a classe MotionEvent e retorna um valor booleano. No primeiro
momento iremos atribuir s variveis globais X e Y as respectivas coordenadas com os mtodos getX() e getY(). Faremos um Case para comparar
julho
2013
21
Configuraes no AndroidManifest.xml
Nas configuraes do arquivo AndroidManifest.xml no faremos
praticamente nada de mirabolante, apenas setamos o uso da Activity
Android_OnTouchEventActivity que ser comentado logo a seguir. Ver em
seguida a listagem completa.
Cdigo 04
<?xml version=1.0
encoding=utf-8?>
<manifest xmlns:android=http://
schemas.android.com/apk/res/
android
package=pct.Android_
OnTouchEvent
android:versionCode=1
android:versionName=1.0>
<uses-sdk
android:minSdkVersion=8 />
<application android:icon=@
drawable/icon android:label=@
string/app_name>
<activity
android:name=.Android_
OnTouchEventActivity
android:label=@string/app_
name>
<intent-filter>
<action
android:name=android.intent.
action.MAIN />
<category
android:name=android.intent.
category.LAUNCHER />
</intent-filter>
</activity>
Criando o Lay-Out
O aplicativo possuir um LinearLayout onde conter um TextView e
um componente chamado desenho que faz referncia classe CriarImagem.
Ver Imagem 04.
</application>
</manifest>
Configuraes no Strings.xml
Este arquivo ir definir algumas
constantes que sero abordadas
ao decorrer do projeto, como
22
2013
O XML correspondente:
Cdigo 05
<?xml version=1.0
encoding=utf-8?>
<LinearLayout
xmlns:android=http://schemas.
android.com/apk/res/android
android:orientation=vertical
android:layout_width=fill_
parent
android:layout_height=fill_
parent
>
<TextView
android:layout_width=fill_
parent
android:layout_height=wrap_
content
android:text=@string/
hello
/>
<pct.Android_OnTouchEvent.
CriarImagem
android:id=@+id/desenho
android:layout_width=fill_
parent
android:layout_height=fill_
parent
android:background=@
color/cinza
/>
</LinearLayout>
Cdigo 06
package pct.Android_
OnTouchEvent;
import android.app.Activity;
import android.os.Bundle;
public class Android_
OnTouchEventActivity extends
Activity
{
@Override
public void onCreate(Bundle
savedInstanceState)
{
super.
onCreate(savedInstanceState);
setContentView(R.
layout.criarimagem);
}
}
O SetContentView() ser o mtodo que ir chamar a tela de nosso
aplicativo. Ver Imagem 06.
Exemplo em Run-Time
<pct.Android_OnTouchEvent.
CriarImagem />
Codificando o exemplo 1
Seguindo a lgica, a atividade Android_OnTouchEventActivity que
codificaremos a seguir, possuir uma chamada para o lay-out criarimagem.
xml que dentro do mesmo teremos a classe CriarImagem.java, na qual est
localizada toda a codificao de nosso exemplo.
2013
23
Classe PintarTela.java
Utilizaremos algumas bibliotecas adicionais para desenvolver este exemplo, veja abaixo:
Cdigo 07
package pct.Android_
OnTouchEvent;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.
AttributeSet;
import android.view.MotionEvent;
import android.view.View;
Temos a classe android.graphics.Paint sendo especfica para pintura,
estilo, cor. Ela tambm oferece base para desenhar geometrias, texto e bitmaps. J a classe android.graphics.Path permite realizar contornos e formas
geomtricas como: segmentos de linhas retas, curvas quadrticas e cbicas.
Cdigo 08
public PintarTela(Context
context, AttributeSet attrs)
{
super(context, attrs);
24
paint.setAntiAlias(true);
julho
2013
paint.setStrokeWidth(6);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.
STROKE);
paint.setStrokeJoin(Paint.
Join.ROUND);
}
Temos o mtodo setAntiAlias() que serve para suavizar as bordas de
nosso toque, o setStrokeWidh() o tamanho da linha, o setColor() para
definir a cor, o setStyle() o estilo e o setStrokeJoin() um tratamento
especfico para quando as linhas se juntarem.
Cdigo 10
@Override
protected void onDraw(Canvas
canvas)
{
canvas.drawPath(path,
paint);
}
Mtodo que ir desenhar usando as configuraes definidas anteriormente
na classe Paint.
Cdigo 11
@Override
public boolean
onTouchEvent(MotionEvent
motionEvent)
{
float eventX =
motionEvent.getX();
float eventY =
motionEvent.getY();
switch (motionEvent.
getAction())
{
case MotionEvent.
ACTION_DOWN:
path.
moveTo(eventX, eventY);
return true;
case MotionEvent.
ACTION_MOVE:
path.
lineTo(eventX, eventY);
break;
default:
return false;
}
invalidate();
return true;
Usaremos apenas as constantes ACTON_DOWN para dar incio do movimento de acordo com as coordenadas definidas fazendo o uso do mtodo
MoveTo() e a ACTION_MOVEpara adicionar uma linha a partir do ltimo
ponto especificado pelas coordenadas (x, y).
Configuraes no AndroidManifest.xml
Adicionaremos algumas configuraes bsicas neste arquivo j comentado
mais acima, veja o trecho:
Cdigo 12
...
<activity android:name=.
Android_OnTouchEventActivity_2
android:label=@string/app_
name>
<intent-filter>
<action
android:name=android.intent.
action.MAIN />
<category
android:name=android.intent.
category.LAUNCHER />
</intent-filter>
</activity>
...
Criando o Lay-Out
Teremos um LinearLayout onde conter um TextView e um componente chamado desenho que faz referncia classe Pintartela. Ver Imagem 07.
O XML correspondente:
Cdigo 13
<?xml version=1.0
encoding=utf-8?>
<LinearLayout
xmlns:android=http://schemas.
android.com/apk/res/android
android:orientation=vertical
android:layout_width=fill_
parent
android:layout_height=fill_
parent
>
<TextView
android:layout_width=fill_
parent
android:layout_height=wrap_
content
android:text=@string/
hello
/>
<pct.Android_OnTouchEvent.
PintarTela
android:id=@+id/desenho
android:layout_width=fill_
parent
android:layout_height=fill_
parent
/>
</LinearLayout>
Codificando o Exemplo 2
Seguindo os passos que j foram descritos acima foi necessrio criar
uma classe estendendo de uma Activity para invocarmos o XML contendo a
classe PintarTela. O mtodo SetContentView() ir chamar a tela de nosso
aplicativo. Ver Imagem 08.
Abaixo cdigo completo.
Cdigo 14
package pct.Android_
OnTouchEvent;
import android.app.Activity;
import android.os.Bundle;
public class Android_
OnTouchEventActivity_2 extends
Activity
{
@Override
public void onCreate(Bundle
savedInstanceState)
Figura 07: Lay-Out do exemplo 2.
julho
2013
25
super.
onCreate(savedInstanceState);
setContentView(R.
layout.pintartela);
}
}
Exemplo em Run-Time
Referncias
http://developer.android.com/reference/android/view/MotionEvent.html
http://developer.android.com/reference/android/view/View.html
Concluses
Uma das formas de interceptar os eventos de interao do usurio com o
aplicativo capturar estes eventos dentro de uma regio chamada View.
a partir desta classe que discorremos o artigo deste ms. Trabalhamos com o
evento OnTouchEvent(), que o evento que capta o toque do dedo na tela do
dispositivo e a classe MotionEvent, classe base para suporte para esta tarefa
junto com mtodos e constantes. No primeiro exemplo procurei demonstrar
como movimentar uma imagem com o TouchScreen, j no segundo como
pintar e escrever na tela do aplicativo. Esta uma das inmeras formas de usar
os recursos TouchScreen na programao Android.
Espero que tenham gostado! Deixo aqui um abrao e nos vemos no ms
que vem!
Sobre o autor
Thiago Cavalheiro Montebugnoli
adora aprender novas tecnologias. Formado pela Faculdade de Tecnologia de Botucatu
SP (FATEC), 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 colunista mensal da Revista The Club Megazine e consultor
Tcnico do The Club. 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
Figura 08: Desenhando e Pintando em Run-Time.
26
julho
2013
As principais mudanas
Delphi XE4
Selecionando o componente TcalendarEdit, no Object Inspector, abriremos a aba Events clicando duas vezes no espao vazio ao lado de onchange.
Escreveremos o cdigo da seguinte forma:
procedure TForm25.
CalendarEdit1Change(Sender:
TObject);
begin
ShowMessage(FormatDateTime(d
ddddd, CalendarEdit1.Date));
end;
Podemos tambm usar um componente de boto com estilos diferentes
em um aplicativo iOS como mostra a figura 02.
julho
2013
27
28
julho
2013
Antes de implementar manipuladores de eventos, primeiramente implantaremos um mtodo comum para abrir uma pgina web com base na
propriedade Text do Tedit.
Cdigo 02
Cdigo 03
Procedure TForm34.OpenURL;
Begin
WebBrowser1.Navigate(Edit1.
Text);
end;
Procedure Tform34.
Edit1KeyDown(Sender; bar Key:
Word;
var KeyChar: char; Shift:
TshiftState);
Begin
If (key = vkReturn) then
Begin
OpenURL;
Button1.SetFocus;
end;
end;
Pronto agora s testar e usar a criatividade para melhorar a interface
da aplicao.
Novo Compilador
Para oferecer suporte aos dispositivos mveis foram criados dois novos
compiladores, um para o simulador do iOS e outro para o dispositivo fsico
(ARM), j que as arquiteturas so distintas.Desta forma agora temos:
2013
29
faa uso de construes como TStringBuilder e TStringHelper para a manipulao de strings. Um trecho de cdigo utilizando estas classes para ilustrar:
Tipo String
Todos os tipos string existentes (AnsiString, UTF8String, RawByteString,
WideString, AnsiChar, PAnsiChar, PWideChar, OpenString, ShortString) agora
esto simplificados em um nico: String. Alm disso, as strings agora so
0-based ao invs de 1-based. Isso significa que alguns cdigos podem precisar
de reviso, mas as funes de manipulao de strings j esto preparadas
para esta mudana.
Outra importante mudana que as strings passaro a ser imutveis,
devido ao gerenciamento de memria dos dispositivos mveis. Nesta verso
do compilador tudo continua conforme anteriormente, voc receber apenas
uma warning alertando que, futuramente, construes como a exibida abaixo
no ser mais suportada:
Outras mudanas
1. Ponteiros no so suportados no mundo mobile
2. No h suporte para Inline assemby
3. Evite chamadas a APIs diretamente, esteja pronto para as novas
plataformas que viro.
4. Prefira utilizar as units cross-plataform, especialmente ao manipular
arquivos (unit IOUtils)
Informaes e recursos para pesquisa
5. Pginas principais dos produtos: RAD Studio, Delphi, C++ Builder,
HTML5 Builder
6. Documentao on line: http://docwiki.embarcadero.com/RADStudio/XE4/en
7. Tutorial Delphi para iOS: Delphi iOS Application Development
8. Link para download do trial: https://downloads.embarcadero.com/
free/rad-studio
9. Trial via Instant Trial (AppWave): http://windowsapps.com/rad-studio-trial.html?trial=1
10. Tudo o que h de novo no Delphi e C++ Builder XE4
11. O que h de novo especificamente no C++ Builder 64 bit
12. Lista de correes do Delphi e C++ Builder XE4: http://edn.embarcadero.com/article/43068
13. White Paper do Marco Cantu sobre todas as mudanas na linguagem: http://www.embarcadero.com/resources/white-papers/application-development
Concluso
Espero que tenham gostado do artigo, resumi as principais alteraes que
foram feita no Delphi XE4 que considero importante.
At a prxima.
Sobre o autor
Jos Antnio P. M. de Paula
Consultor Tcnico no The Club. Cursa o ltimo perodo da FATEC
(Botucatu) no curso de Informtica para Negcios.
str1[3]:=w;
zeca@datasmart.com.br
Portanto altamente recomendado que, para seus novos cdigos, voc
30
julho
2013
julho
2013
05
julho
2013