Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
__________________________________________________________________________________________
2
Criao da app;
Criao do layout;
Navegao entre as abas;
Navegao entre formulrios.
Requisitos:
1. Delphi XE5 ou superior;
2. Aparelho Android;
3. Aparelho iPhone com iOS 7 ou superior (caso deseje testar no iOS);
Obs 1. Serei bastante detalhista no incio para abranger iniciantes e experts.
Obs 2. Usarei nesses primeiros posts o RAD Studio XE6, devido ao novo recurso de formulrios Master que terei que
explicar em um segundo momento separado.
Criao da App
Vamos comear, evidentemente, abrindo o Delphi e criando a aplicao salvando-a em um diretrio de nossa
preferncia. Utilize o menu File > New > Multi-Device Application Delphi (no XE7, em XE5 e 6 o nome do menu
diferente, apenas verifique o correto). (Figura 1)
__________________________________________________________________________________________
3
Na tela que se abre, escolhemos o layout inicial de nossa aplicao. No se preocupe com isso agora, podemos mudar
com o tempo. Portanto, vamos escolher a opo Blank Application.
Somos levados ao primeiro Form de nossa app e vamos chama-la de frmMain (Principal). Existem milhares de tcnicas
diferentes para criar nosso layout e a navegao do aplicativo, mas nesse caso vou mostrar como eu tenho criado meus
aplicativos em minha empresa, assim fica como sugesto.
Para quem j est utilizando o Delphi XE7, deve estar visualizando algo diferente na IDE. So os layouts Master. Agora
possvel criar um layout principal e deixar que a IDE selecione o correto para cada dispositivo no momento de abertura
de nosso form. Mas isso assunto para outros posts, por enquanto vamos nos focar em celulares Android e iOS de 4.
Para isso selecione Android 4 Phone caso esteja no XE7, os demais leitores que esto em verses anteriores utilizem
as opes Google Nexus 4 ou Samsumg Galaxy S2/S4, etc. (Figuras 2 e 3)
Criando meu app step-by-step
Figura 2. Definio de Layout no XE7
Definio do Layout
Muito bom. A primeira coisa a se definir, na minha opinio, desenhar como a aplicao dever se comportar. Eu me
utilizo de vrias tcnicas para isso. Como no sou designer, mas tenho alguma noo de desenho, comprei um bloco
de folhas A3 tipo flipcharting onde costumo desenhar, rusticamente claro, o fluxo da minha aplicao. (Figura 4).
__________________________________________________________________________________________
4
Para quem no tem a mnima noo de desenho, existem inmeras ferramentas no mercado que ajudam nesse
quesito. Mas enfim, no nosso foco aqui. Vamos desenhar na nossa mente mesmo o que desejamos que nosso app
tenha. Proponho as seguintes telas:
Login e Senha;
Lista de Ttulos;
Lista de Usurios/Clientes;
Lista de Ttulos Alugados;
Alugar: Tela para definir o aluguel para um cliente;
Baixar Ttulo Alugado;
A ideia que o app seja utilizado pelo administrador da ocadora como se fosse a extenso de seu programa de uso no
desktop da loja, onde o cara poder consultar rapidamente algumas informaes sobre o ttulo. Nossa tela default ser
a Lista de Ttulos que dever abrir logo que de incio. Faremos um Login e Senha utilizando Parse.com como backend
de banco de dados para facilitar e aprender a usar o servio;
Teremos tambm um menu no estilo Facebook Mobile que se popularizou bastante, ou seja, abriremos as opes
tocando em um boto com Detalhes e o menu se abrir na lateral.
Para criamos o menu inicial, vamos utilizar um TLayout e um TListBox. Ambos devem ser colocamos no formulrio e
NO um dentro do outro. Adicione primeiro o TLayout e faa as seguintes configuraes:
Name: lytMain;
Align: Client;
Agora adicione um TListBox no Form e ento faremos uma srie de mudanas nele conforme mais abaixo.
#Dica: Caso tenha dificuldades em selecionar o Form principal j que o TLayout ficou por cima de tudo, apenas clique
no TLayout e pressione 1x o ESC. Isso far com que o Form seja selecionado.
E caso j tenha adicionado o TListBox dentro do TLayout, basta acessar a caixa de estrutura e mover o TListBox para
cima do Form;
Configure o TListBox como segue:
Name: lstMnuMain
Align: Cient
GroupKind: Grouped
StyleLookup: transparentlistboxstyle
Agora que configuramos as principais propriedades, precisamos adicionar os itens que sero nossos Itens de Menu.
Agruparemos em categorias, por isso utilizamos a propriedade GroupKind para dar um aspecto mais profissional
acrescido do StyleLookup como Transparent.
Obs. Em dado momento faremos a personalizao da aplicao incluindo um layout mais customizado
__________________________________________________________________________________________
5
Clique agora com o boto direito no TListBox e escolha Items Editor para acessarmos o gerenciador de itens
do ListBox. No ComboBox direita da caixa, encontramos os tipos de itens que podemos adicionar. Usaremos sempre
dois tipos (Figura 5):
TListBoxGroupHeader: Cabealho do Grupo;
TListBoxItem: Item
__________________________________________________________________________________________
6
#Dica: Em Mobile, os botes (figuras) que ficam direita do item na lista so chamados de Acessory (Acessrio). Servem
para indicar se o item possui um Mais Informaes, Sub Detalhe ou ainda um Check para por exemplo indicar
que o item est selecionado para alguma ao.
#Dica: Procure observar outros aplicativos e seguir os conceitos padres de cada sistema operacional, pois o principal
fator para que uma aplicao tenha sucesso : Usabilidade. Lembre-se que o usurio j est acostumado com certos
comportamentos nos apps que j utiliza no dia-a-dia.
Configuraremos somente os itens de nosso interesse. Clique no ListBoxItemGroupHeader1 e configure como a seguir:
Name: lstgrpListas
Text: Cadastros
O segundo grupo, modifiquei como a seguir:
Name: lstgrpConfig
Text: Configuraes
Agora configure o TListBoxItem1 como a seguir:
Name: lstitTitulos
Text: Ttulos
ItemData > Acessory: More
Repita os passos anteriores para configurar os demais itens de menu. Nosso menu final ter que ficar semelhante
a Figura 7. Os Names,respectivamente, so:
lstitTitulos
lstitUsuarios
lstitTitulosAlugados
lstitLogin
__________________________________________________________________________________________
7
Primeira codificao
Perfeito at aqui e sei que esto eufricos para codificar tudo. Ento mos a obra. Primeiro criaremos mtodos para
mostrar e ocultar o menu. Para isso, teremos que adicionar alguns elementos visuais ao formulrio para termos uma
aparncia mais interessante.
Adicione ao formulrio 2 (dois) novos componentes. 1 TFloatAnimation e 1 TRectangle. Eles devem ficar DENTRO do
lytMain. O componente de animao deve receber o Name = AnimateDrawer. J o TRectangle precisa ser configurado
como a seguir:
Name: recBackground
Opacity: 0,5
Fill.Color : Black
PropertyName: Position.X
Essas configuraes daro um aspecto mais profissional. Se desejar conferir a estrutura dos componentes novos,
observe a Figura 9.
procedure HideMenu;
procedure ShowMenu;
Pressione Ctrl + Shift + C para criar o escopo de cada mtodo e vamos ao cdigo de cada um conforme a Listagem 2.
Listagem 2. Cdigo dos mtodos criados para Mostrar e Ocultar o Menu
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
procedure TfrmMain.HideMenu;
begin
//Posiciona o ListBox de menu fora da viso
lstMnuMain.AnimateFloat('Position.X', -Self.ClientWidth);
AnimateDrawer.StartValue := Self.ClientWidth - 40;
AnimateDrawer.StopValue := 0;
AnimateDrawer.Start;
end;
procedure TfrmMain.ShowMenu;
begin
AnimateDrawer.StartValue := 0;
AnimateDrawer.StopValue := Self.ClientWidth - C_MnuEspaco;
AnimateDrawer.Start;
//Reposiciona o menu principal
lstMnuMain.AnimateFloat('Position.X', 0);
//Mostra o retngulo preto sobre a lista ativa
ShowBackground(Self.lytMain, CancelMenu);</pre>
<pre>end;
No primeiro mtodo, HideMenu, posicionamos o ListBox do menu para fora da rea de visualizao utilizando uma
animao atravs do mtodo AnimateFloat. Esse mtodo um dos que mais gosto de usar. bem simples e
praticamente todos os objetos Firemonkeypossuem. Basta passar a propriedade que se deseja animar no primeiro
parmetro e o novo valor no segundo parmetro. Nesse caso usamos Position.X com o valor -Self.ClientWidth, que far
o componente se descolar para a esquerda.
Em seguida animamos o layout usando o nosso componente TFloadAnimation. O cdigo ao meu ver dispensa
comentrios assim como o mtodo ShowMenu que exatamente o inverso. Apenas observe que reposicionamos o
ListBox na posio 0 (Zero).
Teremos ainda que criar outros mtodos que nos ajudaro a controlar melhor o menu. Retorne as
sees Private e Public do form e adicione os novos mtodos conforme a Listagem 3.
Listagem 3. Outros mtodos de controle do menu
?
1
2
3
4
5
6
7
8
9
10
private
{ Private declarations }
procedure HideMenu;
procedure ShowMenu;
procedure CancelMenu(Sender: TObject);
public
{ Public declarations }
procedure ShowHideMenu;
procedure ShowForm(AObject: TFmxObject);
procedure ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent = nil);
procedure HideBackground;
end;
Vamos as explicaes:
CancelMenu: Ser necessrio para esconder o retngulo opaco da tela e ocultar o menu;
__________________________________________________________________________________________
9
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
ShowHideMenu;
end;
procedure TfrmMain.ShowHideMenu;
var
Position : single;
begin
{Verifica a posio atual do menu e mostra ou oculta conforme necessrio}
Position := Self.ClientWidth - 40;
case Self.lytMain.Position.X = Position of
true : HideMenu;
false : ShowMenu;
end;
end;
procedure TfrmMain.ShowForm(AObject: TFmxObject);
var
I : Integer;
begin
HideBackground;
for I := 0 to Pred(Self.lytMain.Children.Count) do
TControl(Self.lytMain.Children[I]).Visible :=
TControl(Self.lytMain.Children[I]) = TControl(AObject);
end;
procedure TfrmMain.ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent);
begin
//Atualiza o evento OnClick do retgulo com a ao enviada por parmetro.
///Isso far com que saibamos a tela (ou ao) que deve ser mostrada ao clicar no retngulo
recBackground.OnClick := AOnClick;
recBackground.Parent := AParent;
recBackground.BringToFront;
//Modifica a transparncia do retngulo e anima a transparncia
recBackground.Opacity := 0;
recBackground.Visible := True;
recBackground.AnimateFloat('opacity', 0.5, 0.1);
end;
procedure TfrmMain.HideBackground;
begin
recBackground.AnimateFloat('opacity', 0, 0.1);
recBackground.Visible := False;
end;
Vamos
as
explicaes
de
cada
mtodo
iniciando
por CancelMenu. Esse
mtodo
apenas
chama HideBackground e ShowHideMenuforando o retngulo opaco desaparecer e checando se o menu est aberto
ou fechado para saber para onde temos que ir.
Em seguida ShowHideMenu. Atravs da varivel Position conseguimos detectar qual o posicionamento do Menu (nosso
ListBox, lembre-se). A varivel recebe a largura da tela atual, ou seja, funcionar tanto com celulares quanto com
tablets e na horizontal ou vertical. E subtramos 40 px para evitar que a tela (listagem) atual suma completamente da
viso do usurio. Com base na posio do menu, decidimos se o mostramos ou ocultamos.
ShowForm ser responsvel por receber o objeto (Form, Layout, TabControl) alvo e deixa-lo visvel para o usurio. A
ideia simples. Quando codificarmos o OnClick de cada Item de Menu, faremos um AddObject dentro do nosso
lytMain, em seguida chamamos ShowForm para ocultar todos os outros formulrios e mostrarmos somente o atual.
Isso necessrio, pois nosso ListBox est configurado como como Transparente. Se deixarmos visveis os demais forms,
corremos o risco de sobrepor as telas.
Por fim ShowBackGround e HideBackGround. No primeiro mtodo, recebemos o Parent do objeto que est sendo
carregado, para que o retngulo opaco fique sobre ele, assim teremos um aspecto esmaecido do form quando o
menu estiver aberto. Tambm recebemos um evento OnClick caso desejarmos que ao clicar no retngulo algo
acontea. Por fim trazemos ele para frente e configuramos sua opacidade, visibilidade e a animao para aparecer.
Reparem que estou usando novamente o mtodo AnimateFloat (dessa vez no retngulo) passando como parmetro a
propriedade opacity e os valores 0.5 e 0.1 nos parmetros seguintes.
O 0.5 o novo valor da opacidade, para deixa-lo levemente transparente. O 0.1 o tempo que levar para a animao
ocorrer.
__________________________________________________________________________________________
10
Vamos apenas configurar as propriedades mais bsicas e o layout principal do formulrio. Na Parte II do post faremos
a prototipao da janela para evitar que esse post fique ainda maior.
Primeiro adicione um ToolBar no formulrio e mude sua propriedade Name para toolTitulos. Inclua em seguida um
TLayout ao formulrio e chame-o de lytTitulos. Tambm configure-o para que fique com alinhamento Client (Align =
Client). Ns carregaremos o lytTitulos dentro do lytMain no formulrio principal.
Dentro do TLayout adicione um TabControl e configure suas propriedades como a seguir:
Name: tabctrlTitulos
TabPosition: Bottom
__________________________________________________________________________________________
11
Clique com o boto direito no TabControl e adicione uma nova aba usando o item Add TTabItem. Nessa TabItem (que
chamamos de Aba) colocaremos nossos controles para acesso a base de dados. Por enquanto vamos adicionar apenas
um TLabel com alinhamento Client e o Text igual a Listagem de Ttulos. Modifique tambm a
propriedade TextSettings.HorzAlign para Center, apenas para sinalizar quando carregarmos essa janela no dispositivo
ou emulador.
Para fechar, adicione um TSpeedButton dentro da ToolBar. Ele ser nosso boto voltar. Configure-o como a seguir:
Name: spbBack
StyleLookup: detailstoolbutton
Align: Left
Margins.Left: 8
Teremos ento uma aparncia semelhante a imagem da Figura 12.
frmMain.ShowHideMenu;
Fazendo isso, ns chamamos o mtodo ShowHideMenu que se encarregar de mostrar o menu novamente para que
o usurio possa entrar em outra janela.
Uma ltima alterao no cdigo-fonte da janela, retire a declarao da varivel com a instncia do form, no
precisaremos dela. Localize a seo implementation e apague as linhas como a seguir:
?
1
2
var
frmTitulos: TfrmTitulos;
__________________________________________________________________________________________
12
Retornamos agora para o formulrio principal para fazer a as devidas chamadas e abrir a nossa tela de ttulos.
Acesse File > Use Unit e adicione o formulrio de ttulos a seo interface do form principal. Agora selecione
o lstitemTitulos e adicione o cdigo da Listagem 5ao evento OnClick.
Listagem 5. Cdigo do evento OnClick para abertura da tela Listagem de Ttulos
?
1
2
3
4
5
6
7
8
9
O que estamos fazendo aqui bem simples na verdade. Primeiro verificamos se h alguma instncia do formulrio de
ttulos na memria. Note que usamos uma varivel FTitulos para isso e logo em seguida criamos o Form frmTitulos. A
variveis FTitulos precisa ser declarada na seo Private do form principal, como abaixo:
?
1
2
3
4
...
private
FTitulos: TfrmTitlos;
...
Na seqncia adicionamos o TLayout lytTitulos (Form Titulos) ao TLayout lytMain do formulrio principal. Por fim
chamamos ShowFormpara fazer com que o form se torne visvel. A ltima instruo evita que o menu aparea caso
quem esteja chamando o mtodo seja o prprio form principal.
Estaria pronto para testar nesse momento, mas ainda vamos fazer umas configuraes. Lembram-se que nosso
formulrio de ttulos ser aberto assim que a app inicializar? Pois bem, teremos que codificar ento o
evento OnCreate do form principal. Para isso selecione o Form e clique duas vezes no evento OnCreate e codifique
como na Listagem 6.
Listagem 6. OnCreate do form principal
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Precisamos de algumas personalizaes aqui. Primeiro ns deixamos o retngulo invisvel e mudamos seu alinhamento
para Contents,ou seja, ao contedo, equivalente a opo Client.
#Dica: A diferena entre os alinhamentos Client e Contents, que Contents encobre tambm as barra de status do
aparelho, normalmente visvel na parte superior.
Em seguida ajustamos o menu principal e trazemos o layout para frente de todos os objetos. Por fim, chamamos o
mtodo lstitTitulosClick para forar a abertura do formulrio Listagem de Ttulos.
E a ltima codificao acontece no evento OnClose do formulrio principal. Foramos a liberao da instncia do
formulrio de ttulos caso esteja aberto.
?
1
2
if Assigned(FTitulos) then
FTitulos.DisposeOf;
Ateno para o mtodo DisposeOf. No utilize em Mobile o mtodo Free ou FreeAndNil, pois acabam entrando na fila
do ARC(Gerenciamento de Memria do dispositivo). O DisposeOf fora o FREE da varivel imediatamente. Em outras
palavras, variveis ou objetos devem ser liberados de memria usando esse mtodo.
__________________________________________________________________________________________
13
Testando a app
bvio que depois de chegarmos at aqui, estamos curiosos para testar a aplicao. Ento hora de contar um
segredo. No exatamente um segredo, mas uma dica til. No vamos perder tempo compilando
para iOS ou Android, ou ainda nos simuladores/emuladores. Vamos testar direto no Windows, pois todas as
funcionalidades at aqui codificadas funcionam perfeitamente no Windows.
Para isso, acesse o Project Manager sua esquerda (caso no tenha mudado as configuraes do Delphi) e clique com
o boto direito em cima de Target Platforms. Clique em Add Platform e escolha Win32 na janela que aparece (Figuras
13 e 14).
__________________________________________________________________________________________
14
Concluso
Assim como mencionado desde o incio, existem milhares de maneiras diferentes de criar layouts e navegao em uma
app Mobile. Essa apenas uma delas. Vimos nesse post como criar nosso primeiro menu no estilo Facebook e como
interagir com mais de um form na mesma aplicao.
No prximo post, veremos como prototipar a aplicao. Criaremos uma lista de ttulos utilizando LiveBindings e o
componente PrototypeBindSource assim como o uso de DataModule.
Uma atualizao. Existe uma constante mencionada no mtodo ShowMenu, C_MnuEspaco. Troquem ela pelo valor
40. Esse o espao que a listagem ficar afastada quando o menu estiver aberto.
?
1
2
3
4
5
6
7
8
9
10
11
12
procedure TfrmMain.ShowMenu;
begin
AnimateDrawer.StartValue := 0;
AnimateDrawer.StopValue := Self.ClientWidth - 40;
AnimateDrawer.Start;
//Reposiciona o menu principal
lstMnuMain.AnimateFloat('Position.X', 0);
//Mostra o retngulo preto sobre a lista ativa
ShowBackground(Self.lytMain, CancelMenu);
end;
__________________________________________________________________________________________
15
1.
2.
3.
4.
5.
6.
7.
8.
9.
A primeira parte desse tutorial publicada uma semana atrs (Link aqui) teve como principal objetivo iniciar uma srie
de artigos em formato passo-a-passo mostrando algumas das principais tcnicas e funcionalidades existentes na
ferramenta de desenvolvimento RAD Studio XE6. O objetivo do tutorial construir um aplicativo totalmente a partir
do zero e que seja compatvel com iOS e Android.
No post anterior fomos capazes de:
Criar o app;
Criar o layout inicial;
Desenvolver a navegao base entre as abas;
Desenvolver a navegao base entre os formulrios da aplicao.
Nessa segunda parte, veremos como criar nosso primeiro prottipo do aplicativo que nos ser til para entender e
definir os aspectos gerais do app. Tambm veremos:
Criao do primeiro prottipo funcional;
Criao de dados fictcios com LiveBindings;
Ligao dos dados fictcios do LiveBindings com o objetos de tela, tais como TListView;
Montagem das demais telas do sistema utilizando LiveBindings;
Uso do servio Parse.com;
Criao de Classe para Login e Senha na nuvem bem como outras funcionalidades;
Login e Senha on-line;
Modelagem da nossa base de dados SQLite;
Introduo ao SQLite e sugesto de ferramentas.
Requisitos:
Assistir ao vdeo: FireUI Novo Form Designer RAD Studio XE7
Assistir ao vdeo: TMultiView no RAD Studio XE7
Assistir ao vdeo: Aula complemento Criando meu app step-by-step
Leitura: Como cadastrar e validar login no servio Parse.com usando RAD Studio XE6
1.
2.
3.
4.
Retomando o raciocnio
Assim como mencionado no incio desse artigo, no captulo anterior iniciamos a criao de nosso app a partir do RAD
Studio XE6/Delphi XE6. Nesse captulo vamos dar continuidade ao nosso desenvolvimento, mas agora com um pouco
mais nfase em dados e processos reais.
Para comear, espero que tenham assistido aos vdeos indicados na rea de requisitos, pois so importantes para
darmos continuidade. Na Figura 1, logo abaixo, vemos como ficou nosso formulrio principal, frmMain, depois da
migrao para o RAD Studio XE7.
__________________________________________________________________________________________
16
Prototipao
Vamos nos concentrar na primeira janela de nosso app, Lista de Ttulos. Abra esse Form e adicione a ele um
componente do tipo TPrototypeBindSource da paleta LiveBindings.
#Dica: Para encontrar os componentes de maneira mais rpida, digite o nome do componente no campo de pesquisa
da Tool Palette.
Esse componente nos d plena condio de criar uma lista fictcia com dados para preenchimento de nossa lista. Agora
adicione tambm um componente do tipo TListView da paleta Standard e d o nome de lsvTitulos a ele. Configure suas
propriedades como a seguir:
Name: lsvTitulos
ItemAppearance.ItemAppearance: MultiRightDetail
ItemAppearanceObjects.ItemObjects.Image.Visible: True
#Dica: O TListView padro do Delphi no possui a opo MuiltiRightDetail, por isso assista ao vdeo TMultiView no RAD
Studio XE7 para ver como fazer a instalao desse componente.
Agora clique duas vezes no componente PrototypeBindSource1 e vamos adicionar os campos relacionados ao nosso
prottipo. Com o dilogo aberto, clique no nico boto disponvel no momento para adicionar o primeiro campo. Uma
nova caixa de dilogo ser aberta com duas colunas: Generator e Type. Aqui temos todo tipo de dado que pode ser
gerado aleatoriamente pelo Delphi para simular um banco de dados.
Inicie usando o item ContactBitmaps. Clique nele e no campo logo acima, FieldName, digite o valor FOTO. Esse ser o
campo para receber a foto do ttulo a ser alugado, ou seja, a capa do DVD.
Repita esse passo adicionando os campos como na Tabela 1:
Generator
ContactBitmaps
ContactNames
Type
ftBitmap
ftStrings
Field Name
Foto
Titulo
__________________________________________________________________________________________
17
ContactNames
AlphaColors
Tabela 1. Campos do prottipo de ttulos
ftStrings
ftUInteger
SubTitulo
CodTitulo
O resultado ser semelhante a Figura 2 onde conseguimos visualizar todos os campos da nossa lista fictcia.
O Bind Visually localiza todos os controles da tela e possibilita que liguemos um ao outro para que tenhamos uma
atualizao automtica sem a necessidade de codificao. Em nosso exemplo usaremos apenas os componentes
TListView (lsvTitulos) e o TPrototypeBindSource (PrototypeBindSource1). O restante pode ser ocultado clicando com o
direito nele e escolhendo a opo Hide Element(s).
#Dica: Selecione todos os componentes que ficaro ocultos. Clique em cada item com a tecla Ctrl selecionada. Em
seguida clique em um dos controles selecionados com o boto direito do mouse e ento Hide Element(s).
Note que no lsvTitulos temos as propriedades representadas no Bind Visually:
Item.Text
Item.Detail1
Item.Detail2
Item.Detail3
Item.Bitmap
__________________________________________________________________________________________
18
Entre outras, claro. O que vamos fazer agora ligar cada campo da nossa lista as respectivas propriedades. Por isso,
arraste, em primeiro lugar, o Astersco do Prototype a propriedade Synch. Em seguida siga a lista abaixo:
Foto >>> Item.Bitmap;
CodTitulo >>> Item.Detail3
Titulo >>> Item.Detail1
SubTitulo >>> Item.Detail2
Teremos algo semelhante a Figura 4, inclusive com o formulrio j mostrando dados fictcios.
Prottipo de Usurios
Para a janela de usurios, crie um novo formulrio usando o menu File > New > Multi-Device Form Delphi. Modifique
sua propriedade Name para frmUsuarios e salve-o como UntUsuarios. Inclua tambm um TLayout com o nome de
lytUsuarios e alinhe-o como Client. Coloque uma ToolBar dentro do Layout e logo em seguida um SpeedButton dentro
da ToolBar. Configure-o como a seguir:
Name: spbBack
Align: Left
Margins.Left: 8
StyleLookup: detailstoolbutton
Adicione a ele um TListView com propriedade de alinhamento ao Cient. Repita todos os passos da sesso anterior para
criar um prottipo com uma lista de usurios. Siga a Tabela 2 com os nomes de campos e tipos de dados.
Generator
ContactBitmaps
ContactNames
ContactNames
AlphaColors
Tabela 2. Campos do Prottipo de Usurios
Type
ftBitmap
ftStrings
ftStrings
ftUInteger
Field Name
Foto
Nome
Apelido
CPF
__________________________________________________________________________________________
19
Faremos uso agora do servio de banco de dados na nuvem chamado Parse.com. Desde a verso anterior do Delphi,
ns contamos com componentes do tipo BaaS (Backend as a Services). Esse tipo de servio tem se popularizado
bastante ultimamente.
No incio desse artigo, na sesso Requisitos, voc encontra um link para um artigo que escrevi falando justamente
disso, portanto no vou me estender muito nesse tpico. Tomarei como verdade que voc j entrou no servio
Parse.com, cadastrou-se e criou sua classe Users no servidor deles. No se preocupe, no tutorial informado em
requisitos j h todas as informaes necessrias para o cadastramento no servio.
A partir daqui, crie um novo form que iremos usar como janela de login. D o nome a essa janela de frmLogin e salvea como UntLogin.pas. Repita os passos das telas anteriores para montar o layout base, ou seja, insira um TLayout e
coloque-o como alinhamento ao Client. Dentro dele uma ToolBar e um SpeedButton com o nome spbBack.
Agora iremos montar um box para digitao de usurio e senha. O design fica por sua conta, mas nesse tutorial irei
usar um componente TCalloutPanel da paleta Standard. Alinhe-o como Vertical e aumente ou diminua sua altura de
acordo com seu gosto.
Dentro dele insira um SpeedButton mudando seu Text para Enviar e seu alinhamento para Bottom. Agora coloque
um ListBox com 3 (trs) linhas e seu alinhamento como Client. Modifique a propriedade e ItemHeight para algo em
torno de 40 ou 50 pixels. Isso aumentar a altura das linhas do ListBox.
O primeiro item do Listbox ter sua propriedade Text alterada para Registrar-se. E coloque tambm um componente
do tipo TSwitchda paleta Standard. Configure-o como a seguir:
Name: swtRegistrar
Align: Right
Margins.Right: 10
A segunda e terceira linha contero os Edits para digitao de login e senha. Altere a propriedade Text de ambos para
Usurio e Senha, respectivamente. Insira um TEdit em cada linha alinhando-os direita com margem direita de
10px. Os nomes deles podem ser edtUsuario e edtSenha. O edtSenha precisa ter sua propriedade Password para True.
Localize a paleta de compnentes BaaS Client e adicione o componente BackendUser mudando seu nome
para bkendUsuarios. Localize agora o componente TParseProvider e adicione-o a tela dando o nome de ppUsuarios.
O primeiro componente adicionado o componente que se conectar on-line ao servio e validar nosso usurio e
senha. J o ppUsuarios receber as informaes de nosso cadastro no servio, tais como as chaves de acesso
criptografaras. Por isso, conecte o bkendUsuarios ao ppUsuarios usando a propriedade Provider.
Em ppUsuarios alimente as propriedades ApplicationID, RestApiKey e MasterKey com os valores de sua conta no
servio Parse.com. Em caso de dvidas onde obter tais informaes, leia o artigo recomendado em requisitos. Confira
a Figura 5 como nossa tela dever se assemelhar.
__________________________________________________________________________________________
20
unit Login;
interface
uses
{$Region 'FireDac'}
FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf,
FireDAC.DApt.Intf, FireDAC.Stan.Async, FireDAC.DApt, FireDAC.UI.Intf,
FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Phys, FireDAC.Phys.SQLite,
FireDAC.Stan.ExprFuncs, FireDAC.FMXUI.Wait, Data.Bind.EngExt,
Fmx.Bind.DBEngExt, FireDAC.Comp.UI, Data.Bind.Components, Data.Bind.DBScope,
Data.DB, FireDAC.Comp.Client, FireDAC.Comp.DataSet,
{$EndRegion}
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants, FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs,
FMX.StdCtrls, FMX.MobilePreview, System.Rtti,
REST.Backend.ServiceTypes, REST.Backend.MetaTypes, System.JSON,
REST.OpenSSL, REST.Backend.ParseProvider, REST.Backend.Providers,
REST.Backend.ServiceComponents;
type
TLogin = class
private
FSession
: TBackendEntityValue;
FSessionStarted : Boolean;
FObjBackEndUsers: TBackendUsers;
public
constructor Create;
destructor Destroy;
function Login(AUser, APassword: string): Boolean;
function Logout: Boolean;
function SignUp(AUser, APassword: string): Boolean;
published
property Session
: TBackendEntityValue read FSession
write FSession;
property SessionStarted : Boolean
read FSessionStarted
write FSessionStarted;
property ObjBackEndUsers: TBackendUsers read FObjBackEndUsers write FObjBackEndUsers;
end;
implementation
end.
__________________________________________________________________________________________
21
Criamos tambm duas propriedades, Session e SessionStarted que dispensam comentrios. Apenas uma informao
relacionada a Orientao a Objetos. Internamente nossa classe atualiza as propriedades criadas atravs das
variveis FSession e FSessionStarted. Mas por fora da classe fazemos referncia pela propriedade, ou seja:
?
1
2
if MeuObjetoLogin.SessionStarted then
//usurio logado, chama tela XXX
Pressione Ctrl + Shift + C para criar o escopo dos mtodos e codificarmos. Uma propriedade/varivel que no expliquei
propositadamente foi FObjBackEndUsers. Essa propriedade ser responsvel por receber a referncia ao
objeto BackEndUserscolocado na tela de login. Assim nossa classe fica genrica e podemos us-la em qualquer lugar.
Na Listagem 2 voc pode ver todo o cdigo de cada mtodo.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
constructor TLogin.Create;
begin
inherited Create;
{$IFDEF DEBUG}
FSessionStarted := True;
{$ELSE}
FSessionStarted := False;
{$ENDIF}
end;
destructor TLogin.Destroy;
begin
inherited Destroy;
end;
function TLogin.Login(AUser, APassword: string): Boolean;
var
tmpSession : TBackendEntityValue;
begin
try
FObjBackEndUsers.Users.LoginUser(AUser, APassword, tmpSession);
FSession
:= tmpSession;
FSessionStarted := True;
Result
:= True;
except on E:Exception do
begin
{ Erro de usurio e senha }
if E.Message.Equals('Parse Error: invalid login parameters (101)') then
raise Exception.Create('Usurio ou Senha invlidos!');
Result := False;
end;
end;
end;
function TLogin.Logout: Boolean;
begin
try
FObjBackEndUsers.Users.Logout;
FSessionStarted := False;
Result
:= True;
except on E:Exception do
begin
{ Erro de usurio e senha }
if E.Message.Equals('Parse Error: invalid login parameters (101)') then
raise Exception.Create('Usurio ou Senha invlidos!');
Result := False;
end;
end;
end;
function TLogin.SignUp(AUser, APassword: string): Boolean;
var
Session : TBackendEntityValue;
begin
try
{ Valida se nome de usurio j existe na base }
FObjBackEndUsers.Users.QueryUserName(AUser, Session);
if Session.ObjectID.IsEmpty then
begin
__________________________________________________________________________________________
22
60
61
62
FLibLogin := TLogin.create;
Na sesso Public do form adicione a varivel FLibLogin do tipo TLogin (usada no cdigo anterior) e d um Use
Unit no Login.pasadicionando a unit ao Uses da Interface. Assim passaremos a partir de agora a usar a unit da Classe.
Nosso formulrio principal o primeiro a ser iniciado, portanto o nico que far referncia direta a Login.pas por
enquanto. para acessar as propriedades da classe, usaremos algo como:
?
1
Retorne agora a nossa janela de Login, frmLogin. Aqui precisaremos apenas codificar o boto de login, speLogin. Digite
nele o cdigo abaixo:
?
1
2
frmMain.FLibLogin.ObjBackEndUsers := bkendUsuarios;
case swtRegistrar.IsChecked of
__________________________________________________________________________________________
23
3
4
5
Imagino que j tenham entendido ;). Caso o Swtich esteja marcado, significa que o usurio deseja cadastrar-se no
sistema, portanto chamamos o mtodo de cadastro da nossa classe, caso contrrio nosso Login. Perceba que apenas
chamamos os mtodos e no fazemos desvios, ou seja, o correto seria:
Caso o usurio consiga se cadastrar ou fazer o login, devemos chamar o click do menu Titulos para que carreguemos a
Listagem de Ttulos ou poderamos chamar qualquer tela.
Para no nos estendermos mais nesse tpico, deixo a cargo do leitor fazer os respectivos desvios.
Obs. Na primeira linha do cdigo alimentamos a propriedade ObjBackendUsers passando como referncia o objeto em
rela.
Modelagem de Dados
Para que possamos prosseguir com nosso aplicativo, vamos iniciar tambm nesse artigo a modelarem de nosso banco
de dados local, ou seja, no dispositivo. Para isso vamos utilizar um banco de dados bastante utilizado o SQLite.
O SQLite apenas um dos bancos de dados que podem ser utilizados em dispositivos mveis. Tambm possvel
usarmos IBLite, uma verso reduzida do Intebase da Embarcadero. Para saber mais sobre SQLite, voc pode acessar o
site http://www.sqlite.org que possui uma vasta documentao.
Com ele podemos realizar diversas tarefas, pois apesar de compacto, um banco bastante completo.
Existem milhares de ferramentas na internet para fazer a manuteno e criao de bancos SQLite e uma delas
o SQLite
Expert e
pode
ser
baixado
em www.sqliteexpert.com.
Existem
basicamente
duas
verses, Express e Professional e claro, utilizado a verso Express que gratuita e j ajuda bastante. Tomarei ele como
base ento para nosso artigo.
Outra ferramenta importante para mantermos uma documentao de nosso banco o DIA, uma ferramenta de
modelagem FREE, simples e objetiva. Ele pode ser encontrado e baixado em http://dia-installer.de. Minha sugesto
baixar a verso Full, pois existe a verso Portable no baixaki.com.br, mas no legal.
Acesse a ferramenta DIA abra-a em seu equipamento. No entraremos em detalhes sobre o DIA, ento resumirei suas
caractersticas.
Com o DIA aberto, Figura 6, observe na barra lateral a opo Fluxograma. Clicando nessa opo e em seguida
em Outras Folhaspodemos ver que h inmeros fluxogramas que podemos utilizar para desenhar nossa soluo. Utilize
a opo Bancos de Dados, assim ns podemos incluir nossas entidades. Por enquanto vamos criar somente a tabela de
Ttulos.
__________________________________________________________________________________________
24
Campo
Type
Tamanho
ID_TITULO
Integer
TITULO
String
30
SUBTIULO
String
50
ANO_LANCAMENTO
Integer
Tabela 3. Tabela TITULOS do banco de dados
A aparncia de nossa entidade dever se parecer com a Figura 7.
Especial
AutoInc / Chave Primria
No Nulo
No Nulo
Concluses
Muito bem. Nessa segunda etapa de nosso aplicativo conseguimos dar passos importantes. Criamos uma classe para
efetuarmos o Login e Senha no sistema. Iniciamos a criao do banco de dados local e fizemos, claro, a migrao do
aplicativo da verso RAD Studio XE6 para XE7.
__________________________________________________________________________________________
25
1.
2.
3.
4.
No post anterior iniciamos uma das partes mais importantes de nosso aplicativo mobile com RAD Studio, o banco de
dados. Aprendemos a iniciar a criao de nosso banco utilizando o SQLite, banco bastante popular em aplicaes
mveis, utilizando para isso o aplicativo Free SQLite Expert bem como o DIA para modelagem de nossas entidades.
Nesse tutorial daremos foco para o uso de banco de dados em nosso aplicativos. Criaremos as novas tabelas e
ligaremos em nossas listagens. Em resumo no post anterior fomos capazes de:
Migrar nossa aplicao de Delphi XE6 para XE7;
Recriar o menu lateral utilizando o novo componente TMultiView;
Criar uma tela inicial de login;
Criar nosso primeiro banco de dados SQLite;
A terceira parte desse tutorial ser um pouco mais curta, mas rica em detalhes. Vermos a seguir:
Criao do DataModule principal;
Configurao dos principais componentes de acesso ao banco de dados;
Criao dos mtodos de listagem de Titulos e Detalhes dos Titulos;
Montagem das telas funcionais.
Requisitos:
Leitura: Tutorial: Criando meu app step-by-step Parte II
Assistir ao vdeo: TDevRocks Binding vs TListViews
1.
2.
3.
4.
Retomando o Raciocnio
Assim como mencionando anteriormente, iniciamos a criao de nosso banco de dados SQLite no SQLite Expert. Nessa
parte vamos enriquecer um pouco mais nosso sistema que por enquanto s tem uma tabela, TITULOS. Os atributos da
tabela podem ser vistos na Figura 1.
__________________________________________________________________________________________
26
__________________________________________________________________________________________
27
Agora, vamos fazer nossa primeira Query. Insira u FDQuery e d o nome a ela de qryTitulos. Insira em sua propriedade
SQL o seguinte cdigo SQL.
?
1
2
3
4
5
6
7
SELECT
ID_TITULO,
TITULO,
SUBTITULO,
ANO_LANCAMENTO
FROM
TITULOS
No entrarei em detalhes sobre instrues SQL, tomarei como verdade que todos tem o mnimo de noo sobre o SQL.
Estamos fazendo aqui uma simples seleo de dados, apenas trazendo os campos da tabela. Caso deseje, tambm
possvel clicar duas vezes no componente Query e abrir a janela de edio de SQL. Inclusive possvel fazer o teste de
retorno de dados para verificar se a instruo est correta.
Aps ter digitado a instruo, clique com o direito no componente e selecione Fields Editor e em seguida clique com o
direito e selecione Add all fields para adicionar todos os campos da tabela.
At aqui, se voc j conhece o mnimo de Delphi, no h novidades. Se preferir acesso campo a campo e modifique a
propriedade DisplayFormat inserindo nomes mais amigveis para cada campo da tabela.
fdcConexao.Params.Values['Database']...
fdcConexao.Connected := True;
__________________________________________________________________________________________
28
...
Perceba inclusive que inclumos no exemplo anterior, frmPrincipal, ou seja, tambm so aceitos formulrios.
Muito bem, estamos atualizando o parmetro DriverID com o nome do driver de nosso banco, ou seja, SQLite. Em
seguida atualizamos o parmetro com o nome caminho completo do banco. Ateno apenas para alguns detalhes.
Estamos usando Diretivas de Compilao para desviar o cdigo de acordo com a plataforma.
?1 {$IF DEFINED (IOS) || (ANDROID)}
Se for iOS ou (||) Android usamos TPath.Combine e TPath.GetDocumentsPath. Ambos os mtodos pertencem ao
namespace System.IOUtils, portanto declare essa unit na seo Interface da unit.
TPath.Combine: Responsvel por concatenar duas strings de endereo. Ele j faz o trabalho de descobrir, por exemplo,
qual barra utilizar, j que h diferena entre iOS, Android e Windows;
TPath.GetDocumentsPath: Descobre qual o endereo da pasta Documents no dispositivo mvel.
Sempre utilize esses dois mtodos para buscar e concatenar diretrios no Mobile.
Por fim de tudo, conectamos ao banco de dados usando um Connected := True;
Envolvemos tudo isso em um TryExcept para evitar que algum problema acontea sem que possamos notificar o
usurio.
DM.qryTitulos.Active := False;
DM.qryTitulos.Active := True;
Estamos fechando e abrindo novamente a tabela para forar um refresh. No esquea de fazer um Use Unit nesse
form, j que ele ainda no enxerga nosso Data Module.
Em outro momento faremos uma codificao para formar o DisposeOf dos formulrios no visveis em tela, evitando
que tenhamos memria desnecessria sendo desperdiada. Nesse momento transferiremos o cdigo de abertura das
queries para o Form Create de cada tela.
Antes de testar a aplicao, acesse o menu Project >> Options e em Form modifique a ordem de criao do frmMain e
do DM como mostrado na Figura 5.. Estamos ainda sem foto para os ttulos, que devero aparecer ao lado esquerdo
do TListView.
__________________________________________________________________________________________
29
Montaremos agora uma aba para mostrar os detalhes do nosso Ttulo. Para isso adicione uma nova aba ao TabCtrl de
Clientes clicando com o boto direito nele e em seguida em AddTabItem. Nessa TabItem, que chamaremos de
tbitemDetalhes, adicione um TListBox. Adicione somente duas linhas (Itens) nesse ListBox. O primeiro deles, altere a
altura para 105px. Adicione um TImage com o nome de imgFoto e alinhe-0 a esquerda modificando tambm suas
margens para 8px em todos os lados.
Ainda na primeira linha do ListBox, adicione um TLayout e dentro dele 2 (Labels). Eles sero nosso Ttulo e SubTtulo
respectivamente. Eles devem receber o Name e o Text como abaixo, assim como outras propriedades:
Label Ttulo
Name: lblTitulo
Text: lblTitulo
StyleLookup: listboxitemlabel
Align: Top
Margins.Right: 8
Margins.Top: 8
Label SubTitulo
Name: lblSubTitulo
Text: lblSubTitulo
StyleLookup: listboxitemdetaillabel
Align: Client
Margins.Bottom: 8
Margins.Right: 8
Margins.Top: 8
A segunda linha receber apenas e Text = Ano Lanamento.
O ListBox dever ficar com a propriedade Align igual a Client, mas antes de fazer isso adicione uma ToolBar. Dentro
dela adicione um SpeedButton e d o nome a ele de spbVoltar e o Text como Voltar. Modifique seu StyleLookup para
backtoolbutton e a propriedade Left do Margins para 8px. No evento OnClick desse button, apenas escreva:
?
1
tabctrlTitulos.Previous;
Esse boto ser responsvel por voltar a listagem de ttulos. Agora sim marque o ListBox como Client e vamos ver o
resultado. Nossa janela dever possuir uma aparncia semelhante a da Figura 6.
__________________________________________________________________________________________
30
Figura 7.
Tambm no queremos que as abas na parte inferior sejam mostradas para o usurio final, ento deixaremos elas na
tela apenas em tempo de projeto para nos ajudar a desenhar e fazer as devidas manutenes. Mas em runtime
sumiremos com elas assim como marcaremos como default a aba de Listagem. Entre no evento OnCreate desse form
e digite o cdigo a seguir:
?
1
2
tabctrlTitulos.TabPosition := TTabPosition.None;
tabctrlTitulos.ActiveTab
:= tbitemLisTitulos;
__________________________________________________________________________________________
31
Bem simples no? Estamos mudando a propriedade TabPosition para None, assim as abas no aparecero. E tambm
configuramos a ActiveTab como sendo a listagem. Retorne agora para a aba principal e selecione o evento OnItemClick
do TListView. Digite o cdigo para passar para a aba de Detalhes:
?
1
tabctrlTitulos.Next;
Um ltimo retoque. Se executarmos agora o aplicativo, veremos que no lugar de Ano Lanamento aparece apenas o
Ano, e o texto some. Ento clique duas vezes no componente BindinsList1 e em seguida selecione o link correspondente
ao Item de ListBox do Ano de Lanamento, provavelmente ser o ltimo. Pressione F11 para abrir o Object Inspector
e selecione o campo CustomFormat. Digite na propriedade o texto a seguir:
?
1
Isso far com que concatenemos a palavra Ano Lanamento com o valor gravado na tabela, ou seja, o ano
propriamente dito.
Perfeito, com isso finalizamos nossa tela de detalhes. Execute o aplicativo e veja como ficou. Observe no Vdeo 1 como
ficou nossas alteraes nessa terceira parte.
Concluses
Nessa terceira parte de nosso tutorial, vimos como implementar o uso de tabelas reais de um banco SQLite para
carregar informaes em um TListView. Vimos tambm como facilmente criar um Layout para mostrar os detalhes de
um item do ListView, nesse caso um Item selecionado pelo usurio final.
Na prxima etapa, veremos como fazer o primeiro CRUD (Funes de Incluso, Excluso e Alterao de Dados) no
banco de dados.
__________________________________________________________________________________________
32
1.
2.
3.
4.
5.
Chegamos a Parte IV de nosso Tutorial: Criando meu app step-by-step em RAD Studio XE7. No captulo anterior, mais
curto que os demais, aprendemos a montar nossa tela de Listagem de Ttulos conectada em dados reais atravs de um
banco de dados SQLite. Ns fizemos a navegao, vinculamos o banco ao projeto e deixamos tudo preparado para
iniciarmos a parte de Incluso, Excluso e Alterao de ttulos. Confira abaixo:
Criao do DataModule principal;
Configurao dos principais componentes de acesso ao banco de dados;
Criao dos mtodos de listagem de Titulos e Detalhes dos Titulos;
Montagem das telas funcionais.
Nessa nova etapa veremos como implementar o CRUD (Create, Read, Update e Delete, ou seja, Insero, Leitura,
Atualizao e Excluso) em nosso aplicativo. Vejamos a pauta:
Criao de campo do tipo imagem na tabela de Ttulos;
Criao de mtodo para auto-numerar ID de Ttulos;
Binding da imagem com as listagem e detalhes do Ttulo;
Incluso, Alterao e Excluso de Ttulos;
Seleo de fotos da biblioteca ou cmera;
Requisitos
Leitura: Tutorial: Criando meu app step-by-step parte III;
Assistir ao vdeo: TDevRocks Binding vs TListViews
1.
2.
3.
4.
Retomando o raciocnio
Nossa sesso Retomando o raciocnio de hoje tem a ver com o que fizemos at o presente momento. No captulo
anterior ns iniciamos, como dito anteriormente, com uma parte crucial: incluso de dados reais. Entretanto deixamos
para trs duas coisas:
1. Auto-numerao do ID de Ttulos;
2. Criao do campo Foto;
A foto ser usada para mostrar a capa do ttulo, DVD, em questo. Tanto no TListView quanto em detalhes. E no caso
do ID do ttulo, como vamos ter outros numeradores, vamos criar uma funo no DataModule que receba a tabela e o
nome do campo e devolvemos j um Integer com o ID, assim poderemos reutilizar a function em outras tabelas quando
necessrio.
Feito isso, teremos que alterar a instruo SQL que traz os campos. Por isso, retorne ao Delphi e acesse o DataModule
(DM) para que possamos modificar o componente qryTitulos. Selecione a propriedade SQL e clique duas vezes nela e
inclua o campo FOTO na instruo assim como na Listagem 1.
?
1
2
3
4
5
6
7
8
SELECT
ID_TITULO,
TITULO,
SUBTITULO,
ANO_LANCAMENTO,
FOTO
FROM
TITULOS
Binding de Fotos
H quem prefira salvar as fotos em uma pasta especfica. Tambm prefiro, mas depende muito do tipo de aplicao.
Nesse caso prefiro salvar direto no banco, j que seria mais chato fazer o binding com as fotos soltas no device. Esse
processo to simples quanto o que fizemos no captulo anterior.
Acesse a janela frmTitulos e em seguida acione o Bind Visually. Selecione o TListView correspondente a lista de ttulos
e observe que ele possui um item chamado Item.Bitmap em sua lista de campos na janela Binding. Ligue o campo FOTO
a esse item. Do mesmo modo, mude para a aba de Detalhes e ligue o campo FOTO a propriedade Bitmap do TImage
que colocamos para receber a foto.
#Dica: Caso no aparea a propriedade Bitmap em qualquer dos casos, clique nas reticncias do objeto que deseja
fazer a ligao do Binding, e localize a propriedade desejada na caixa de dilogo. Marque-a e ento ela aparecer no
bind.
Pronto! A primeira parte do binding est finalizada. O que precisamos fazer agora preparar a parte de codificao
para que possamos possibilitar mudar a foto do item na lista. Veja as ligaes dessa sesso na Figura 2.
__________________________________________________________________________________________
34
Errata da Parte II
Na Parte II ns fizemos a codificao para vincular nosso banco de dados em runtime no evento OnCreate do
DataModule, mas acabei publicando um erro na utilizao de diretivas de compilao que s notei com o incio dos
testes nesse captulo. No OnCreate utilizamos a seguinte linha:
?
1
2
3
[...]
{$IF DEFINED (IOS) || (ANDROID)}
[...]
[...]
{$IF DEFINED(IOS) OR DEFINED(ANDROID)}
[...]
Alguns leitores tambm reclamaram que ao passar pela linha Connected := True, o banco dados no abre e ainda indica
um erro na aplicao, que est relacionado a uma configurao no passada no captulo III. Clicando duas vezes do
componente FDConnection (fdConexao), repare que em nossas configuraes existe uma propriedade chamada
OpenMode que est setada como CreateUTF8. Troque-a para ReadWrite. Isso se faz necessrio, pois estamos
distribuindo o banco de dados SQLite e no criando-o em runtime.
Em outras palavras, j temos o banco de dados criado e faremos a distribuio dele quando fecharmos a aplicao para
a loja ou para nossos testes no device. Para que no fique totalmente confuso, observe a Listagem 2 que contm o
cdigo completo corrigido.
__________________________________________________________________________________________
35
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Connected := True;
except on E: Exception do
begin
ShowMessage(E.Message);
end;
end;
{$ELSE}
try
Params.Values['Database'] := 'CAMINHO_DO_BANCO_DE_DADOS\Database\Locadora.sqlite';
Connected := True;
except on E: Exception do
begin
ShowMessage(E.Message);
end;
end;
{$ENDIF}
end;
end;
Editando um registro
H inmeras maneiras de fazemos a edio dos dados em tela, portanto faremos a princpio na maneira mais simples
e objetiva possvel. V at a aba Detalhes do Ttulo e adicione trs novos speedbuttons. Eles faro o trabalho de Editar,
Salvar e Cancelar uma edio. Configure-os como a seguir:
Name: spbEditar
StyleLookup:
Align: Right
Margins.Right: 8px
Text: Editar
Visible: False
Name: spbSalvar
StyleLoockup: donetoolbutton
Align: Right
Margins.Right: 8px
Text: Salvar
Visible: False
Name: spbCancelar
StyleLookup: deletetoolbutton
Align: Left
Margins.Left: 8px
Text: Cancelar
Visible: False
Note que todos os nossos botes possuem a propriedade Visible segada como False. Isso porque vamos deixa-los como
visveis de acordo com a situao. Criaremos um mtodo para fazer esse trabalho. Por isso crie uma nova procedure
na seo Public do formulrio e codifique como na Listagem 3.
__________________________________________________________________________________________
36
?
1
2
3
4
5
6
7
procedure TfrmTitulos.AtualizarBotoes;
begin
spbVoltar.Visible
:= (DM.qryTitulos.State = dsBrowse);
spbEdicao.Visible
:= (DM.qryTitulos.State = dsBrowse);
spbCancelar.Visible := (DM.qryTitulos.State in dsEditModes);
spbSalvar.Visible
:= (DM.qryTitulos.State in dsEditModes);
end;
__________________________________________________________________________________________
37
Fiz o print das telas propositadamente com o cursor selecionado na opo Media Library. Essas so aes prontas do
Delphi. Na seqncia vemos:
TTakePhotoFromLibraryAction
TTakePhotoFromCameraAction
TShowShareSheetAction
As duas primeiras so usadas respectivamente para selecionar uma foto da Galeria (Android) ou Biblioteca (iOS) e a
segunda usada para tirar uma novo nova. A terceira opo usada para invocar a tela de compartilhamento nas
redes sociais, etc.
Adicione uma ao para Cmera e outra para Biblioteca. Chame-as de actFotoCamera e actFotoBiblioteca. Depois de
criadas ns podemos clicar na ao e acessar suas propriedades e eventos. O que precisamos aqui s do evento
OnDidFinishTaking, que ser codificado por ns. Clique duas vezes nesse evento para a ao actFotoCamera.
Esse evento ocorre logo depois da captura da foto, ou seja, aps o usurio tirar a foto e escolher usa-la. Ns
carregaremos a foto diretamente para o campo FOTO em nosso banco de dados. Para isso apenas digite no evento:
?
DM.qryTitulosFOTO.Assign(Image);
O parmetro Image vem do prprio evento e carregado automaticamente pelo Delphi aps a captura de foto. Essa
mesma linha pode ser digitada no mesmo evento para a segunda ao, faa isso.
Se voc escreveu os cdigo corretamente para cada boto como indicado mais acima, ento at aqui no teremos
problemas e tudo estar funcionando perfeitamente.
Retornaremos em breve aqui, pois teremos que codificar o momento certo de chamar esses mtodos.
Pressione Ctrl + Shift + C para que o Delphi crie o escopo no mtodo e ento digite o cdigo da Listagem 5. Perceba
que criamos uma constante chamada _SQL que recebe SELECT MAX(ROWID)+1 AS NEW_ID FROM %s. Isso bem
simples.
__________________________________________________________________________________________
38
RowID um campo oculto nas tabelas do SQLite que bastante comum em alguns bancos de dados, tal como Oracle.
Ele uma espcie de controle interno do banco de dados. O que faremos igualar o campo ID_TITULO de nossa tabela
ao valor desse campo. Usamos Max para pegar o maior valor nesse campo e adicionamos +1. O %s um coringa que
usaremos para substitui-lo pelo nome da tabela, ou seja, teremos uma instruo SQL assim:
?
1
__________________________________________________________________________________________
39
edtTitulo.Enabled
:= (DM.qryTitulos.State in dsEditModes);
edtSubTitulo.Enabled := (DM.qryTitulos.State in dsEditModes);
edtAno.Enabled
:= (DM.qryTitulos.State in dsEditModes);
if (DM.qryTitulos.State in
begin
edtTitulo.StyleLookup
edtSubTitulo.StyleLookup
edtAno.StyleLookup
end
else
begin
edtTitulo.StyleLookup
edtSubTitulo.StyleLookup
edtAno.StyleLookup
end;
dsEditModes) then
:= 'editstyle';
:= 'editstyle';
:= 'editstyle';
:= 'transparentedit';
:= 'transparentedit';
:= 'transparentedit';
__________________________________________________________________________________________
40
1
2
3
DM.qryTitulos.Append;
tabctrlTitulos.Next;
AtualizarBotoes;
No d para ser mais simples que isso. Append para criar um novo registro, mudamos para a aba de detalhes e
atualizamos os botes que consequentemente tambm ativar os edits para incluso de dados.
Ns preparamos nosso cdigo para ativarmos a cmera ou a biblioteca de fotos, mas no fizemos as devidas chamadas
ainda. Faremos o seguinte: quando o usurio tocar na foto na tela de detalhes, ento acionaremos um pop-up menu e
perguntaremos o que o usurio deseja fazer:
Nova Foto;
Biblioteca
Cancelar
Desse modo, cada item do pop-up chamar uma determinada ao. Para fazer esse menu usaremos um artifcio bem
comum, um ListBox. Isso mesmo! Insira um ListBox na tela e clique duas vezes nele para adicionar itens. Crie trs itens
e altere suas propriedades como a seguir:
Name: lstitNovaFoto
Text: Nova Foto
Name: lstitBiblioteca
Text: Biblioteca
Name: lstCancelar
Text: Cancelar
Eu modifiquei as fontes de cada item do listbox, mas fica a seu critrio. Tambm importante modificar a altura de
todos os itens, use a propriedade ItemHeight do prprio ListBox e altere-a para 40 que um bom nmero. A aparncia
desse listbox deve ser parecida como a Figura 8.
__________________________________________________________________________________________
41
Perfeito! Agora temos que preparar a logstica para que tudo isso funcione. Ns faremos o menu aparecer de cima
para baixo com uma animao, e desaparecer do mesmo modo. Para que possamos sumir com o menu quando o
usurio tocar fora, usaremos nossa antiga tcnica de criar um retngulo escuro por baixo de tudo. Ns vimos isso no
primeiro tutorial. Voltaremos com a ideia.
V at o formulrio principal, frmMain, e adicione um TRectangle de qualquer tamanho e modifique sua propriedade
Opacity para 0.5. Na seo Public do form, crie dois mtodos:
?
1
2
procedure TfrmMain.HideBackground;
begin
recBackground.AnimateFloat('opacity', 0, 0.1);
recBackground.Visible := False;
end;
procedure TfrmMain.ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent);
begin
recBackground.OnClick := AOnClick;
recBackground.Parent := AParent;
recBackground.BringToFront;
recBackground.Opacity := 0;
recBackground.Visible := True;
recBackground.AnimateFloat('opacity', 0.5, 0.1);
end;
frmMain.HideBackground;
lstPopUpFoto.AnimateFloat('position.y', lstPopUpFoto.Height * -1);
lstPopUpFoto.Visible := False;
Simples no? Chamamos o mtodo HideBackground presente no formulrio principal e depois as animaes para
esconder o menu. Por default o menu deve ficar invisvel e longe do alcance dos olhos, portanto no OnCreate do
formulrio de ttulos adicione o cdigo da Listagem 8.
?
1
2
3
4
5
6
lstPopUpFoto.Width
lstPopUpFoto.Position.X
lstPopUpFoto.Position.Y
lstPopUpFoto.Visible
:=
:=
:=
:=
ClientWidth - 20;
(ClientWidth - lstPopUpFoto.Width) / 2;
lstPopUpFoto.Height * -1;
False;
AtualizarBotoes;
__________________________________________________________________________________________
42
9
10
end;
end;
HidePopup;
actFotoCamera.ExecuteTarget(Sender);
HidePopup;
actBiblioteca.ExecuteTarget(Sender);
E caso o usurio queira desistir de tirar foto, apenas chame HidePopup e HideBackground para sumir com o popup de
tela.
?
1
2
HidePopup;
frmMain.HideBackground;
Excluindo registros
Para fecharmos com chave de ouro, precisaremos fazer a excluso de registros e o PullToRefresh, ou seja, puxe para
atualizar. Usaremos gestos para isso, mas os defaults. Quando o usurio arrastar o dedo para os lados, um boto Delete
dever aparecer. Se puxar de cima para baixo, ento atualizamos a tabela. Isso tudo no ListView.
Bem, o PullToRefresh j est pronto. Apenas ative a propriedade PullToRefresh e ento codifique o evento
OnPullToRefresh. Digite apenas:
?
1
2
DM.qryTitulos.Active := False;
DM.qryTitulos.Active := True;
Como isso encerramos a quarta parte de nosso tutorial. Ainda ser disponibilizado um vdeo com mais alguns detalhes.
Ento fiquem de olho, pois esse post sofrer algumas modificaes.
Concluso
Nesse tutorial vimos muitas das operaes triviais de qualquer aplicativo. Mas tambm vimos tcnicas simples, porm
eficazes para criar um pop-up de menu, muito utilizado em aplicaes mveis. Vimos tambm a utilizao de aes
padres e o uso de contedo do aparelho, como fotos.
__________________________________________________________________________________________
44
Bem vindos a parte V de nosso Tutorial: Criando meu app step-by-step a partir do desenvolvimento em RAD Studio XE7.
At agora entendemos uma srie de mecanismos que nos ajuda a desenvolver de forma mais rpida e intuitiva, criando
nossas telas, capturando fotos, ligando controles a campos do banco de dados, etc.
Relembrando da seo passada, ns vimos:
Criao de campo do tipo imagem na tabela de Ttulos;
Criao de mtodo para auto-numerar ID de Ttulos;
Binding da imagem com as listagem e detalhes do Ttulo;
Incluso, Alterao e Excluso de Ttulos;
Seleo de fotos da biblioteca ou cmera;
Essa seo ser um pouco mais light. Entenderemos como aplicar um estilo mais profissional ao aplicativo, instalao
e configurao do cliente Git para clone de nosso fonte do Bitbucket. E tambm criaremos uma janela de configurao
para guardar preferncias do usurio. Segue a lista:
Instalao e configurao do Git no Delphi XE7;
Como aplicar estilos mais profissionais?
Criando uma janela de preferncias;
Criao de classe para guardar informaes de preferncias.
Requisitos:
Leitura: Tutorial: Criando meu app step-by-step parte IV;
1.
2.
3.
4.
5.
__________________________________________________________________________________________
45
Eu costumo copiar os estilos na pasta de Styles do Delphi, mas na verdade voc pode colar onde voc desejar. Nesse
artigo
veremos
onde
podemos
instalar
tais
temas.
Acesse
a
pasta C:\Users\Public\Documents\Embarcadero\Studio\15.0\Styles. Nessa pasta voc tambm encontra os arquivos
separados por plataforma, ento agora fica fcil. Basta deixar dois explorers lado a lado e copiar e colar cada tema em
sua respectiva pasta.
Agora que temos os temas devidamente instalados, basta que faamos a adio no nosso projeto. Para isso abra o
Delphi XE7 e em seguida nosso projeto. No form principal, frmMain, adicione um componente do
tipo TStyleBook. Localize-o digitando seu nome da caixa de pesquisa na paleta de componentes.
Agora selecione a plataforma Android sua direita no Project Manager. Isso necessrio pois voc pode adicionar um
estilo para cada plataforma se desejar. Selecionada a plataforma, clique duas vezes no componente StyleBook1 criado
anteriormente. Voc ver alguns botes na parte superior, um deles o Load, para carregarmos o estilo que
desejamos. Clique nesse boto e localize o arquivo AndroidEmeraldDark.style naquela mesma pasta onde colocamos
os temas. Em seguida clique em Apply & Close. Selecione agora o formulrio em si e em sua
propriedade StyleBook selecione o componente de mesmo nome, isso far com que o tema seja aplicado
imediatamente, como podemos ver na Figura 2.
Adicione um novo boto alinhado direita com margem direita de 8px. O seu Text dever ser Gravar e o
name spbGravar. Esse boto ser nosso boto para gravao das preferncias em arquivo INI. A tela dever se parecer
com a Figura 3.
__________________________________________________________________________________________
46
Adicione um Item de cabealho e em seguida um item comum. O primeiro deles d o nome de lstgrpSeguranca e
seu Text mude para Segurana. Em seguida modifique o name do segundo item para lstitDesconectar e seu Text para
Desconectar ao sair. Adicione dentro desse item de ListBox um componente TSwitch e d o nome a ele
de swtDesconectar. Alinhe-o a direita com margem direita igual a 8px.
interface
uses
IniFiles, System.IOUtils
Em seguida escreva o cabealho das funes e propriedades que vamos codificar aqui. Veja a Listagem 1 como o cdigo
precisa ser implementado.
?
1
2
3
type
Lib = class
private
__________________________________________________________________________________________
47
4
5
6
7
8
9
10
11
12
13
FDesconectarAoSair: Boolean;
function GetDesconectarAoSair: Boolean;
procedure SetDesconectarAoSair(const Value: Boolean);
public
procedure SaveConfig;
procedure ReadConfig;
published
property DesconectarAoSair: Boolean read GetDesconectarAoSair write SetDesconectarAoSa
end;
Ns criamos uma propriedade chamada DesconectarAoSair do tipo Boolean (True/False) e guardarmos a informao
se o usurio deseja ou no sair totalmente do sistema ao sair do aplicativo. Em seguida criamos dois mtodos:
SaveConfig: Salvar os dados no arquivo INI;
ReadConfig: Ler dados do arquivo INI;
Pressione Ctrl +Shift + C para que o Delphi crie para ns o escopo dos mtodos. Ns faremos algo bem simples j que
temos apenas uma configurao para ser guardada no arquivo INI. Digite o cdigo da Listagem 2.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
finally
Ini.DisposeOf;
end;
end;
procedure Lib.SaveConfig;
var
Ini : TIniFile;
begin
try
Ini := TIniFile.Create(TPath.Combine(TPath.GetDocumentsPath, 'Config.ini'));
Ini.WriteBool('SEGURANCA', 'DesconectarAoSair', FDesconectarAoSair);
finally
Ini.DisposeOf;
end;
end;
procedure Lib.SetDesconectarAoSair(const Value: Boolean);
begin
FDesconectarAoSair := Value;
end;
__________________________________________________________________________________________
48
?
1
2
3
4
5
6
7
8
9
[...]
uses
ULib,
UntPreferencias;
[...]
public
FPreferencias : TfrmPreferencias;
FLib
: TLib;
[...]
Acesse o evento OnCreate do form principal e faa a criao da instncia de FLib, como abaixo:
?
1
2
FLib := TLib.Create;
FLib.ReadConfig;
J no evento OnClose, precisamos dispensar a varivel para evitar MemoryLeak. Faa como abaixo:
?
1
2
if Assigned(FLib) then
FLib.DisposeOf;
Agora falta apenas, nesse formulrio, fazer a chamada para o form de preferncias. Clique duas vezes no item de
listbox referente ao menu preferncias e codifique-o como na Listagem 3.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Cadastro de Preferncias
Como nossa janela de preferncias s possui um item para ser gravado, ento vai ser fcil codificarmos. Precisamos
gravar o que o usurio escolheu e na abertura da tela precisamos ler o que foi gravado e atualizar a tela. Publiquei
na Listagem 4 o cdigo completo dos dois eventos, OnCreate e OnClick (spbGravar).
?
1
2
3
4
5
6
7
8
9
10
11
__________________________________________________________________________________________
49
Seleo do Git
__________________________________________________________________________________________
50
Endereo remoto
Download
Finalizao
Quando o download finalizar, o Delphi detectar se h algum arquivo .dpr, .dproj e etc e j far a sugesto de abertura
do arquivo. Voc pode cancelar nesse momento se desejar.
O cdigo-fonte desse exemplo encontra-se disponvel aqui.
Concluses
Nesse artigo pudemos aprender como fcil adicionar um novo estilo as nossas aplicaes Delphi para Mobile, bem
como para desktop Windows e Mac. O aprendizado aqui serve no somente para aplicativos multi-device, mas caso
voc deseje adicionar um estilo profissional a sua aplicao, os passos tambm so vlidos.
Tambm aprendemos a usar arquivos INI para ler e gravar informaes nos diretrios do dispositivo mvel. Por fim,
aprendemos a configurar o Git para efetuar o clone de nosso projeto no Bitbucket. Os passos vistos aqui, tambm so
vlidos para qualquer outro cdigo-fonte disponvel na nuvem ou localmente.
__________________________________________________________________________________________
51
Criando meu app step-by-step tem se tornado uma referncia a muitos seguidores do blog, e ns agradecemos muito
;). Mas at o presente momento, estamos vendo coisas bsicas no Delphi ento hora de avanarmos um pouco mais.
Nessa sexta parte, iniciaremos a criao de um servidor de aplicativos desenvolvido com DataSnap REST, passando pelo
conceito de Reflection no FireDAC no futuro, bem como o uso de objetos JSON para troca de DataSets entre cliente e
servidor. Calma, calma! Para os iniciantes, tanto no Delphiquanto no DataSnap, isso pode parecer uma Hidra de Lerna,
vulgarmente chamada de Bicho de Sete Cabeas. Mas no, ser fcil.
No artigo anterior, ns aprendemos a criar uma janela de configuraes utilizando arquivos INI para persistir as
preferncias do usurio, alm de outras coisas. Confira:
Instalao e configurao do Git no Delphi XE7;
Como aplicar estilos mais profissionais?
Criando uma janela de preferncias;
Criao de classe para guardar informaes de preferncias.
Nesta sexta parte, veremos como criar nosso servidor DataSnap e como configurar nossa aplicao cliente para ler
nossos ServerMethods.
Criao do servidor DataSnap;
Criao do mdulo de conexo com o servidor DataSnap;
Teste de conexo.
Requisitos:
Leitura: Leitura do artigo Parte V;
Vdeo: Assistir ao vdeo complementar em nosso canal no YouTube;
__________________________________________________________________________________________
52
Criando o servidor
Com o RAD Studio XE7 aberto e nosso projeto tambm j aberto na IDE, vamos adicionar um novo projeto clicando
com o boto direito em ProjectGroup1 no Project Manager a nossa direita (Figura 2). Selecione Add New Project.
Entendendo o Servidor
Depois de clicar em Finish, o Delphi cria para ns todos os arquivos necessrios e as respectivas configuraes para
que o servidor funcione corretamente em modo Stand-alone, ou seja, em modo executvel. Voc perceber que temos
trs arquivos abertos:
FormUnit1: Formulrio principal do servidor;
ServerMethodsUnit1: Servidor de Mtodos;
WebMobuleUnit1: Principal unit do servidor, possui os componentes que mantm o servidor no ar, tal como DSServer.
O primeiro formulrio da lista, salve-o como UntMainServer.pas e d o nome (Propriedade Name) a ele
de frmMainServer. Em seguida salve o segundo formulrio como UntServerMetodos.pas e d o Name
de SrvServerMetodos. Por fim salve o WebModuleUnit1 como UntWebModulo.pas e troque seu Name
para webModulo.
Aproveitando que estamos no webModulo, vamos analisar esse formulrio. O primeiro componente importante desse
formulrio o DSServer1. ele que recebe todas as requisies de aplicaes cliente, sejam elas mobile, sejam elas
desktop Windows ou Mac.
Em seguida ns temos um DSServerClass1. Esse componente responsvel por exportar as classe e consequentemente
os mtodos do servidor para o cliente. Podemos ter quantos componentes desse quisermos. Clique nesse componente
e acesse seu evento OnGetClass.Teremos seguinte cdigo:
?
1
2
3
4
5
procedure TwebModulo.DSServerClass1GetClass(
DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
PersistentClass := UntServerMetodos.TSrvServerMetodos;
end;
__________________________________________________________________________________________
53
Para sermos bem simplistas, estamos exportando a Unit ServerMetodos inteira para o cliente, o que significa que tudo
que estiver programado l dentro, ser exportado e poder ser acessado, como por exemplo nossos mtodos de acesso
a banco de dados.
Acesse agora a folha de cdigo do ServerMetodos e localize a parte superior da unit onde encontramos os
mtodos ReverseString e EchoString. Esses dois mtodos podero ser acessados por nossos aplicativos mveis, bem
como outros mtodos que venhamos a codificar nessa rea.
Para finalizar tudo, salve agora o projeto como DataSnapServer. Utilize a opo File > Save Project As. Em seguida
compile e execute nosso servidor utilizando Shift+Ctrl+F9 para rodar fora do modo Debug. Voc ver que basta clicar
no boto Start para que ele entre em ao e passe a escutar nossas requisies.
Aplicao Cliente
Agora aprenderemos apenas como fazer a configurao e conexo com nosso servidor de aplicativos DataSnap.
Mantenha o servidor aberto para que possamos fazer as configuraes.
#Dica: Clique com o boto direito do mouse em ProjectGroup1 no Project Manager e em seguida selecione Save Project
Group As para salvar o grupo de projetos.
Clique duas vezes em nosso projeto LodadoraDelphi.exe para que possamos selecionar o projeto Mobile. Ns
precisaremos incluir uma nova Unit nesse projeto utilizando o menu File > New > Other > DataSnap Server e logo em
seguida selecione o item DataSnap RESTClient Module (Figura 3).
Na primeira tela apenas escolha apenas Local server e avance. A tela seguinte que nos interessa. Nela escolhemos qual
o tipo de projeto servidor queremos conectar. Com base em nossa escolha, o Delphi criar a Unit e os componentes
necessrios para acesso ao servidor de dados. Nesse caso temos as opes:
DataSnap stand alone server: Servidor DataSnap stand-alone, nossa escolha;
WebBroker and stand alone server: Servidores Web;
IIS Module: Esse tipo de servidor funciona atravs do IIS no Windows, Internet Information Services;
Apache module: Podemos ter nosso servidor DataSnap rodando sob plataforma Apache;
Do not know: Desconhecido. Exige maior conhecimento das rotinas do servidor.
Escolheremos ento, como mencionado, a primeira opo DataSnap stand alone server. Na tela seguinte, e ltima, ns
podemos testar nossa conexo bem como modificar ou apenas informar a porta correta para conexo.
Depois de finalizado, ns teremos uma nova Unit que salvaremos como UntModuloCliente. E d o nome a ele de
ModuloCliente. Ns podemos ter quantos mdulos cliente quisermos. Perceba que um nico componente foi includo
nesse formulrio. Esse componente, do tipo DSRestConnection, o responsvel por conectar-se com nosso servidor
de aplicaes. Clicando nele e observando suas propriedades, perceba que podemos a qualquer momento alterar a
porta de conexo na propriedade Port.
Caso voc deseje testar se a conexo funciona, basta clicar com o boto direito do mouse no DSRestConnection e
selecionar Test Connection. Ainda com o boto direito, clique em Generate DataSnap client classes. Esse principal
__________________________________________________________________________________________
54
segredo do DataSnap. Clicando nessa opo, uma nova Unit ser gerada. Chamaremos essa Unit de Proxy, pois o que
ela faz. Esse proxy tem o objetivo de nos linkar com os mtodos do servidor. atravs dele que recebemos e
enviamos parmetros, datasets, etc entre cliente e servidor de aplicativos. Salve essa Unit com o nome que desejar,
mas eu prefiro cham-la simplesmente de Proxy.pas.
#Dica1: Sempre que uma nova funo for criada, excluda, tiver seus parmetros modificados ou ainda possuir novas
classes para serem exportadas/importadas, utilize o boto direito do mouse e a opo Generate DataSnap client
classes.
#Dica2: Na dica acima, apenas no se esquea que o servidor precisa estar aberto e iniciado.
#Dica3: A Unit Proxy.pas NUNCA deve ser alterada manualmente. No necessrio.
Figuras 4 e 5.
__________________________________________________________________________________________
55
?
1
2
uses
System.SysUtils, System.Classes, Proxy, IPPeerClient, Datasnap.DSClientRest;
Perceba como o cdigo simples. Abra a unit ModuloCliente e note que h uma propriedade chamada
SrvServerMetodosClient, que nada mais que uma referncia a nossa classe TSrvServerMetodos no lado servidor.
Atravs dessa propriedade conseguimos acesso ao mtodo ReverseString. Passamos para ela o valor digitado no Edit1
e recebemos do servidor a String invertida que substitui o contedo do prprio Edit.
Esses so os passos e conceitos padres para acesso ao servidor. No prximo tutorial, faremos a exportao de
um TFDJSONDataSet do servidor para o cliente e com ele alimentaremos uma tabela temporria do lado cliente.
Para no avanarmos demais nessa sexta parte, finalizaremos aqui e continuaremos nosso desenvolvimento na parte
VII.
Concluses
O uso de DataSnap uma mo a roda para quem deseja separar sua aplicao em camadas. Aqui vimos que
perfeitamente possvel efetuar chamadas ao servidor de aplicativos utilizando a porta 8080 e ler o retorno do servidor
em aplicaes mobile.Nossa aplicao est preparada para funcionar tambm em Desktop Windows ou Mac apenas
adicionando essas plataformas em nosso Project Manager, o que nos d tranquilidade para migrar nossa app para n
plataformas. At a prxima!
__________________________________________________________________________________________
56
Reflection, novo conceito de desenvolvimento de servidores DataSnap com RAD Studio XE e FireDAC. Mencionei isso
no post passado referente ao Tutorial: Criando meu app step-by-step DataSnap Parte VI quando disse que iramos
avanar um pouco mais em nosso tutorial. Pois bem, chegou a hora. Nessa stima parte de nossa sequncia, veremos
como exportar um DataSnap do servidor para o cliente em formato FDJSONDataSet, nova classe no RAD Studio XE.
Tambm vimos a criao do nosso banco de dados Firebird 2.5 em nossa vdeo-aula complementar no YouTube nos
preparando j para fazer o sincronismo entre servidor e cliente. Vejamos o que foi dito na verso anterior desse post.
Criao do servidor DataSnap;
Criao do mdulo de conexo com o servidor DataSnap;
Teste de conexo.
Nessa stima parte, faremos a exportao da primeira tabela do banco no lado servidor, bem como seu uso no lado
cliente. Veja:
Criao da tabela do banco de dados no Firebird;
Criao dos mtodos de exportao de Ttulos no lado servidor;
Leitura e atualizao da tabela Ttulos local no dispositivo mvel;
Requisitos:
Leitura: Leitura do artigo parte VI;
Vdeo: Assistir ao vdeo complementar da parte VI;
__________________________________________________________________________________________
57
Para isso faremos agora as configuraes necessrias para acessar o servidor de banco de dados Firebird usando o
componente FDConnection. Abra o servidor DataSnap criado no artigo anterior e encontrei nosso ServerMethod que
tem o nome UntServerMetodos. nele que colocaremos nossas tabelas e conexes com o Firebird.
claro que o mais certo seria isolarmos os nossos Queries de demais componentes de acesso, como o FDConnection,
mas para nosso exemplo, no precisaremos dessa abordagem. Apenas insira um FDConnection no ServerMethod e d
o nome de FDConexao a ele. Em seguida clique duas vezes no componente para configurarmos suas propriedades de
acesso.
Na parte superior da janela, selecione o combo referente ao Driver ID e escolha FB. Feito isso, o Delphi modificar os
parmetros na parte de baixo para que sejamos capazes de configurar os dados de acesso. Em DataBase configure
incluindo o endereo completo do arquivo de banco de dados, em nosso caso LOCADORASERVER.FDB. E seguida
configure seu usurio e senha, SYSDBA e masterkey, respectivamente. Em Protolo, marque TCPIP. Clique em Test para
verificar se est tudo ok com a conexo. No nosso caso, estamos usando o Firebird 2.5, conforme demonstrado em
vdeo-aula. Observer a Figura 2 as configuraes bsicas.
Bem simples, no? Exato, no queremos complicar nada nesse momento, apenas aprender a exportar o DataSet. Certo,
agora vamos fazer a function de retorno dessa tabela. Pressione F12 para ver o cdigo-fonte e procure a seo Public.
Declare a nossa function como na linha a seguir:
?
Perceba que estamos usando a classe TFDJSONDataSets como retorno da funo. Agora, precisamos pressionar CTRL
+ SHIFT + C para que o Delphi crie o escopo de nosso mtodo. Escreveremos o cdigo da Listagem 1.
?
1
2
__________________________________________________________________________________________
58
3
4
5
6
7
8
__________________________________________________________________________________________
59
Preparando o Sincronismo
Nessa ltima parte desse artigo, avanaremos pouco, pois desejo detalhar mais a tela de sincronismo na parte VIII, que
ficar bastante grande. Faremos apenas o entendimento do que ser feito acrescido de um pouco de cdigo.
Retorne at a tela principal do sistema com o nome de frmMain. No captulo anterior, ns deixamos um item de ListBox
a mais para testarmos a conexo com o servidor. Quero apenas que apague o Label e o TEdit inserido e deixe o boto.
No cdigo do boto, quero que insira o cdigo da Listagem 2.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
__________________________________________________________________________________________
60
Somente isso j fazia com que a aplicao parasse e aguardasse o usurio pressionar em Yes ou No, mas agora
diferente. Precisamos fazer um algo mais. Aps o ltimo parmetro, o HelpContext, passamos um mtodo annimo
para a MessageDlg, ou seja, criamos um PROCEDURE no ltimo parmetro, veja:
?
1
2
3
4
5
6
7
8
Dessa forma, quando o Yes for detectado, o cdigo que ser executado o nosso procedure (const AResult:
TModalResult) []. Entraremos em mais detalhes em outros tutoriais. Apenas entenda a nova sintax.
Retomando o raciocnio
Em nosso mtodo annimo ns no temos muita codificao, repare. So apenas 4 (quatro) linhas, o resto
so comentrios. Pois bem, a primeira coisa que fazemos receber na varivel LDataSetList a lista de DataSets recebida
do servidor com o uso do mtodo GetTitulos. Nesse caso estamos recebendo apenas UM DataSet. Depois de fazer isso,
ns fechamos o MemoryTable. Adicionei um FDMemoryTablena janela, pois receberemos o contedo da Query do
Servidor e adicionaremos dentro do MemoryTable no cliente, assim podemos fazer qualquer coisa com ele depois.
A prxima linha apenas um teste para nos certificarmos de que realmente a lista de DataSets possui ao menos um
DataSet. Fazemos isso usando um Assert.
Por fim, usamos o mtodo AppendData do MemoryTable para adicionar TODO o contedo do DataSet TITULO ao
MemoryTable. O AppendData j deixa o MemoryTable aberto, ou seja, nesse momento precisamos apenas montar um
LOOP para incluir esse dados em um banco de dados local. Bingo, nosso SQLite.
Na parte VIII de nosso Tutorial: Criando meu app step-by-step, faremos uso de ArrayDML para inserir rapidamente os
dados no nosso SQLite.
Concluses
Nessa stima parte de nosso tutorial, avanamos para o uso de Reflection do FireDAC como uma forma mais eficaz e
veloz de trazer informaes do servidor DataSnap para o cliente. Criamos nossa tabela do Firebird e j estamos prontos
para efetuarmos o sincronismo de dados.
O leitor Eduardo Belo fez um comentrio pertinente a um ponto de nosso tutorial. Assim como mencionado no vdeo
complementardesse post no YouTube, estamos utilizando a dll gds32.dll que refere-se ao Interbase, banco de dados
da Embarcadero. Entretando, na realidade nesse post usei o modo de retrocompatibilidade no momento da instalao
do Firebird 2.5. Isso faz com que o instalador renomeie a fdclient.dll para gds32.dll nos diretrios de sistema do
Windows.
Vale lembrar que o Firebird, para conhecimento dos leigos, derivado do Interbase, mas em um passado bastante
remoto. Para quem no sabe, o Interbase at sua verso 6.0 era gratuito e de cdigo-fonte aberto. Alguns
desenvolvedores russos copiaram o fonte e criaram o Firebird, que aos poucos foi se distanciando em termos de
funcionalidades em comparao ao Interbase. Hoje, so bastante diferentes.
__________________________________________________________________________________________
61
Estamos entrando na reta final de nosso Tutorial: Criando meu app step-by-step, e na parte VII iniciamos uma das
partes cruciais de nosso curso: O Sincronismo. Vimos como usar a classe TFDJSONDataSets para exportar dados do
servidor DataSnap para nosso aplicativo Mobile. Mas no vimos como fazer com que os dados recebidos sejam
inseridos no banco de dados local SQLite, veremos ento como utilizar comandos ArrayDML para fazer rapidamente
essas incluses.
Na parte VII ento vimos os seguintes tpicos:
Criao da tabela do banco de dados no Firebird;
Criao dos mtodos de exportao de Ttulos no lado servidor;
Leitura e atualizao da tabela Ttulos local no dispositivo mvel;
Como mencionado, veremos aqui os seguintes recursos:
Comandos ArrayDML para rpida insero no banco;
Ajustes na liberao de memria de objetos FORM;
Requisitos:
Leitura: Tutorial: Criando meu app step-by-step Parte VII
Note que vemos uma estrutura bsica usando os quatro componentes base do DBExpress (existem milhares de outras
estruturas de componentes) onde normalmente nossas telas, a parte visual do sistema, se conecta
ao ClientDataSet1 que poderia ser por exemplo uma janela de clientes. O ClientDataSet Auxiliar (cdsAuxiliar) seria
usado para rodar um loop em dados temporrio fazendo a incluso em ClientDataSet1, algo como a Listagem 1.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TForm1.Importar;
begin
DataModule.cdsAuxiliar.First;
while not DataModule.cdsAuxiliar.EOF do
begin
DataModule.ClientDataSet1.Append;
DataModule.ClientDataSet1.FieldByName('CAMPO1').AsString := DataModule.cdsAuxiliar.FieldByName('CAMPO1').AsString;
DataModule.ClientDataSet1.FieldByName('CAMPO2').AsString := DataModule.cdsAuxiliar.FieldByName('CAMPO3').AsString;
DataModule.ClientDataSet1.FieldByName('CAMPO3').AsString := DataModule.cdsAuxiliar.FieldByName('CAMPO3').AsString;
DataModule.ClientDataSet1.Post;
DataModule.cdsAuxiliar.Next;
end;
DataModule.ClientDataSet1.ApplyUpdates(-1);
end;
__________________________________________________________________________________________
62
Entendendo o conceito
A estratgia de uso do FireDAC com ArrayDML para importao de dados ou simplesmente para qualquer insero de
dados direto no banco bem simples e de rpido entendimento. Vejamos.
No FireDAC, mais precisamente no FDQuery, temos o comando Execute assim como outros DataSets, mas nesse caso
podemos passar um nmero de inseres a ele e fazer o preenchimento de todos os parmetros da query de uma s
vez. Em nosso exemplo anterior, na parte VII de nosso tutorial, iniciamos a sincronizao usando o algoritmo
da Listagem 2.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Receberemos nesse mtodo a tabela que contm os dados a serem importados, ou seja, nosso memTemporario.
Pressione Ctrl + Shift + C para que o Delphi crie o escopo de nosso mtodo e vamos a codificao. Digite o cdigo
da Listagem 3.
?
1
2
3
__________________________________________________________________________________________
63
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
' +
' +
' +
' +
' +
' +
' +
' +
' +
' +
' +
' +
' +
' +
' +
';
var
intNumInserts : Integer;
begin
{Nmero de registros recebidos do servidor}
intNumInserts := AMemoryTable.RecordCount;
DM.qryAuxiliar1.Active
:= False;
DM.qryAuxiliar1.SQL.Text := _INSERT;
{Informamos a Query Auxliar qual o nmero de Inserts ser efetuado}
DM.qryAuxiliar1.Params.ArraySize := intNumInserts;
AMemoryTable.First;
while not AMemoryTable.Eof do
begin
DM.qryAuxiliar1.ParamByName('ID_TITULO').AsIntegers[AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('ID_TITULO').AsInteger;
DM.qryAuxiliar1.ParamByName('TITULO')
.AsStrings [AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('TITULO')
.AsString;
DM.qryAuxiliar1.ParamByName('SUBTITULO').AsStrings [AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('SUBTITULO').AsString;
DM.qryAuxiliar1.ParamByName('FOTO')
.AsBlobs
[AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('FOTO')
.AsVariant;
DM.qryAuxiliar1.ParamByName('MINIATURA').AsBlobs
[AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('MINIATURA').AsVariant;
AMemoryTable.Next;
end;
{Se houver mais de um registro a ser aplicado, ento chama o Execute da Quuery Auxiliar}
if intNumInserts > 0 then
DM.qryAuxiliar1.Execute(intNumInserts, 0);
DM.qryAuxiliar1.Active := False;
end;
DM.qryAuxiliar1.ParamByName('ID_TITULO').AsIntegers[AMemoryTable.RecNo-1] :=
Nos colchetes passamos o RecNo -1 (o array comea em 0 (zero)) do registro da MemoryTable no momento de cada
interao do Loop. E recebemos o valore referente ao campo da tabela em questo.
Aps terminar o loop, ns precisamos apenas executar a query usando o mtodo Execute do qryAuxiliar1. O primeiro
parmetro serve para indicarmos quantas vezes ser executado o comando, nesse caso o nmero de registros
presentes no MemoryTable. O segundo parmetro deixamos em 0 (zero) pois indica ao query que iremos comear as
inseres a partir do primeiro registro.
__________________________________________________________________________________________
64
Por fim apenas fechamos a tabela. Esse mecanismo pode ser usado para basicamente qualquer insero em lote que
voc precise efetuar em seus sistemas.
A ltima providncia que devemos tomar retornar ao evento do boto Sincronizar e adiciona a linha abaixo para fazer
a chamada ao mtodo AtualizarTitulos.
?
1
2
3
Otimizando Memria
Vamos voltar no tempo at a primeira parte de nosso tutorial. Ns criamos um mtodo
no frmMain chamado ShowForm que recebe um TFmxObject como parmetro. Esse mtodo responsvel por abrir
os formulrios de nosso aplicativo mvel. Recordemos o cdigo:
?
1
2
3
4
5
6
7
8
Pegando como exemplo o item de menu Titulos, vemos que estamos fazendo um primeiro teste para verificar se existe
instncia do formulrio de ttulos e o criamos usando um Create(Self). A liberao de memria desse formulrio,
definitiva, fazemos no OnClose do formulrio principal.
?
1
2
if Assigned(FTitulos) then
FTitulos.DisposeOf;
At aqui nenhum problema e nenhuma novidade. Iniciantes e usurios Avanados do Delphi iro concordar que no
h nada de novo. Mas precisamos pensar na hiptese iminente de termos mais formulrios. Quando isso acontecer,
no podemos deixar nossos forms sempre ativos na memria, pois como mencionado anteriormente, poderemos
receber mensagens de erros e um grande problema com MemoryLeaks. Resolvi esse problema de forma at simples,
embora trabalhosa.
#Dica: MemoryLeaks, para os leigos, o estouro de memria na aplicao, ou seja, objetos no liberados de memria.
Vamos l. No mesmo evento ShowForm criaremos uma lista de objetos a serem destrudos e ento os liberaremos de
memria. Para comearmos essa rotina, primeiro precisamos de um novo formulrio. Pegando a ideia inicial de nosso
app, vamos criar um novo formulrio chamado frmUsuarios. Clique em File > New > Multi-Device Form Delphi. Use HD
Form como template. Modifique a propriedade Name para frmUsuarios e salve a unit como UntUsuarios. No faremos
nada com o formulrio agora. Apenas o usaremos como parte de nossa rotina para testes em nossa verso 2
de ShowForm.
Lembre-se de retirar a varivel com o nome do formulrio na rea Interface do form. Localize a instruo no cdigofonte e apague-a.
?
1
2
var
frmUsuarios: TfrmUsuarios;
__________________________________________________________________________________________
65
Retorne ao formulrio principal e adicione o novo form a seo Interface usando File > Use Unit. Crie uma nova varivel
em Private com o nome FUsuarios do tipo TfrmUsuarios. No evento OnClick do segundo item de menu, digite o cdigo
da Listagem 5:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Repare que fizemos modificaes significativas. Criamos duas variveis para receber o nome do formulrio e outra para
gerenciar os objetos que sero destrudos. Basicamente o que faremos detectar quando trocamos de um formulrio
para outro e destrumos o formulrio anterior, exemplo:
Quando o usurio acessar o menu Usurios / Clientes, criaremos o formulrio na memria.
__________________________________________________________________________________________
66
FListaForms.DisposeOf;
Com todas essas verificaes e cuidados, conseguimos manter um app mais fluido e confivel.
Concluses
Fizemos basicamente duas grandes modificaes nesse tutorial. Aprendemos a aproveitar o contedo recebido do
servidor DataSnap e inclumos os registros em nossa base de dados local usando ArrayDML. Tambm vimos como fazer
uma modificao significativa em nossa rotina de abertura de formulrios para evitar problemas de MemoryLeak no
futuro.
__________________________________________________________________________________________
67
A parte IX de nosso Tutorial: Criando meu app step-by-step traz a voc todos os detalhes para o uso de dois importantes
botes de hardware no Android, os botes Back e Menu. Esses botes so comuns e aparecem em todos os aparelhos
munidos de sistema operacional Android, sejam botes fsicos ou virtuais. O boto Home tambm existe e comum,
mas varia um pouco o uso em cada aparelho. O aparelho que usamos para testar nossas aplicaes por exemplo,
um Samsung Win Duos, possui todos esses botes em formato fsico, comum em aparelhos Samsung. Nosso Tablet
Multilaser por outro lado, possui apenas botes virtuais.
Como devem ter notado, essa fase de nosso tutorial ser mais light, mas no menos importante. Alm de vermos como
fazer uso dos botes Back e Menu em nosso aplicativo, aprenderemos dicas importantes relacionadas ao controle da
aplicao usando tais botes.
Para relembrarmos o que vimos na edio passada, veja abaixo em forma de tpicos. Ns vimos basicamente o uso
de ArrayDML e algumas dicas para liberao de memria.
Comandos ArrayDML para rpida insero no banco;
Ajustes na liberao de memria de objetos FORM;
E como mencionado, veremos aqui:
Como fazer uso dos botes Back e Menu?
Requisitos
Leitura: Artigos de I a VIII desse tutorial.
Botes de Hardware
Antes de codificarmos nosso sistema, vamos entender qual a ideia de usar os botes de hardware, em quais momentos
vamos utiliza-los e onde detectar o seu pressionamento. Se recapitularmos nosso app, vamos lembrar que temos
algumas telas que so acessadas via Menu Principal. Algumas delas possuem navegao, ou seja, botes virtuais
Prximo e Anterior. aqui que entra o boto Back.Queremos que ao tocar no boto, uma aba (TabControl) retorne. J
o boto Menu, vamos usa-lo em dois momentos:
1. Quando o usurio desejar abrir o Menu Principal;
2. E quando houverem menus Pop-up;
Agora, onde detectar que o usurio tocou nos botes? Os botes de hardware no Android precisam ser programados
manualmente, praticamente hardcoded, isso porque eles no tem como saber em qual tela estamos em nosso app e
muito menos para onde vamos. Outra coisa importante que temos um Form Principal que praticamente comanda o
app inteiro. Lembre-se da primeira parte do tutorial quando montamos a arquitetura de navegao. Temos
um TLayout no form principal e outro TLayout em cada nova janela, e ao abrir uma nova janela, ns adicionamos o
Layout do alvo ao Layout do form principal. (Figura 1)
__________________________________________________________________________________________
68
Em outras palavras, como se adicionssemos os demais formulrios ao formulrio principal, portanto o comando
central o Form Principal. Se colocarmos algum cdigo nos evento OnKeyUp do formulrio alvo, esse no ser
acionado, ao contrrio, o evento acionado ser o OnKeyUp do form principal. Por isso nele que programaremos tudo.
Selecione o evento OnKeyUp e clique duas vezes nele para iniciarmos a programao.
A primeira providncia declararmos uma nova varivel a esse evento.
FService do tipo IFMXVirtualKeyboardService. Essa varivel ser responsvel por verificar se o teclado est visvel, pois
se estiver, ignoramos os botes Back e Menu.
O escopo do nosso evento pode ser visto na Listagem 1.
?
1
2
3
4
5
6
var
FService : IFMXVirtualKeyboardService;
begin
end;
Em seguida comeamos toda a brincadeira. Para o boto Back basta checarmos o estado da varivel Key presente no
evento. Perceba que a assinatura do evento OnKeyUp possui um Sender, um Key e um KeyChar. Testaremos Key para
verificar qual tecla (ou boto) foi pressionada. Podemos usar apenas:
?
1
2
Veja como simples. Para o boto menu, basta testarmos se o Key igual a vkMenu. O cdigo-fonte da Listagem
2 refere-se ao cdigo completo do nosso mecanismo, ento vamos entender uma por uma das chamadas.
?
1
2
3
4
5
__________________________________________________________________________________________
69
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
begin
{Recebe o estado do teclado virtual}
TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FService));
{Se o boto back pressionado e o teclado virtual ativo, no faz nada}
if Key = vkHardwareBack then
begin
if (FService <> nil) and (TVirtualKeyboardState.Visible in FService.VirtualKeyBoardState) then
begin
//Reservado, no faz nada
end
else
begin
{Verifica qual formulrio est ativo e ento chama o mtodo Voltar}
{Se NO estiver com a listagem de pedidos aberta}
{$Region 'Menu'}
if MultiView1.IsShowed then
begin
MultiView1.HideMaster;
Key := 0;
end
{$EndRegion}
{$Region 'Titulos'}
else if (FTitulos.lytTitulos.Visible) and not (FTitulos.tabctrlTitulos.ActiveTab = FTitulos.tbitemLisTitulos) then
FTitulos.PressionouVoltar
else if (FTitulos.lytTitulos.Visible) and (FTitulos.tabctrlTitulos.ActiveTab = FTitulos.tbitemLisTitulos) then
begin
MessageDlg('Deseja sair do aplicativo?', TMsgDlgType.mtConfirmation,
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
procedure (const AResult: TModalResult)
begin
if AResult = mrYes then
begin
{$IFDEF ANDROID}
MainActivity.finish;
{$ELSE}
exit;
{$ENDIF}
end;
end
);
end
{$EndRegion}
{$Region 'Preferncias'}
else if (Assigned(FPreferencias)) then
begin
MessageDlg('Deseja sair do aplicativo?', TMsgDlgType.mtConfirmation,
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
procedure (const AResult: TModalResult)
begin
if AResult = mrYes then
begin
{$IFDEF ANDROID}
MainActivity.finish;
{$ELSE}
exit;
{$ENDIF}
end;
end
);
end;
{$EndRegion}
Key := 0;
end;
end
{Boto Menu do Android}
else if Key = vkMenu then
begin
if (FService <> nil) and (TVirtualKeyboardState.Visible in FService.VirtualKeyBoardState) then
begin
//Reservado, no faz nada
end
{O menu est sendo mostrado, apenas fecha o menu}
else
begin
if MultiView1.IsShowed then
HideBackground
{Verifica se o Pedidos est sendo mostrado e no est na lista de pedidos, para ento abrir o menu}
else if (FTitulos.lytTitulos.Visible) then
FTitulos.PressionouMenu;
Key := 0;
end;
end;
end;
__________________________________________________________________________________________
70
testamos tambm se estamos na aba tbitemListTitulos, nesse caso chamamos o mtodo PressionouVoltar do
formulrio Titulos. Esse mtodo dever ser criado como a seguir:
?
1
2
3
4
5
procedure TfrmTitulos.PressionouVoltar;
begin
if tabctrlTitulos.ActiveTab = tbitemDetalhes then
tabctrlTitulos.Previous();
end;
Perceba como simples. Aps verificar que o menu no est aberto e que no estamos na aba principal de Titulos, ns
chamamos o mtodo PressionouVoltar da tela alvo e deixamos que o mtodo decida o que fazer. Nesse caso
verificamos se a aba Detalhes est aberta, caso esteja, ento voltamos uma aba.
Dessa maneira faremos em todas as janelas, criando um mtodo PressionouVoltar e codificando o que queremos que
acontea, tela a tela. A mesma codificao, fazemos para a tela de preferncias de sistema, a nica diferena que
testamos se a janela est criada usando um Assigned na varivel do form, isso porque preferncias criada e destruda
sempre.
Retornando ao formulrio principal, o final da codificao diz respeito ao boto menu. Nesse caso testamos se o Key
igual a vkMenu,para ento fazermos os devidos testes. Em nosso exemplo, temos apenas um teste que referente a
janela Titulos. Caso ela esteja visvel, ento chamamos o mtodo PressionouMenu do prprio FTitulos, ou seja, mais
uma vez o controle dado ao formulrio. O mtodo PressionouMenu dever ser criado como a seguir:
?
1
2
3
4
5
6
7
procedure TfrmTitulos.PressionouMenu;
begin
if (tabctrlTitulos.ActiveTab = tbitemLisTitulos) then
frmMain.MultiView1.ShowMaster
else if (tabctrlTitulos.ActiveTab = tbitemLisTitulos) and (DM.qryTitulos.State in dsEditModes) then
imgFotoClick(imgFoto);
end;
Como mencionado, mais uma vez o formulrio tem o controle da situao. Aqui nesse caso estamos verificando qual
aba est aberta. Se a aba visvel for a principal, abrimos o menu principal. Se Detalhes for a aba visvel e estivermos em
modo de Edio, descemos o menu pop-up para que o usurio troque a foto do ttulo.
Basicamente s isso que precisamos fazer. Parece complicado, mas na verdade somente trabalhoso e precisamos
ter muita ateno na codificao. A ltima coisa a explicar aqui sobre a linha Key := 0 vista em vrios lugares no
cdigo da tela principal, OnKeyUp. Isso necessrio, pois se o Key no receber zero a aps o pressionamento, o evento
continuar a executar linha a linha e ento teremos problemas.
Fica agora ao seu gosto, codificar o restante das telas usando como base o cdigo explicado acima.
Concluso
O usurio Android est bastante acostumado a usar os botes de hardware para voltar telas ou abrir menus. Por isso
importantssimo que codifiquemos cada boto para que a navegao do app fique mais transparente. Em iOS isso
no possvel, isso porque existem poucos botes e o que exitem esto destinados a funes especficas. A Apple no
permite que voc utilize um boto de hardware para alguma funo diferente da que ele foi criado, exemplo. Um boto
para aumentar volume, apenas aumenta volume e nada mais. Recentemente a Apple liberou o uso do boto Aumentar
Volume para que seja usado em aplicativos de foto, nada mais.
Outro detalhe no mencionado na codificao foi a instruo MainActivity.finish; Essa instruo finaliza totalmente a
aplicao Android, como se fosse um Application.Terminate em aplicativos Desktop. Isso de muita importncia, s
com essa instruo garantimos que o app ser totalmente fechado e que todas as variveis, forms, etc sejam liberados
de memria. Em iOS isso no necessrio.
Caso tenha interesse em ver mais informaes sobre outros botes, verifique a DocWiki da Embarcadero.
__________________________________________________________________________________________
71
Chegamos a ltima parte de nosso Tutorial: Criando meu app step-by-step. At agora vimos como fazer toda a parte de
criao do aplicativo desde a concepo, passando por layout at o download de uma tabela inteira vinda de um
servidor DataSnap apontado para uma base de dados em Firebird 2.5. Muitos leitores nos escreveram solicitando essa
ltima parte que seria a mais importante de todas: o Sincronismo. Nesse tutorial ns veremos como fazer a excluso,
atualizao e insero de novos ttulos no servidor Firebirdusando o aplicativo Mobile.
Na parte anterior vimos:
Comandos ArrayDML para rpida insero no banco;
Ajustes na liberao de memria de objetos FORM;
Como mencionado veremos a seguir:
Como criar um mtodo para excluir registros do aplicativo mvel e do servidor;
Como enviar novos registros do Mobile para o Servidor;
Como criar um ApplyUpdates dos dados locais para o servidor;
Requisitos:
Leitura: Tutorial: Criando meu app step-by-step Parte IX
__________________________________________________________________________________________
72
25
26
27
28
29
30
ShowMessage(E.Message);
end;
end;
{$ENDIF}
end;
end;
AtualizarTitulos(memTemporario);
end
);
end;
__________________________________________________________________________________________
73
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//Mtodo de atualizao
procedure TfrmMain.AtualizarTitulos(AMemoryTable: TFDMemTable);
const
_INSERT =
'INSERT INTO TITULOS ' +
'(
' +
'
ID_TITULO ,
' +
'
TITULO
,
' +
'
SUBTITULO ,
' +
'
FOTO
,
' +
'
MINIATURA
' +
')
' +
'VALUES
' +
'(
' +
'
:ID_TITULO ,
' +
'
:TITULO
,
' +
'
:SUBTITULO ,
' +
'
:FOTO
,
' +
'
:MINIATURA
' +
');
';
var
intNumInserts : Integer;
begin
{Nmero de registros recebidos do servidor}
intNumInserts := AMemoryTable.RecordCount;
DM.qryAuxiliar1.Active
:= False;
DM.qryAuxiliar1.SQL.Text := _INSERT;
{Informamos a Query Auxliar qual o nmero de Inserts ser efetuado}
DM.qryAuxiliar1.Params.ArraySize := intNumInserts;
AMemoryTable.First;
while not AMemoryTable.Eof do
begin
DM.qryAuxiliar1.ParamByName('ID_TITULO').AsIntegers[AMemoryTable.RecNo-1]
DM.qryAuxiliar1.ParamByName('TITULO')
.AsStrings [AMemoryTable.RecNo-1]
DM.qryAuxiliar1.ParamByName('SUBTITULO').AsStrings [AMemoryTable.RecNo-1]
DM.qryAuxiliar1.ParamByName('FOTO')
.AsBlobs
[AMemoryTable.RecNo-1]
DM.qryAuxiliar1.ParamByName('MINIATURA').AsBlobs
[AMemoryTable.RecNo-1]
:=
:=
:=
:=
:=
AMemoryTable.FieldByName('ID_TITULO').AsInteger;
AMemoryTable.FieldByName('TITULO')
.AsString;
AMemoryTable.FieldByName('SUBTITULO').AsString;
AMemoryTable.FieldByName('FOTO')
.AsVariant;
AMemoryTable.FieldByName('MINIATURA').AsVariant;
AMemoryTable.Next;
end;
{Se houver mais de um registro a ser aplicado, ento chama o Execute da Quuery Auxiliar}
if intNumInserts > 0 then
DM.qryAuxiliar1.Execute(intNumInserts, 0);
DM.qryAuxiliar1.Active := False;
end;
__________________________________________________________________________________________
74
1.
2.
3.
4.
2.
1.
2.
3.
4.
3.
1.
2.
3.
4.
4.
1.
2.
3.
4.
5.
1.
2.
3.
4.
o
o
o
o
o
o
Name: spbVoltar
StyleLookup: backtoolbutton
Align: left
Margins.Left: 8
SpeedBuuton:
Name: spbCancelar
StyleLookup: deletetoolbutton
Align: left
Margins.Left: 8
SpeedButton:
Name: spbSalvar
StyleLookup: donetoolbutton
Align: right
Margins.Right: 8
SpeedButton:
Name: spbEditar
StyleLookup: composetoolbuttonbordered
Align: right
Margins.right: 8
Label:
Name: lblTituloDet
StyleLookup: listboxheaderlabel
Align: Contents
Margins: todas em 8px
Na ToolBar inferior adicione um SpeedButton com o nome spbExcluir. Alinhe-o como Client e coloque 8px em todas as
margens dele. No corpo do TabItem adicione um ListBox com o nome lsboxDetalhe e o alinhamento
como Client. Adicione dois itens no lsboxDetalhe. No primeiro item adicione um componente TImage e alinhe-o a
esquerda com margens 8px em todos os lados. Em seguida aumente a altura do item de listbox para 105 na
propriedade Height. Nosso TImage dever ficar com os tamanhos de largura (width) e altura (height)prximos
de 89px.
Nesse mesmo item de listbox adicione um TLayout e coloque-o como alinhamento Client. Dentro desse layout adicione
outro ListBoxque conter dois novos itens. Insira em cada item um componente TEdit para cada campo da tabela
de Ttulos, ou seja, um para Ttulo e outro para SubTitulo, veja abaixo:
TEdit:
Name: edtTitulo
Align: Client
Margins: todas como 8px
TEdit:
Name: edtSubTitulo
Align: Client
Margins: todas como 8px
No segundo item do nosso listbox geral, lsboxDetalhe, adicione um label alinhado a esquerda com 8px de margem
esquerda. Depois insira um TEdit chamado de edtAno e alinhe-o direita. Feitos os ajustes, ns termos algo parecido
com a Figura 3.
__________________________________________________________________________________________
75
Editando os dados
A primeira providncia criarmos um mtodo para ativar e desativar os botes. Para isso, acesse a
rea Public do form e crie um mtodo com o nome AtualizarBotoes, como abaixo:
procedure AtualizarBotoes;
Pressione Ctrl + Shift + C para criar o escopo do mtodo e codifique-o como na Listagem 3. E vamos a explicao. Ns
deixamos os botes Voltar, Editar e Excluir visveis somente se estivermos em modo Browse, ou seja, visualizando os
dados. Os botes Salvar e Cancelar somente ficam visveis se estivemos em modo de edio. Ainda mudamos a
propriedade ReadOnly de alguns componentes para permitir digitao.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
procedure TfrmTitulos.AtualizarBotoes;
begin
spbVoltar.Visible
:= (DM.qryTitulos.State = dsBrowse);
spbEdicao.Visible
:= (DM.qryTitulos.State = dsBrowse);
spbExcluir.Visible
:= (DM.qryTitulos.State = dsBrowse);
spbCancelar.Visible
spbSalvar.Visible
:= (DM.qryTitulos.State in dsEditModes);
:= (DM.qryTitulos.State in dsEditModes);
edtTitulo.Enabled
edtSubTitulo.Enabled
edtAno.Enabled
:= (DM.qryTitulos.State in dsEditModes);
:= (DM.qryTitulos.State in dsEditModes);
:= (DM.qryTitulos.State in dsEditModes);
edtTitulo.ReadOnly
:= (DM.qryTitulos.State = dsBrowse);
edtSubTitulo.ReadOnly := (DM.qryTitulos.State = dsBrowse);
edtAno.ReadOnly
:= (DM.qryTitulos.State = dsBrowse);
if (DM.qryTitulos.State in
begin
edtTitulo.StyleLookup
edtSubTitulo.StyleLookup
edtAno.StyleLookup
lblTituloDet.Text
end
else
begin
edtTitulo.StyleLookup
edtSubTitulo.StyleLookup
dsEditModes) then
:=
:=
:=
:=
'editstyle';
'editstyle';
'editstyle';
'Editando...';
:= 'transparentedit';
:= 'transparentedit';
__________________________________________________________________________________________
76
29
30
31
32
edtAno.StyleLookup
lblTituloDet.Text
end;
end;
:= 'transparentedit';
:= 'Detalhes';
Listagem 3. AtualizarBotes
Acesse o evento OnClick do boto voltar e digite o cdigo abaixo para que possamos Cancelar a edio caso o usurio
deseje retornar para a tela anterior.
?
1
2
3
4
5
6
7
Uma providncia que poderamos criar aqui seria perguntar ao usurio com um MessageDlg se ele realmente deseja
sair
da
tela
e
cancelar
o
cadastro.
Mas
isso
fica
a
critrio
do
leitor.
No boto cancelar insira o cdigo:
?
1
2
DM.qryTitulos.Cancel;
AtualizarBotoes;
Assim ns cancelamos a edio e atualizamos os botes de tela. Em seguida vamos mexer no evento OnClick do
boto Salvar, veja como fica:
?
1
2
3
4
5
Aqui simples entendermos. Se o cadastro estiver em estado de insero, ou seja, cadastro novo. Ns chamamos o
mtodos de criao de ID para esse registro. Ento gravamos o registro e atualizamos novamente os botes da tela.
Por fim, codifique o boto Editar como a seguir:
?
1
2
3
DM.qryTitulos.Edit;
AtualizarBotoes;
edtTitulo.SetFocus;
Muito fcil, apenas editamos e atualizamos novamente os botes. Focamos em cima do primeiro edit para que o
teclado suba. O ltimo boto o de excluso. Nesse codificaremos como abaixo, mas voltaremos mais tarde aqui para
fazermos uma alterao.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
Apenas perguntamos ao usurio se confirma a excluso e em caso positivo chamamos o mtodo Delete do Query e o
boto voltar automaticamente para que a tela seja atualizada. Ns teremos que voltar aqui mais tarde para poder
colocar a excluso tambm no servidor.
Se voc rodar sua aplicao nesse momento, tudo funcionar perfeitamente com exceo da parte de fotos que no
foi codificada ainda. Retorne a aba de listagem nessa tela e adicione um novo SpeedButton na toolbar superior. D o
nome de spbAdd nele e alinhe-o direita com Margin.Right igual a 8px. Seu StyleLookup ser addtoolbuttonbordered e
seu cdigo como a seguir:
?
1
2
3
DM.qryTitulos.Append;
tabctrlTitulos.Next;
AtualizarBotoes;
__________________________________________________________________________________________
77
Aqui apenas chamamos o mtodo de incluso do DataSet e mudamos para a aba de detalhes sem esquecer de atualizar
os botes de tela.
DM.qryTitulosFOTO.Assign(Image);
Como isso ns estamos recebendo a foto tirada/escolhida pelo usurio e inserindo direto no respectivo campo da base
de dados. Por fim, v at o evento OnClick do imgFoto e adicione o cdigo abaixo:
?
1
2
3
4
5
6
7
8
9
Perceba que bem fcil entendermos. Estamos primeiro verificando se a tabela est em modo de edio e ento
mostramos um pop-upmenu criado em aulas anteriores. Nesse pop-up ns teremos as opes Novo Foto, Biblioteca e
Cancelar. Basta voltar no tutorial que falamos disso e veja a codificao. Finalizamos por aqui.
Teste a aplicao e verifique se tudo funcionou.
Excluindo do servidor
Nossa brincadeira agora comea a ficar mais sria. At o momento estamos alterando somente no dispositivo mvel,
ou seja, se excluirmos algo no aparelho, o registro ser excludo apenas do aparelho. Quando o usurio fizer uma nova
sincronizao, o dado vir novamente. Ento voltemos ao cdigo-fonte do servidor e vamos criar um mtodo para
excluso. Acesse o nosso nico ServerMethodno servidor DataSnap e insira na rea Public o seguinte mtodo e
pressione Ctrl + Shift + C para criar o escopo do mtodo:
?
1
Codifique esse mtodos como abaixo. Insira nesse ServerMethod um FDQuery e d o nome de qryAuxiliar. O que
estamos fazendo bem simples. Criamos uma constante com a instruo DELETE para excluir ttulo da base de dados.
Fechamos a query, inserimos o valor do parmetro ATitulo que ser enviado pelo Cliente e ento usamos
o ExecSQL. Caso d tudo certo, resultamos True, caso contrrio Falsepara que possamos enviar uma mensagem ao
usurio.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
__________________________________________________________________________________________
78
Perceba que fizemos uma pequena alterao no miolo de nosso mtodo. Chamamos o server
mtodo ExcluirTitulo passando para ele o ID_TITULO do ttulo selecionado. Se o mtodo retornar verdadeiro, significa
que conseguimos excluir no servidor, ento exclumos tambm off-line. Caso contrrio, mensagem ao usurio.
ApplyUpdates no servidor
Agora entramos na reta final. Vamos fazer a primeira parte, o ApplyUpdates. Quem j est acostumado a desenvolver
com DBExpress e ClientDataSet, sabe que existe um mtodo chamado ApplyUpdates do ClientDataSet que faz o
trabalho de enviar as alteraes para o servidor de banco de dados. Ns teremos que criar nosso prprio mtodo de
atualizao do lado do servidor. Retorne ao servidor DataSnap e adicione um novo mtodo como abaixo:
?
1
2
3
4
5
6
7
O que ns fazemos aqui criar uma instncia da interface IFDJSONDeltasApplyUpdates para que possamos fazer
o apply. Instanciamos a varivel e ento chamamos o mtodo ApplyUpdates da Interface passando como parmetro o
nome da tabela gravado na constante sTitulos (const sTitulos = TITULOS) na rea Private no do servidor DataSnap. E
o segundo parmetro ns chamamos o mtodo Command do qryTitulos. Somente isso. O restante a prpria interface
faz o trabalho para ns. Gere novamente o servidor e execute-o.
Voltando ao aplicativo mobile, retorne no nosso mdulo cliente e ento atualize o arquivo Proxy. Antes de fazermos a
alterao,
precisamos
de
um
componente MemoryTable no DataModule principal.
Adicione
um
componente FDMemTable no DataModule e d o nome de memTitulos. Ns usaremos esse componente para receber
os dados alterados e envi-lo ao servidor. Ns precisamos alterar o boto Salvar. Volte no cdigo-fonte e ento
modifique-o como a seguir:
?
1
2
3
4
5
6
7
8
9
10
__________________________________________________________________________________________
79
11
12
13
14
15
16
17
18
LDeltaList := TFDJSONDeltas.Create;
LDataList := TFDJSONDataSets.Create;
TFDJSONDataSetsWriter.ListAdd(LDataList, DM.qryTitulos);
TFDJSONDeltasWriter.ListAdd(LDeltaList, sTitulos, DM.memTitulos);
ModuloCliente.SrvServerMetodosClient.ApplyUpdadesTitulos(LDeltaList);
AtualizarBotoes;
end;
O que ns fazemos aqui bem simples. Ns precisamos criar uma instncia da classe FDJSONDeltas. Essa instncia
receber os dados alterados da query para envio ao servidor. Tambm precisamos de uma varivel para receber os
dados em formato FDJSONDataSets. O que estamos fazendo adicionando os registros da query Titulos dentro do
componente memTitulos. Logo em seguida chamamos o mtodo ApplyUpdatesTitulos passando o LDeltaList como
parmetro. Feito isso o servidor receber a lista de Deltas e aplicar ao banco de dados.
Concluso
Finalizamos aqui nosso Tutorial: Criando meu app step-by-step que iniciamos em RAD Studio XE6 e finalizamos em XE7
(ou XE8 que tambm funcionar normalmente). O que vimos nesse tutorial que com poucos detalhes e at com
pouca programao, conseguimos criar um aplicativo totalmente compatvel com iOS 32 e 64Bits, Android, Mac OS X
e Windows 32 e 64bits.
Desenvolver aplicativos para essas plataformas hoje muito mais simples do que podemos imaginar. E o melhor de
tudo, com um nico cdigo-fonte. Em nosso app, temos acesso a um banco de dados local SQLite e ainda inclumos a
funcionalidade de sincronismo com um servidor de aplicativos plugado em um Firebird 2.5.
Esperamos que esse tutorial tenha sido importante para voc leitor e que possa compartilhar para outros que desejam
aprender mais.
At a prxima
#GoToDelphi
Nessa ltima parte de nosso tutorial, alguns leitores detectaram problemas na funo ApplyUpdates e resolvemos
revisar o artigo. De fato, o ApplyUpdatesTitulos criado aqui no funciona perfeitamente, isso porque estamos tentando
extrair os Deltas do qryTitulos (Query), mas isso no possvel. A codificao utilizada no consegue extrair justamente
por no existirem Deltas em FDQuery. Para corrigir o problema, devemos fazer algumas alteraes no nosso projeto.
Vamos l:
A primeira alterao redirecionar todos os binds para o memTitulos presente em nosso DataModule. Ento, nosso
memTitulos dever possuir os campos da tabela Ttulos. Ns j adicionamos esses campos no FieldsEditor da qryTitulos,
por isso clique com o direito nesse componente e escolha Fields Editor. Selecione todos os campos, pressione Ctrl + C
para copia-los e feche-o. Em seguida clique com o direito no memTitulos e escolha Fields Editor. Clique com o direito
na janelinha e em seguida em Paste.
Agora volte ao formulrio ttulos, acione a janela de Binding e refaa todos os links de campos apontando-os para o
memTitulos, como na Figura 4.
__________________________________________________________________________________________
80
__________________________________________________________________________________________
81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var
LDeltaList : TFDJSONDeltas;
//LDataList : TFDJSONDataSets; desnecessrio
begin
if DM.memTitulos.State in [dsInsert] then
DM.memTitulos.FieldByName('ID_TITULO').AsInteger := DM.GetIDFromTable('TITULOS');
DM.memTitulos.Post;
LDeltaList := TFDJSONDeltas.Create;
//LDataList := TFDJSONDataSets.Create; desnecessrio
TFDJSONDeltasWriter.ListAdd(LDeltaList, sTitulos, DM.memTitulos);
//TFDJSONDataSetsWriter.ListAdd(LDataList, DM.memTitulos); desnecessrio
ModuloCliente.SrvServerMetodosClient.ApplyUpdadesTitulos(LDeltaList);
AtualizarBotoes;
end;
procedure TDM.AbrirTitulos;
var
LDataSetList : TFDJSONDataSets;
begin
qryTitulos.Active := False;
qryTitulos.Active := True;
LDataSetList
:= TFDJSONDataSets.Create;
memTitulos.Active := False;
TFDJSONDataSetsWriter.ListAdd(LDataSetList, qryTitulos);
memTitulos.AppendData(TFDJSONDataSetsReader.GetListValue(LDataSetList, 0));
end;
Com isso, ns agora temos o processo completo de alterao funcionando perfeitamente no Android e iOS. Agora no
evento OnCreate do formulrio Titulos chame esse mtodo para que possamos abrir a tabela.
O cdigo-fonte disponvel no BitBucket j est atualizado para download.
__________________________________________________________________________________________
82