Você está na página 1de 82

Criando meu app step-by-step  

– Parte I ...........................................................
.................................................................................................................
...................................................... 3

Criação da App .............................................................


...................................................................................................................................
........................................................................................
..................3

Definição do Layout .................................................................


......................................................................................................................................
............................................................................
.......4

Criando o menu inicial ............................................................


..................................................................................................................................
.............................................................................
....... 5

Primeira codificação ...............................................................


.....................................................................................................................................
.............................................................................
....... 8

Criando o segundo FORM e testando o menu ..........................................................


...................................................................................................
.........................................11

Testando a app ............................................................


...............................................................................................................................
......................................................................................
................... 14

Conclusão ....................................................................
..........................................................................................................................................
......................................................................................
................ 15

Criando meu app step-by-step Parte II ..........................................................


..............................................................................................................
.................................................... 16

Retomando o raciocínio ..........................................................


................................................................................................................................
...........................................................................
..... 16

Prototipação .................................................................
......................................................................................................................................
.....................................................................................
................ 17

Protótipo de Usuários .............................................................


...................................................................................................................................
...........................................................................
.....19

Criando uma tela de login ...................................................................


..................................................................................................................................
...............................................................20

Construindo a classe de login ............................................................


............................................................................................................................
................................................................ 21

Usando a Classe Login. .......................................................................................................................................


....................................................................................................................................... 23

Modelagem de Dados .............................................................


...................................................................................................................................
...........................................................................
..... 24

Conclusões ...................................................................
.........................................................................................................................................
......................................................................................
................ 25

Criando meu app step-by-step –


step-by-step – Parte
 Parte III .................................................................
..........................................................................................................
......................................... 26

Retomando o Raciocínio .........................................................


...............................................................................................................................
...........................................................................
.....26

Codificando a abertura do banco de dados ..............................................................


.......................................................................................................
......................................... 28

Conectando a primeira tabela ...........................................................


...........................................................................................................................
................................................................ 29

Detalhes dos Títulos. ..........................................................................................................................................


.......................................................................................................................................... 30

Conclusões ...................................................................
.........................................................................................................................................
......................................................................................
................ 32

Criando meu app step-by-step Parte IV .........................................................


.............................................................................................................
....................................................33

Retomando o raciocínio ..........................................................


................................................................................................................................
...........................................................................
..... 33

Alterando o banco de dados ..............................................................


..............................................................................................................................
................................................................33

Binding de Fotos ......................................................................


...........................................................................................................................................
..........................................................................
..... 34

Errata da Parte II ......................................................................


...........................................................................................................................................
..........................................................................
.....35

Editando um registro ..............................................................


....................................................................................................................................
...........................................................................
.....36

Gerando um novo registro. ................................................................................................................................


................................................................................................................................ 38

Criando um pop-up menu...................................................................


..................................................................................................................................
............................................................... 41

Excluindo registros. ............................................................................................................................................
............................................................................................................................................ 43

Conclusão ....................................................................
..........................................................................................................................................
......................................................................................
................ 44

Criando meu app step-by-step –


step-by-step – Estilo
 Estilo –
 – Parte
 Parte V....................................................................
...............................................................................................
........................... 45

Usando um estilo mais profissional ...............................................................


...................................................................................................................
.................................................... 45

Criando um arquivo de configurações ...........................................................


...............................................................................................................
....................................................46

 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
1
Codificando o arquivo INI ...................................................................
..................................................................................................................................
............................................................... 47

Cadastro de Preferências ........................................................


..............................................................................................................................
...........................................................................
..... 49

Configurando e baixo um código-fonte usando Git no RAD Studio XE7 ............................................................ 50


Conclusões ...................................................................
.........................................................................................................................................
......................................................................................
................ 51

Criando meu app step-by-step –


step-by-step – DataSnap
 DataSnap REST –
REST – Parte
 Parte VI ...........................................................
..............................................................................
................... 52

Criando o servidor DataSnap REST.................................................................


.....................................................................................................................
.................................................... 52

Criando o servidor ...................................................................


........................................................................................................................................
..........................................................................
..... 53

Entendendo o Servidor ...........................................................


.................................................................................................................................
...........................................................................
.....53

Aplicação Cliente .....................................................................


..........................................................................................................................................
..........................................................................
..... 54

Testando o retorno de métodos ........................................................


........................................................................................................................
................................................................56

Conclusões ...................................................................
.........................................................................................................................................
......................................................................................
................ 56

Criando meu app step-by-step –


step-by-step – Reflection
 Reflection –
 – Parte
 Parte VII .....................................................................
.....................................................................................
................ 57

Criando a tabela no banco de dados Firebird ...........................................................


....................................................................................................
......................................... 57

Reflection do FireDAC –
FireDAC – Configuração
 Configuração do servidor DataSnap ............................................................................57
Preparando o cliente para acesso. .....................................................................................................................
..................................................................................................................... 60

Preparando o Sincronismo..................................................................
.................................................................................................................................
............................................................... 60

Pausa para métodos anônimos. .........................................................................................................................


......................................................................................................................... 61

Retomando o raciocínio ..........................................................


................................................................................................................................
...........................................................................
..... 61

Conclusões ...................................................................
.........................................................................................................................................
......................................................................................
................ 61

Criando meu app step-by-step –


step-by-step – ArrayDML
 ArrayDML –
 – Parte
 Parte VIII ....................................................................
....................................................................................
................ 62

Criando meu app step-by-step –


step-by-step – ArrayDML
 ArrayDML –
 – Parte
 Parte VIII ....................................................................
....................................................................................
................ 62

Entendendo o conceito...........................................................
.................................................................................................................................
...........................................................................
..... 63

Otimizando Memória ..............................................................


....................................................................................................................................
...........................................................................
..... 65

Conclusões ...................................................................
.........................................................................................................................................
......................................................................................
................ 67

Criando meu app step-by-step –


step-by-step – Botões
 Botões de Hardware –
Hardware – Parte
 Parte IX ......................................................................68
Botões de Hardware ...............................................................
.....................................................................................................................................
...........................................................................
.....68

Conclusão ....................................................................
..........................................................................................................................................
......................................................................................
................ 71

Criando meu app step-by-step –


step-by-step – Sincronismo
 Sincronismo –
 – Parte
 Parte X –
X – Final
 Final ...................................................................
........................................................................
..... 72

Tutorial: Criando meu app step-by-step –


step-by-step – Sincronismo
 Sincronismo –
 – Parte
 Parte X ................................................................
.....................................................................
..... 72

Editando e Adicionando registros no cliente ............................................................


.....................................................................................................
......................................... 74

Editando os dados ...................................................................


........................................................................................................................................
..........................................................................
..... 76

Atualizando e Selecionando fotos. .....................................................................................................................


..................................................................................................................... 78

Excluindo do servidor .............................................................


...................................................................................................................................
...........................................................................
..... 78

Excluindo no cliente versus Excluindo no servidor ..............................................................


............................................................................................
.............................. 79

ApplyUpdates no servidor ..................................................................


.................................................................................................................................
............................................................... 79

Enviando novos registros ........................................................


..............................................................................................................................
...........................................................................
.....80

Conclusão ....................................................................
..........................................................................................................................................
......................................................................................
................ 80

 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
2
O desenvolvimento de aplicações móveis utilizando Delphi tem gerado muito “pano pra manga” em comunidades
Delphi nas redes sociais. Com o interesse cada vez maior, de programadores novos ou experientes, em desenvolver
apps com a ferramenta, surgem também as dúvidas. Muitas comuns como o simples fato de navegar entre telas de um
app ou ainda dúvidas mais avançadas como o uso de Bluetooph com Delphi em iOS e Android. Muito bem, baseado
nisso resolvi criar alguns posts com orientações e um passo-a-passo explicando as principais dúvidas encontradas pela
internet.
Nesse primeiro post vamos começar do início:

1. Criação da app;
2. Criação do layout;
3. Navegação entre as abas;
4. Navegação entre formulários.

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 início para abranger iniciantes e experts.


Obs 2. Usarei nesses primeiros posts o RAD Studio XE6, devido ao novo recurso de formulários Master que terei que
explicar em um segundo momento separado.

Vamos começar, evidentemente, abrindo o Delphi e criando a aplicação salvando-a em um diretório de nossa
preferência. Utilize o menu File>New>Multi-DeviceApplication – Delphi 
Delphi  (no
  (no XE7, em XE5 e 6 o nome do menu é
diferente, apenas verifique o correto). ( )

. Início da aplicação

 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
3
Na tela que se abre, escolhemos o layout inicial de nossa aplicação. Não se preocupe com isso agora, podemos mudar
com o tempo. Portanto, vamos escolher a opção .

Somos levados ao primeiro Form de nossa app e vamos chama-la de  frmMain (Principal). Existem milhares de técnicas
diferentes para criar nosso layout e a navegação do aplicativo, mas nesse caso vou mostrar como eu tenho criado meus
aplicativos em minha empresa, assim fica como sugestão.
Para quem já está utilizando o Delphi XE7, deve estar visualizando algo diferente na IDE. São os layouts Master . Agora
é possível criar um layout principal
principa l e deixar que a IDE selecione o correto para cada dispositivo
dispo sitivo 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 estão em versões anteriores utilizem
as opções GoogleNexus4  ou SamsumgGalaxyS2/S4 , etc. ( )
Criando meu app step-by-step
 Definição de Layout no XE7

 Definição de Layout XE4,5 e 6

Feito isso o que vamos começar a fazer é entender ao certo como nossa app irá se comportar. Tive a ideia de criar um
app para controle de locadora (Quem nunca fez um sistema de locadora ao fazer um curso de programação, não é
mesmo? ;)), pois já estamos familiarizados com algumas das tabelas e informações que uma locadora precisa ter para
funcionar.
Nesse primeiro momento faremos a criação de nossas listas sem o uso de banco de dados, ou seja, aprenderemos a
usar o esquema de Prototipação do Delphi criando dados fictícios para visualizarmos
visualizarmos o funcionamento
funcionamento do app.
Salvemos o projeto então. Na propriedade Name do formulário insira o texto “frmMain” (sem as áspas) e salve o
formulário usando File>New>SaveAs… Dê o nome de UntMain e salve-o no diretório que desejar. Em seguida salve
o projeto usando File>New>SaveProjectAs… Dei o nome de LocadoraDelphi.dproj 

Muito bom. A primeira coisa a se definir, na minha opinião, é desenhar como a aplicação deverá se comportar. Eu me
utilizo de várias técnicas para isso. Como não sou designer, mas tenho alguma noção de desenho, comprei um bloco
de folhas A3 tipo  flipcharting
 flipcharting onde costumo desenhar, rusticamente claro, o fluxo da minha aplicação. ( ).

 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
4
 Folha A3 para desenho

Para quem não tem a mínima noção de desenho, existem inúmeras ferramentas no mercado que ajudam nesse
quesito. Mas enfim, não é 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 Títulos;
 Lista de Usuários/Clientes;
 Lista de Títulos Alugados;
 Alugar: Tela para definir o aluguel para um cliente;
 Baixar Título Alugado;
A ideia é que o app seja utilizado pelo administrador da ocadora como se fosse a extensão de seu programa de uso no
desktop da loja, onde o cara poderá consultar rapidamente algumas informações sobre o título. Nossa tela default  ser
a  que deverá abrir logo que de início. Faremos um Login e Senha utilizando Parse.com como backend
de banco de dados para facilitar e aprender a usar o serviço;
Teremos também um menu no estilo FacebookMobile  que se popularizou bastante, ou seja, abriremos as opções
tocando em um botão 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 formulário e
NÃO um dentro do outro. Adicione primeiro o TLayout  e faça as seguintes configurações:
 Name: lytMain;
 Align: Client;
Agora adicione um TListBox  no Form e então faremos uma série de mudanças 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 serão 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 personalização da aplicação incluindo um layout mais customizado

 __________________________________________________________________________________________
5
Clique agora com o botão 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 ( ):
 TListBoxGroupHeader: Cabeçalho do Grupo;
 TListBoxItem: Item

 Tipos de Item de ListBox

 Ordem os menus

Adicione 2 (dois) TListBoxGroupHeader   e 4 (quatro) TListBoxItem   e coloque-os na ordem da . Cada item


do ListBox   possui suas propriedades, isso significa que podemos utilizar a propriedade Text  como “Caption” do nosso
menu e ainda outras propriedades como ItemData  para adicionar um botão  Acessory e uma imagem para ele.
 __________________________________________________________________________________________
6
#Dica: Em Mobile, os botões (figuras) que ficam à direita do item na lista são chamados de Acessory (Acessório). Servem
para indicar se o item possui um “Mais Informações”, “Sub Detalhe” ou ainda um “Check” para por exemplo indicar
que o item está selecionado para alguma ação.
#Dica: Procure observar outros aplicativos e seguir os conceitos padrões de cada sistema operacional, pois o principal
fator para que uma aplicação tenha sucesso é: Usabilidade.  Lembre-se que o usuário 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: Configurações
Agora configure o TListBoxItem1  como a seguir:
 Name: lstitTitulos
 Text: Títulos
 ItemData > Acessory: More
Repita os passos anteriores para configurar os demais itens de menu. Nosso menu final terá que ficar semelhante
a . Os Names,respectivamente, são:
 lstitTitulos
 lstitUsuarios
 lstitTitulosAlugados
 lstitLogin

 Menu final

Observe que não colocamos todos os itens de menu na tela nesse primeiro momento. Vamos “comer o boi por partes”
como dizem meus conterrâneos. Muito bom! Nossa mecânica para carregar cada Form será a seguinte:
1. Para cada Lista, teremos um TForm com suas próprias funcionalidades, barras de navegação, etc;
2. Não utilizaremos Show ou ShowModal,  ao contrário. Criaremos o TForm no momento oportuno e carregaremos ele
dentro do TLayout principal em nosso frmMain utilizando um AddObject. Dessa forma temos controle total sobre todos
os forms abertos.
Por conta do segundo item que colocamos o menu (ListBox) e o layout (TLayout) dentro do formulário e não um dentro
do outro como mencionado anteriormente. Nosso lytMain será um mero espectador, receberá dentro dele todos os
objetos (Forms) que precisarmos navegar.
Para ter certeza que fez as configurações corretas, seu projeto deverá se parecer com a   que se refere a
caixa StruturedoDelphi .

 __________________________________________________________________________________________
7
 Caixa Structure

Perfeito até aqui e sei que estão eufóricos para codificar tudo. Então mãos a obra. Primeiro criaremos métodos para
mostrar e ocultar o menu. Para isso, teremos que adicionar alguns elementos visuais ao formulário para termos uma
aparência mais interessante.
interessante.
Adicione ao formulário 2 (dois) novos componentes. 1 TFloatAnimation  e 1 TRectangle.  Eles devem ficar DENTRO do
lytMain. O componente de animação deve receber o Name=AnimateDrawer . Já o TRectangle  precisa ser configurado
como a seguir:
 Name: recBackground
 Opacity: 0,5
 Fill.Color : Black
 PropertyName:
PropertyName: Position.X
Essas configurações darão um aspecto mais profissional. Se desejar conferir a estrutura dos componentes novos,
observe a .

. Aspecto final do menu

Vamos ao código dos métodos agora. Crie duas novas Procedures  na seção Private do Form como na
 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
8
 Código dos novos métodos
?
1 procedure HideMenu;
2 procedure ShowMenu;
Pressione Ctrl+Shift+C  para
 para criar o escopo de cada método e vamos ao código de cada um conforme a
 Código dos métodos criados para Mostrar e Ocultar o Menu
?
procedure TfrmMain.HideMenu;
begin
1
//Posiciona o ListBox de menu fora da visão
2
lstMnuMain.AnimateFloat('Position.X', -Self.ClientWidth);
3
4
AnimateDrawer.StartValue := Self.ClientWidth - 40;
5
AnimateDrawer.StopValue := 0;
6
AnimateDrawer.Start;
7
end;
8
9
procedure TfrmMain.ShowMenu;
10
begin
11
AnimateDrawer.StartValue := 0;
12
AnimateDrawer.StopValue := Self.ClientWidth - C_MnuEspaco;
13
AnimateDrawer.Start;
14
15
//Reposiciona o menu principal
16
lstMnuMain.AnimateFloat('Position.X', 0);
17
18
//Mostra o retângulo preto sobre a lista ativa
19
ShowBackground(Self.lytMain, CancelMenu);</pre>
<pre>end;

No primeiro método, HideMenu, posicionamos o ListBox do menu para fora da área de visualização utilizando uma
animação através do método  AnimateFloat.
 AnimateFloat.  Esse é método é um dos que mais gosto de usar. É bem simples e
praticamente todos os objetos Firemonkey possuem. Basta passar a propriedade que se deseja animar no primeiro
parâmetro e o novo valor no segundo parâmetro. Nesse caso usamos Position.X  com
 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 código ao meu ver dispensa dispe nsa
comentários assim como o método ShowMenu  que é exatamente o inverso. Apenas observe que reposicionamos o
ListBox na posição 0 (Zero).
Teremos ainda que criar outros métodos que nos ajudarão a controlar melhor o menu. Retorne as
seções Private e Public  do form e adicione os novos métodos conforme a
 Outros métodos de controle do menu
?
private
{ Private declarations }
1
procedure HideMenu;
2
procedure ShowMenu;
3
procedure CancelMenu(Sender: TObject);
4
public
5
{ Public declarations }
6
procedure ShowHideMenu;
7
procedure ShowForm(AObject: TFmxObject);
8
procedure ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent = nil);
9
procedure HideBackground;
10
end;

Vamos as explicações:
 CancelMenu: Será necessário para esconder o retângulo opaco da tela e ocultar o menu;
 ShowHideMenu:  Controla a visibilidade do menu;
 ShowForm: Indicaremos ao formulário Main quem deverá estar visível ou invisível;
 ShowBackground  e HidBackground:  Responsáveis por mostrar e ocultar o retângulo;
Pressione Ctrl + Shift + C para criação dos escopos e codifique como na
 Métodos de controle do menu
?
1 procedure TfrmMain.CancelMenu(Sender: TObject);
2 begin
3 HideBackground;

 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
9
4 ShowHideMenu;
5 end;
6
7 procedure TfrmMain.ShowHideMenu;
8 var
9 Position : single;
10 begin
11 {Verifica a posição atual do menu e mostra ou oculta conforme necessário}
12 Position := Self.ClientWidth - 40;
13 case Self.lytMain.Position.X = Position of
14 true : HideMenu;
15 false : ShowMenu;
16 end;
17 end;
18
19 procedure TfrmMain.ShowForm(AObject: TFmxObject);
20 var
21 I : Integer;
22 begin
23 HideBackground;
24
25 for I := 0 to Pred(Self.lytMain.Children.Count) do
26 TControl(Self.lytMain.Children[I]).Visible :=
27 TControl(Self.lytMain.Children[I]) = TControl(AObject);
28 end;
29
30 procedure TfrmMain.ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent);
31 begin
32 //Atualiza o evento OnClick do retâgulo com a ação enviada por parâmetro.
33 ///Isso fará com que saibamos a tela (ou ação) que deve ser mostrada ao clicar no retângulo
34 recBackground.OnClick := AOnClick;
35 recBackground.Parent
recBackground.Pa rent := AParent;
36 recBackground.BringToFront;
37 //Modifica a transparência do retângulo e anima a transparência
38 recBackground.Opacity := 0;
39 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 explicações de cada método iniciando por CancelMenu. Esse método apenas
chama HideBackground  e  e ShowHideMenu forçando o retângulo opaco desaparecer e checando se o menu está aberto
ou fechado para saber para onde temos que ir.
Em seguida ShowHideMenu. Através da variável Position  conseguimos detectar qual o posicionamento do Menu (nosso
ListBox, lembre-se). A variável recebe a largura da tela atual, ou seja, funcionará tanto com celulares quanto com
tablets e na horizontal ou vertical. E subtraímos 40 px para evitar que a tela (listagem) atual suma completamente da
visão do usuário. Com base na posição do menu, decidimos se o mostramos ou ocultamos.
ShowForm  será responsável por receber o objeto ( Form,Layout,TabControl ) alvo e deixa-lo visível para o usuário. A
ideia é simples. Quando codificarmos o OnClick  de cada Item de Menu, faremos um  AddObject  dentro   dentro do nosso
lytMain, em seguida chamamos ShowForm  para ocultar todos os outros formulários e mostrarmos somente o atual.
Isso é necessário, pois nosso ListBox  está
 está configurado como como  Se deixarmos visíveis os demais forms,
corremos o risco de sobrepor as telas.
Por fim ShowBackGround  e  e HideBackGround.   No primeiro método, recebemos o Parent   do objeto que está sendo
carregado, para que o retângulo opaco fique sobre ele, assim teremos um aspecto “esmaecido” do form quando o
menu estiver aberto. Também recebemos um evento OnClick  caso desejarmos que ao clicar no retângulo algo
aconteça. Por fim trazemos ele para frente e configuramos sua opacidade, visibilidade e a animação para aparecer.
Reparem que estou usando novamente o método  AnimateFloat 
 AnimateFloat  (dessa
 (dessa vez no retângulo) passando como parâmetro a
propriedade ‘opacity’  e
 e os valores 0.5 e 0.1 nos parâmetros seguintes.
O 0.5 é o novo valor da opacidade, para deixa-lo levemente transparente. O 0.1 é o tempo que levará para a animação
ocorrer.

 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
10
A essa altura do campeonato, provavelmente conseguiremos compilar normalmente nossa aplicação sem problemas.
Então, agora vamos criar um segundo formulário para testar se nosso menu e nossa mecânica está funcionando
perfeitamente.
Crie um novo form usando File>New>FiremonkeyMobileForm – Delphi 
Delphi  e
 e marque a opção HDFireMonkeyForm . Por
fim clique em Ok, para finalizar ( ). Agora temos um segundo formulário que será usando para nossa Lista
de Títulos.

 Criação do novo Form

 Confirmação do novo Form

Vamos apenas configurar as propriedades mais básicas e o layout principal do formulário. Na Parte II do post faremos
a prototipação da janela para evitar que esse post fique ainda maior.
Primeiro adicione um ToolBar  no
  no formulário e mude sua propriedade Name para toolTitulos.  Inclua em seguida um
TLayout ao formulário e chame-o de lytTitulos. Também configure-o para que fique com alinhamento Client ( Align=
Client ).
). Nós carregaremos o lytTitulos dentro do lytMain no formulário principal.
Dentro do TLayout adicione um TabControl  e  e configure suas propriedades como a seguir:
 Name: tabctrlTitulos
 TabPosition: Bottom
 ______________________
 _________________________________
______________________
________________________
________________________
_______________________
______________________
__________
11
Clique com o botão 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 Títulos”. Modifique também 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 botão voltar. Configure-o como a seguir:
 Name: spbBack
 StyleLookup: detailstoolbutton
 Align: Left
 Margins.Left: 8
Teremos então uma aparência semelhante a imagem da

 Aparência do formulário Títulos

A única codificação por hora nesse Form é fazer a chamada ao método ShowHideMenu  do formulário principal. Isso
mesmo! Nós vamos fazer um UseUnit  do formulário principal em nossa Listagem de Títulos. Clique em File>UseUnit  e
adicione a unit UntMain na seção Implementation do form.
Em seguida clique duas vezes no único botão dessa tela e adicione a linha de código a seguir:
?
1 frmMain.ShowHideMenu;
Fazendo isso, nós chamamos o método ShowHideMenu  que se encarregará de mostrar o menu novamente para que
o usuário possa entrar em outra janela.
Uma última alteração no código-fonte da janela, retire a declaração da variável com a instância do form, não
precisaremos dela. Localize a seção implementation e apague as linhas como a seguir:
?
1 var
2 frmTitulos: TfrmTitulos;

 __________________________________________________________________________________________
12
Retornamos agora para o formulário principal para fazer a as devidas chamadas e abrir a nossa tela de títulos.
Acesse File > Use Unit  e adicione o formulário de títulos a seção interface do form principal. Agora selecione
o lstitemTitulos  e adicione o código da ao evento OnClick.
 Código do evento OnClick para abertura da tela Listagem de Títulos
?
if not Assigned(FTitulos) then
1
FTitulos := TfrmTitulos.Create(Self);
2
3
{Adiciona o Layout de Pedidos ao Layout Principal que controla tudo}
4
lytMain.AddObject(FTitulos.lytTitulos);
5
{Deixa todos os layouts invisíveis e deixa o layout alvo visível}
6
ShowForm(FTitulos.lytTitulos);
7
8
if Sender <> Self then
9
ShowHideMenu;
O que estamos fazendo aqui é bem simples na verdade. Primeiro verificamos se há alguma instância do formulário de
títulos na memória. Note que usamos uma variável FTitulos  para isso e logo em seguida criamos o FormfrmTitulos. A
variáveis FTitulos precisa ser declarada na seção Private do form principal, como abaixo:
?
1 ...
2 private
3 FTitulos: TfrmTitlos;
4 ...
Na seqüência adicionamos o TLayout lytTitulos  (Form Titulos) ao TLayout lytMain   do formulário principal. Por fim
chamamos ShowFormpara fazer com que o form se torne visível. A última instrução evita que o menu apareça caso
quem esteja chamando o método seja o próprio form principal.
Estaria pronto para testar nesse momento, mas ainda vamos fazer umas configurações. Lembram-se que nosso
formulário de títulos será aberto assim que a app inicializar? Pois bem, teremos que codificar então o
evento OnCreate  do form principal. Para isso selecione o Form e clique duas vezes no evento OnCreate  e codifique
como na
 OnCreate do form principal
?
1 procedure TfrmMain.FormCreate(Sender: TObject);
2 begin
3 {Layout Escuro Global}
4 recBackground.Visible := False;
5 recBackground.Align := TAlignLayout.Contents;
6
7 {Modifica a largura do ListBox para a mesma do formulário, pois o mesmo está como Align = None}
8 lstMnuMain.Width := Self.ClientWidth;
9 lstMnuMain.Position.X := -Self.ClientWidth;
10
11 //Traz para frente o layout principal evitando sobreposição de listas
12 lytMain.BringToFront;
13
14 lstitTitulosClick(Sender);
15 end;
Precisamos de algumas personalizações aqui. Primeiro nós deixamos o retângulo invisível e mudamos seu alinhamento
para Contents, ou seja, ao conteúdo, equivalente a opção Client.
#Dica: A diferença entre os alinhamentos Client  e Contents,  é que Contents   encobre também as barra de status do
aparelho, normalmente visível na parte superior.
Em seguida ajustamos o menu principal e trazemos o layout para frente de todos os objetos. Por fim, chamamos o
método lstitTitulosClick  para forçar a abertura do formulário ListagemdeTítulos .
E a última codificação acontece no evento OnClose  do formulário principal. Forçamos a liberação da instância do
formulário de títulos caso esteja aberto.
?
1 if Assigned(FTitulos) then
2 FTitulos.DisposeOf;
Atenção para o método DisposeOf.  Não utilize em Mobile o método Free ou FreeAndNil,  pois acabam entrando na fila
do  ARC (Gerenciamento de Memória do dispositivo). O DisposeOf  força o FREE   da variável imediatamente. Em outras
palavras, variáveis ou objetos devem ser liberados de memória usando esse método.

 __________________________________________________________________________________________
13
É óbvio que depois de chegarmos até aqui, estamos curiosos para testar a aplicação. Então é hora de contar um
segredo. Não exatamente um segredo, mas uma dica útil. Não 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 não tenha mudado as configurações do Delphi) e clique com
o botão direito em cima de TargetPlatforms. Clique em  AddPlatform e escolha Win32 na janela que aparece (
).

 Adição de plataforma

 Plataforma Win32

Agora basta clicar duas vezes na plataforma e executar a aplicação.


#Dica: Caso não precise debugar a aplicação, selecione Release em BuildConfigurations, pois é mais rápido o deploy,
inclusive dos aparelhos.
Se tudo correr bem, teremos telas semelhantes as figuras seguintes:

 __________________________________________________________________________________________
14
Assim como mencionado desde o início, existem milhares de maneiras diferentes de criar layouts e navegação 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 aplicação.
No próximo post, veremos como prototipar a aplicação. Criaremos uma lista de títulos utilizando LiveBindings  e o
componente PrototypeBindSource  assim como o uso de DataModule.

Uma atualização. Existe uma constante mencionada no método ShowMenu, C_MnuEspaco. Troquem ela pelo valor
40. Esse é o espaço que a listagem ficará afastada quando o menu estiver aberto.
?
1 procedure TfrmMain.ShowMenu;
2 begin
3 AnimateDrawer.StartValue := 0;
4 AnimateDrawer.StopValue := Self.ClientWidth - 40;
5 AnimateDrawer.Start;
6
7 //Reposiciona o menu principal
8 lstMnuMain.AnimateFloat('Position.X', 0);
9
10 //Mostra o retângulo preto sobre a lista ativa
11 ShowBackground(Self.lytMain, CancelMenu);
12 end;

 __________________________________________________________________________________________
15
A primeira parte desse tutorial publicada uma semana atrás (Link aqui) teve como principal objetivo iniciar uma série
de artigos em formato passo-a-passo mostrando algumas das principais técnicas 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 compatível com iOS e Android.
No post anterior fomos capazes de:
1. Criar o app;
2. Criar o layout inicial;
3. Desenvolver a navegação base entre as abas;
4. Desenvolver a navegação base entre os formulários da aplicação.
Nessa segunda parte, veremos como criar nosso primeiro protótipo do aplicativo que nos será útil para entender e
definir os aspectos gerais do app. Também veremos:
1. Criação do primeiro protótipo funcional;
2. Criação de dados fictícios com LiveBindings;
3. Ligação dos dados fictícios do LiveBindings com o objetos de t ela, tais como TListView;
4. Montagem das demais telas do sistema utilizando LiveBindings;
5. Uso do serviço Parse.com;
6. Criação de Classe para Login e Senha na nuvem bem como outras funcionalidades;
7. Login e Senha on-line;
8. Modelagem da nossa base de dados SQLite;
9. Introdução ao SQLite e sugestão de ferramentas.

Requisitos:
 Assistir ao vídeo: FireUI – Novo Form Designer RAD Studio XE7
 Assistir ao vídeo: TMultiView no RAD Studio XE7
 Assistir ao vídeo: Aula complemento – Criando meu app step-by-step
 Leitura: Como cadastrar e validar login no serviço Parse.com usando RAD Studio XE6

Assim como mencionado no início desse artigo, no capítulo anterior iniciamos a criação de nosso app a partir do RAD
Studio XE6/Delphi XE6. Nesse capítulo vamos dar continuidade ao nosso desenvolvimento, mas agora com um pouco
mais ênfase em dados e processos reais.
Para começar, espero que tenham assistido aos vídeos indicados na área de requisitos, pois são importantes para
darmos continuidade. Na , logo abaixo, vemos como ficou nosso formulário principal, frmMain, depois da
migração para o RAD Studio XE7.

 __________________________________________________________________________________________
16
 Aplicativo migrado para RAD Studio XE7

O que fizemos aqui foi incluir o novo componente   ao formulário para que tenhamos um menu lateral
automático sem esforço de codificação, assim podemos nos concentrar em coisas ainda mais importantes.
Nessa segunda etapa faremos o  da lista de Títulos para que tenhamos algum dado para exibição. Então
mãos na massa.

Vamos nos concentrar na primeira janela de nosso app, Lista de Títulos. Abra esse Form e adicione a ele um
componente do tipo  da paleta LiveBindings.
#Dica: Para encontrar os componentes de maneira mais rápida, digite o nome do componente no campo de pesquisa
da Tool Palette.

Esse componente nos dá plena condição de criar uma lista fictícia com dados para preenchimento de nossa lista. Agora
adicione também um componente do tipo  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 padrão do Delphi não possui a opção MuiltiRightDetail, por isso assista ao vídeo TMultiView no RAD
Studio XE7 para ver como fazer a instalação desse componente.

Agora clique duas vezes no componente PrototypeBindSource1 e vamos adicionar os campos relacionados ao nosso
protótipo. Com o diálogo aberto, clique no único botão disponível no momento para adicionar o primeiro campo. Uma
nova caixa de diálogo será aberta com duas colunas:  e  Aqui temos todo tipo de dado que pode ser
gerado aleatoriamente pelo Delphi para simular um banco de dados.
Inicie usando o item  Clique nele e no campo logo acima,  digite o valor FOTO. Esse será o
campo para receber a foto do título a ser alugado, ou seja, a capa do DVD.
Repita esse passo adicionando os campos como na

ContactBitmaps ftBitmap Foto


ContactNames ftStrings Titulo

 __________________________________________________________________________________________
17
ContactNames ftStrings SubTitulo
AlphaColors ftUInteger CodTitulo
 Campos do protótipo de títulos

O resultado será semelhante a  onde conseguimos visualizar todos os campos da nossa lista fictícia.

Tabela com campos fictícios do protótipo

Feche a janela e faremos agora a ligação dos campos aos respectivos itens no TListView via LiveBindings. Acesse o
Object Inspector e localize no rodapé dele o item . Caso não o encontre, clique com o direito no formulário
e localize o  no pop-up. Nós veremos uma tela semelhante a

 Bind Visually

O Bind Visually localiza todos os controles da tela e possibilita que liguemos um ao outro para que tenhamos uma
atualização automática sem a necessidade de codificação. 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 opção .
#Dica: Selecione todos os componentes que ficarão ocultos. Clique em cada item com a tecla Ctrl selecionada. Em
seguida clique em um dos controles selecionados com o botão direito do mouse e então 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 Asterísco 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  inclusive com o formulário já mostrando dados fictícios.

 Ligação do LiveBindings

Perceba que um novo componente foi adicionado ao formulário, o  Esse é o componente que possui o link
de cada propriedade e seus campos. Dessa forma já temos uma lista pronta.

Para a janela de usuários, crie um novo formulário usando o menu File>New>Multi-DeviceForm – Delphi.  Modifique
sua propriedade Name para  frmUsuarios  e salve-o como UntUsuarios.   Inclua também 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 sessão anterior para
criar um protótipo com uma lista de usuários. Siga a  com os nomes de campos e tipos de dados.

ContactBitmaps ftBitmap Foto


ContactNames ftStrings Nome
ContactNames ftStrings Apelido
AlphaColors ftUInteger CPF
 Campos do Protótipo de Usuários

 __________________________________________________________________________________________
19
Faremos uso agora do serviço de banco de dados na nuvem chamado Parse.com.  Desde a versão anterior do Delphi,
nós contamos com componentes do tipo BaaS (Backend as a Services). Esse tipo de serviço tem se popularizado
bastante ultimamente.
No início desse artigo, na sessão Requisitos, você encontra um link para um artigo que escrevi falando justamente
disso, portanto não vou me estender muito nesse tópico. Tomarei como verdade que você já entrou no serviço
Parse.com, cadastrou-se e criou sua classe Users  no servidor deles. Não se preocupe, no tutorial informado em
requisitos já há todas as informações necessárias para o cadastramento no serviço.
A partir daqui, crie um novo form que iremos usar como janela de login. Dê o nome a essa janela de frmLogin e salve-
a 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 digitação de usuário 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 (três) 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 também um componente
do tipo TSwitchda paleta Standard.  Configure-o como a seguir:
 Name: swtRegistrar
 Align: Right
 Margins.Right: 10
A segunda e terceira linha conterão os Edits para digitação de login e senha. Altere a propriedade Text  de ambos para
“Usuário” 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 mudando seu nome
para bkendUsuarios.  Localize agora o componente  e adicione-o a tela dando o nome de ppUsuarios.
O primeiro componente adicionado é o componente que se conectará on-line ao serviço e validará nosso usuário e
senha. Já o ppUsuarios receberá as informações de nosso cadastro no serviço, tais como as chaves de acesso
criptografaras. Por isso, conecte o bkendUsuarios  ao ppUsuarios usando a propriedade Provider.
Em ppUsuarios  alimente as propriedades  e com os v alores de sua conta no
serviço . Em caso de dúvidas onde obter tais informações, leia o artigo recomendado em requisitos. Confira
a  como nossa tela deverá se assemelhar.

Modelo de tela de login

 __________________________________________________________________________________________
20
Para que nosso sistema torne-se mais profissional, vamos dar início a criação de uma classe de Login que será utilizada
futuramente por toda a aplicação. A explicação base é simples.
1. Criaremos métodos para efetuar o Login, Logout e Registrar um novo Usuário no Parse.com;
2. Guardaremos a sessão do usuário para que possamos validar mais tarde se ele está ou não logado.
Para isso entre em File>New>UnitDelphi.  Salve essa Unit com o nome Login.pas. No meu caso criei uma pasta no
projeto para guardar todas as nossas classes. Criei com o nome Lib. Agora copie e cole desse tutorial, o código
da  em sua nova Unit.
?
1 unit Login;
2
3 interface
4
5 uses
6 {$Region 'FireDac'}
7 FireDAC.Stan.Intf, FireDAC.Stan.Option,
8 FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf,
9 FireDAC.DApt.Intf, FireDAC.Stan.Async, FireDAC.DApt, FireDAC.UI.Intf,
10 FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Phys, FireDAC.Phys.SQLite,
11 FireDAC.Stan.ExprFuncs, FireDAC.FMXUI.Wait, Data.Bind.EngExt,
12 Fmx.Bind.DBEngExt, FireDAC.Comp.UI, Data.Bind.Components, Data.Bind.DBScope,
13 Data.DB, FireDAC.Comp.Client, FireDAC.Comp.DataSet,
14 {$EndRegion}
15 System.SysUtils, System.Types, System.UITypes, System.Classes,
16 System.Variants, FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs,
17 FMX.StdCtrls, FMX.MobilePreview, System.Rtti,
18 REST.Backend.ServiceTypes, REST.Backend.MetaTypes, System.JSON,
19 REST.OpenSSL, REST.Backend.ParseProvider, REST.Backend.Providers,
20 REST.Backend.ServiceComponents;
21
22 type
23 TLogin = class
24 private
25 FSession : TBackendEntityValue;
26 FSessionStarted : Boolean;
27 FObjBackEndUsers: TBackendUsers;
28 public
29 constructor Create;
30 destructor Destroy;
31 function Login(AUser, APassword: string): Boolean;
32 function Logout: Boolean;
33 function SignUp(AUser, APassword: string): Boolean;
34 published
35 property Session : TBackendEntityValue read FSession write FSession;
36 property SessionStarted : Boolean read FSessionStarted write FSessionStarted;
37 property ObjBackEndUsers: TBackendUsers read FObjBackEndUsers write FObjBackEndUsers;
38 end;
39
40 implementation
41
42 end.
Escopo da classe

Na sessão Uses estamos adicionando toda as units necessárias para a codificação de nossa classe. Peço atenção apenas
agora na definição da classe.
Criamos em a classe sem nenhuma herança, ou seja, TLogin = class. Declaramos FSession do
tipo TBackendEntityValue que receberá a sessão do usuário logado. E uma variável para marcarmos como True/False
sempre que o usuário, respectivamente, fizer login ou logout.
Em seguida declaramos os métodos Create e Destroy para controlarmos a criação e destruição da classe e também o
estado de algumas variáveis. Na seqüência criamos 3 (três) métodos todos devolvendo Boolean, assim podemos testar
na chamada se o método foi executado com sucesso. Explicação dos métodos:

Receberemos como texto o Usuário e Senha digitados nos campos na janela de login. Verificamos se o login e
senha são válidos e inicializamos a sessão usando a variável FSession.
Apenas limpamos a informação da FSession  retornando ao sistema que o usuário não está mais on-line.
Usaremos esse método para cadastrar o usuário on-line sempre que ele marcar o item “Registrar-se”, ou seja,
usuário novo.

 __________________________________________________________________________________________
21
Criamos também duas propriedades, Session e SessionStarted  que dispensam comentários. Apenas uma informação
relacionada a Orientação a Objetos. Internamente nossa classe atualiza as propriedades criadas através das
variáveis FSession e FSessionStarted.  Mas por fora da classe fazemos referência pela propriedade, ou seja:
?
1 if MeuObjetoLogin.SessionStarted then
2 //usuário logado, chama tela XXX
Pressione Ctrl+Shift+C  para criar o escopo dos métodos e codificarmos. Uma propriedade/variável que não expliquei
propositadamente foi FObjBackEndUsers. Essa propriedade será responsável por receber a referência ao
objeto BackEndUserscolocado na tela de login. Assim nossa classe fica genérica e podemos usá-la em qualquer lugar.
Na você pode ver todo o código de cada método.
?
1 constructor TLogin.Create;
2 begin
3 inherited Create;
4 {$IFDEF DEBUG}
5 FSessionStarted := True;
6 {$ELSE}
7 FSessionStarted := False;
8 {$ENDIF}
9 end;
10
11 destructor TLogin.Destroy;
12 begin
13 inherited Destroy;
14 end;
15
16 function TLogin.Login(AUser, APassword: string): Boolean;
17 var
18 tmpSession : TBackendEntityValue;
19 begin
20 try
21 FObjBackEndUsers.Users.LoginUser(AUser, APassword, tmpSession);
22 FSession := tmpSession;
23 FSessionStarted := True;
24 Result := True;
25 except on E:Exception do
26 begin
27 { Erro de usuário e senha }
28 if E.Message.Equals('Parse Error: invalid login parameters (101)') then
29 raise Exception.Create('Usuário ou Senha inválidos!');
30 Result := False;
31 end;
32 end;
33 end;
34
35 function TLogin.Logout: Boolean;
36 begin
37 try
38 FObjBackEndUsers.Users.Logout;
39 FSessionStarted := False;
40 Result := True;
41 except on E:Exception do
42 begin
43 { Erro de usuário e senha }
44 if E.Message.Equals('Parse Error: invalid login parameters (101)') then
45 raise Exception.Create('Usuário ou Senha inválidos!');
46 Result := False;
47 end;
48 end;
49 end;
50
51 function TLogin.SignUp(AUser, APassword: string): Boolean;
52 var
53 Session : TBackendEntityValue;
54 begin
55 try
56 { Valida se nome de usuário já existe na base }
57 FObjBackEndUsers.Users.QueryUserName(AUser, Session);
58 if Session.ObjectID.IsEmpty then
59 begin

 __________________________________________________________________________________________
22
60 { Cria o usuário já fazendo login na sessão }
61 FObjBackEndUsers.Users.SignupUser(AUser, APassword, nil, FSession);
62 ShowMessage('Usuário e Senha cadastrado com sucesso!');
FSessionStarted := True;
Result := True;
end
else
begin
ShowMessage('Nome de Usuário já existe. Por favor escolha outro!');
Result := False;
end;
except on E:Exception do
raise Exception.Create('Erro de internet!' + E.Message);
end;
end;
Codificação final da classe

Vamos entender agora o que estamos fazendo na classe começando pelo método construtor Create. Nele estamos
usando uma diretiva de compilação para não atrapalhar nossos testes no futuro. Caso a aplicação tenha sido compilada
em Debug, marcamos a sessão como Iniciada, assim não seremos obrigados a digitar usuário e senha toda hora. Caso
contrário, o sistema já inicia como sessão não iniciada.
Em seguida temos o método  recebendo usuário e senha em formato Texto (String). Nosso código aqui é bem
simples. Chamamos a função LoginUser presente no objeto  Passamos para a função o Usuário e a Senha
passados por parâmetro bem como uma variável temporária de Sessão declarada nesse métodos. A
função LoginUser  valida o usuário e a senha e devolve a informação para a sessão temporária. Caso o usuário e a senha
não existam on-line, uma exceção será gerada com o erro: ParseError:invalidloginparameters(101) . Existem milhares
de formas de testar, mas acabei fazendo na maneira mais simples possível.
Caso o usuário e senha tenham sido validados com sucesso, as variáveis FSession e FSessionStarted são atualizadas e
devolvemos Result := True informando que o método obteve sucesso.
  é o método mais simples. Apenas chamamos a função de mesmo nome contida no objeto BackendUsers e
atualizamos as respectivas variáveis.
Por fim, SignUp, acredito que o método mais inteligente da classe. Primeiro nós chamamos a
função QueryUserName passando o usuário recebido e uma sessão temporária. Se a Sessão temporária estiver vazia
na propriedade ObjectID,  significa que o usuário passado não existe na base. O ObjectID na verdade é o campo de
chave primária da tabela Users  no serviço Parse.com  e é alimentado sempre que cadastramos um novo usuário.
Estando vazia, então chamamos o método SignupUser passando o usuário e senha informados nos campos da janela.
Assim o usuário será cadastrado e logo em seguida iniciamos a sessão do usuário.
Caso o ObjectID esteja preenchido, significa que o usuário já existe no banco, então pedimos ao usuário para informar
um apelido diferente.

Perfeito! Até aqui nenhum problema. Agora precisamos usar a classe, ou seja, efetivamente chamar os métodos
necessários para efetuar o login. A primeira providência é criar a classe em runtime e como precisaremos dela em
vários lugares, vamos cria-la na abertura do sistema. Acesse o evento OnCreate do formulário principal e digite o código
abaixo:
?
1 FLibLogin := TLogin.create;

Na sessão do form adicione a variável FLibLogin do tipo TLogin (usada no código anterior) e dê umUse
Unit  no Login.pas adicionando a unit ao UsesdaInterface. Assim passaremos a partir de agora a usar a unit da Classe.
Nosso formulário principal é o primeiro a ser iniciado, portanto é o único que fará referência direta a Login.pas por
enquanto. para acessar as propriedades da classe, usaremos algo como:
?
1 frmMain.FLibLogin.PROPRIEDADE (ou método)
Retorne agora a nossa janela de Login, frmLogin. Aqui precisaremos apenas codificar o botão de login, speLogin.  Digite
nele o código abaixo:
?
1 frmMain.FLibLogin.ObjBackEndUsers := bkendUsuarios;
2 case swtRegistrar.IsChecked of

 __________________________________________________________________________________________
23
3 true : frmMain.FLibLogin.SignUp(edtUsuario.Text, edtSenha.Text);
4 false : frmMain.FLibLogin.Login(edtUsuario.Text, edtSenha.Text);
5 end;

Imagino que já tenham entendido ;). Caso o Swtich esteja marcado, significa que o usuário deseja cadastrar-se no
sistema, portanto chamamos o método de cadastro da nossa classe, caso contrário nosso Login. Perceba que apenas
chamamos os métodos e não fazemos desvios, ou seja, o correto seria:
Caso o usuário consiga se cadastrar ou fazer o login, devemos chamar o click do menu Titulos para que carreguemos a
Listagem de Títulos ou poderíamos chamar qualquer tela.
Para não nos estendermos mais nesse tópico, deixo a cargo do leitor fazer os respectivos desvios.
Obs. Na primeira linha do código alimentamos a propriedade ObjBackendUsers passando como referência o objeto em
rela.

Para que possamos prosseguir com nosso aplicativo, vamos iniciar também 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
O SQLite é apenas um dos bancos de dados que podem ser utilizados em dispositivos móveis. Também é possível
usarmos IBLite, uma versão reduzida do Intebase da Embarcadero. Para saber mais sobre SQLite, você pode acessar o
site http://www.sqlite.org que possui uma vasta documentação.
Com ele podemos realizar diversas tarefas, pois apesar de compacto, é um banco bastante completo.
Existem milhares de ferramentas na internet para fazer a manutenção e criação de bancos SQLite e uma delas é
o e pode ser baixado em www.sqliteexpert.com.  Existem basicamente duas
versões, Express e Professional  e claro, utilizado a versão Express que é gratuita e já ajuda bastante. Tomarei ele como
base então para nosso artigo.
Outra ferramenta importante para mantermos uma documentação de nosso banco é o   uma ferramenta de
modelagem FREE, simples e objetiva. Ele pode ser encontrado e baixado em http://dia-installer.de. Minha sugestão é
baixar a versão Full, pois existe a versão Portable no baixaki.com.br, mas não é legal.
Acesse a ferramenta DIA abra-a em seu equipamento. Não entraremos em detalhes sobre o DIA, então resumirei suas
características.
Com o DIA aberto, , observe na barra lateral a opção Fluxograma.   Clicando nessa opção e em seguida
em OutrasFolhaspodemos ver que há inúmeros fluxogramas que podemos utilizar para desenhar nossa solução. Utilize
a opção Bancos de Dados, assim nós podemos incluir nossas entidades. Por enquanto vamos criar somente a tabela de
Títulos.

 DIA Modelagem

Arraste um objeto do tipo Entidade para a área branca e clique duas vezes nela para abrir a caixa de propriedades.
Nessa janela inclusa o nome da nossa tabela, TITULOS e então clique em Atributos.
Nessa área podemos incluir todos os campos da tabela. Comece incluindo como na

 __________________________________________________________________________________________
24
ID_TITULO Integer AutoInc / Chave Primária
TITULO String 30 Não Nulo
SUBTIULO String 50
ANO_LANCAMENTO Integer Não Nulo
 Tabela TITULOS do banco de dados
A aparência de nossa entidade deverá se parecer com a .

 Entidade TITULOS

A partir de agora, faremos sempre a modelagem de dados de nossa app através dessa ferramenta para criar nossas
entidades e deixar sempre uma documentação atualizada.
Vamos agora replicar isso no SQL Expert criando o banco e a tabela. Abra a ferramenta e clique em File>New>
DataBase. Informe o caminho e o nome do banco de dados. Minha sugestão é que salvemos o banco no mesmo
diretório da aplicação em uma pasta com o nome Database. O nome do banco de dados poderá ser Locadora.sqlite . O
restante dos campos podem ser deixados como Default.
Em seguida clique com o direito no nosso banco de dados e em seguida em NewTable. Em TableName digite TITULOS.
Logo abaixo, você encontra algumas abas onde podemos incluir nossos campos, índices, chaves estrangeiras, etc. Bem
abaixo encontraremos o botão Add, para criar um novo campo.
Clique em Add e adicione o primeiro campo, ID_TITULO do tipo INT. Nós vamos controlar o auto incremento da tabela
através de triggers no próximo artigo, portanto não se preocupe por enquanto. Continue criando a tabela utilizando
nossa entidade na modelagem. Observe a como deverá ser concluída a criação da tabela TITULOS.

 Tabela TITULOS criada.

Na próxima fase de nossa série de artigos, aprofundaremos melhor no banco de dados e faremos a ligação do banco
ao nosso sistema utilizando
Salve o banco de dados e o diagrama de modelagem.

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 criação do banco de dados local e fizemos, claro, a migração do
aplicativo da versão RAD Studio XE6 para XE7.

 __________________________________________________________________________________________
25
No post anterior iniciamos uma das partes mais importantes de nosso aplicativo mobile com RAD Studio, o banco de
dados. Aprendemos a iniciar a criação de nosso banco utilizando o SQLite, banco bastante popular em aplicações
móveis, 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:
1. Migrar nossa aplicação de Delphi XE6 para XE7;
2. Recriar o menu lateral utilizando o novo componente TMultiView;
3. Criar uma tela inicial de login;
4. Criar nosso primeiro banco de dados SQLite;
A terceira parte desse tutorial será um pouco mais curta, mas rica em detalhes. Vermos a seguir:
1. Criação do DataModule principal;
2. Configuração dos principais componentes de acesso ao banco de dados;
3. Criação dos métodos de listagem de Titulos e Detalhes dos Titulos;
4. Montagem das telas funcionais.

Requisitos:
 Leitura: Tutorial: Criando meu app step-by-step – Parte II
 Assistir ao vídeo: TDevRocks – Binding vs TListViews

Assim como mencionando anteriormente, iniciamos a criação 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

Tabela TITULOS

Nota-se que criamos um campo chamado , que receberá, evidentemente, um ID auto numérico para
representar o registro. Existem “n” possibilidades para se fazer um numerador, inclusive
com  e  no banco, mas eu prefiro ter o controle da situação e fazer isso direto no código-
fonte. Por isso criaremos uma função para nos retornar o ID do título.
Assim como em aplicações Desktop, é possível criar DataModules para separar nossos componentes visuais de
componentes de acesso a dados. Inicie essa etapa entrando em File>>New>Other  e escolhendo a opção Data Module
no item DelphiFiles . Dê o nome a esse Data Module de “DM” e salve sua unit como UntDM.pas.
Usaremos a partir daqui os componentes da paleta FireDAC, tais como  e O primeiro
componente a entrar no ar será o TFDConnection, insira um no DM e renomeie-0 para  fdcConexao. Após isso clique
duas vezes nesse componente e observe a caixa de diálogo que se abre ( ).

 __________________________________________________________________________________________
26
Diálogo de configuração do banco

Nessa janela somos capazes de fazer todo tipo de configuração relacionada ao banco a ser conectado. Na parte superior
encontramos o campo DriverID e ConnectionDefinitionName.  Em DriverID podemos ver que o FireDAC é compatível
com diversos bancos, entre eles DB2, Firebird (FB), Interbase (IB), SQLServer (MSSQL), Oracle (ORA), entre outros
tantos. Mas não se confunda. Atualmente os únicos bancos de dados que podem ser executados no dispositivo móvel
(até o fechamento desse artigo, claro) são IBLite que é uma versão reduzida do Interbase para Mobile e o SQLite, que
estamos tratando aqui. O fato, por exemplo, de termos acesso a Firebird, não significa que ele rodará em nosso
dispositivo, o que tem causado bastante confusão em algumas pessoas.
Se você já tem um vínculo com nosso SQLite através do DataExplorerdoDelphi  (Janela ao lado direito do Delphi) então
podemos vê-lo e seleciona-lo nessa caixa. Por hora apenas selecione SQLite em Driver ID.

Em seguida a única configuração que faremos é informar o caminho e nome do banco de dados ao FireDAC na
propriedade Database. Em nosso exemplo, o banco está na pasta raiz do código-fonte na pasta Database. Algo como:
C:\tutorial\Database\Locadora.sqlite
Observe onde você salvou seu banco para poder indicar o caminho correto. Para ter certeza que está tudo bem, clique
em Test para ver se conecta-se ao banco. Uma mensagem como na deverá aparecer.

Conexão com sucesso

Provavelmente se compilarmos o app nesse momento, nenhum problema será detectado, mas é provável que
recebamos algumas mensagens de erro ao executar o app no Windows ou no dispositivo. Isso porque ainda precisamos
declarar algumas units ou, mais fácil, incluir dois novos componentes que fazem o papel final de configuração do app.
Insira um FDGUIxWaitCursor e n FDPhysSQLiteDriverLink. Não é necessária nenhuma configuração adicional. São na
verdade os componentes que fazem o link final com o banco, não entrarei em detalhes. Por fim, desative a propriedade
Login Prompt do fdConexao.
 __________________________________________________________________________________________
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 código SQL.

?
1 SELECT
2 ID_TITULO,
3 TITULO,
4 SUBTITULO,
5 ANO_LANCAMENTO
6 FROM
7 TITULOS

Não entrarei em detalhes sobre instruções SQL, tomarei como verdade que t odos tem o mínimo de noção sobre o SQL.
Estamos fazendo aqui uma simples seleção de dados, apenas trazendo os campos da tabela. Caso deseje, também é
possível clicar duas vezes no componente Query e abrir a janela de edição de SQL. Inclusive é possível fazer o teste de
retorno de dados para verificar se a instrução está correta.
Após ter digitado a instrução, 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 mínimo de Delphi, não há novidades. Se preferir acesso campo a campo e modifique a
propriedade DisplayFormat inserindo nomes mais amigáveis para cada campo da tabela.

Evidentemente temos que distribuir e abrir o arquivo de banco de dados sempre que a aplicação se abre. Para isso
costumo codificar diretamente no evento OnCreate do Data Module usando o código da

?
1 procedure TDM.DataModuleCreate(Sender: TObject);
2 begin
3 with fdcConexao do
4 begin
5 {$IF DEFINED (IOS) || (ANDROID)}
6 Params.Values['DriverID'] := 'SQLite';
7 try
8 Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'Locadora.sqlite');
9 Connected := True;
10 except on E: Exception do
11 begin
12 raise Exception.Create('Erro de conexão com o banco de dados!');
13 end;
14 {$ENDIF}
15
16 {$IFDEF MSWINDOWS}
17 try
18 Params.Values['Database'] := 'P:\tutoriais-tdevrocks\Curso-Completo\Parte III - SQLite\Database\Locadora.sqlite';
19 Connected := True;
20 except on E: Exception do
21 begin
22 raise Exception.Create('Erro de conexão com o banco de dados!');
23 end;
24 {$ENDIF}
25 end;
26 end;
Abertura do banco de dados
O que estamos fazendo aqui é algo relativamente simples. Vamos lá. Primeiro note que utilizei a palavra reservada
WITH. Para quem não conhece, os iniciantes claro, essa palavra reservada permite que não precisemos mais digitar
repetidas o nome de um objeto no bloco, exemplo:
Ao invés de usarmos toda hora:
?1 fdcConexao.Params.Values.['DriverID']...
2 fdcConexao.Params.Values['Database']...
3 fdcConexao.Connected := True;

Nós simplesmente envolvemos o bloco inteiro com um:


?1 with COMPOENTE do
Para mais de um componente, podemos incluir vírgulas:
?1 with fdcConexao, qryTitulos, frmPrincipal do
 __________________________________________________________________________________________
28
2 ...
Perceba inclusive que incluímos no exemplo anterior, frmPrincipal, ou seja, também são aceitos formulários.
Muito bem, estamos atualizando o parâmetro DriverID com o nome do driver de nosso banco, ou seja, SQLite. Em
seguida atualizamos o parâmetro com o nome caminho completo do banco. Atenção apenas para alguns detalhes.
Estamos usando Diretivas de Compilação para desviar o código de acordo com a plataforma.
?1 {$IF DEFINED (IOS) || (ANDROID)}
Se for iOS ou (||) Android usamos TPath.Combine e TPath.GetDocumentsPath. Ambos os métodos pertencem ao
namespace System.IOUtils, portanto declare essa unit na seção Interface da unit.
 TPath.Combine: Responsável por concatenar duas strings de endereço. Ele já faz o trabalho de descobrir, por exemplo,
qual barra utilizar, já que há diferença entre iOS, Android e Windows;
 TPath.GetDocumentsPath: Descobre qual o endereço da pasta Documents no dispositivo móvel.
Sempre utilize esses dois métodos para buscar e concatenar diretórios no Mobile.
Por fim de tudo, conectamos ao banco de dados usando um Connected := True;
Envolvemos tudo isso em um Try…Except para evitar que algum problema aconteça sem que possamos notificar o
usuário.

É hora de colocarmos dados reais no nosso aplicativo, por isso faremos agora o Binding da primeira tabela real,
TITULOS. Na primeira parte desse artigo, já incluímos um FDQuery ao Data Module e codificamos a instrução SQL para
trazer os dados de TITULOS. Agora precisamos ler essas informações em u TListView. Para isso, abra nosso formulário
de títulos frmTitulos.pas.
Faça com que ele tenha vínculo com nosso Data Module usando o menu File >> Use Unit e escolhendo o DM. Ao fazer
isso, conseguiremos visualizar tanto o TListView quando o BindSource na janela Bind Visually ( ).

Bind Visually de Títulos

Além disso, teremos que tomar outra providência: abrir a tabela Títulos. Faremos isso, por enquanto, no menu,
portanto retorne ao frmMain, clique duas vezes no ListBoxItem correspondente ao nosso Menu Títulos e clique duas
vezes para visualizarmos o código-fonte.
Adicione o código das linhas a seguir:
?
1 DM.qryTitulos.Active := False;
2 DM.qryTitulos.Active := True;
Estamos fechando e abrindo novamente a tabela para forçar um “refresh”. Não esqueça de fazer um Use Unit nesse
form, já que ele ainda não enxerga nosso Data Module.
Em outro momento faremos uma codificação para formar o DisposeOf dos formulários não visíveis em tela, evitando
que tenhamos memória desnecessária sendo desperdiçada. Nesse momento transferiremos o código de abertura das
queries para o Form Create de cada tela.
Antes de testar a aplicação, acesse o menu Project >> Options e em Form modifique a ordem de criação do frmMain e
do DM como mostrado na . Estamos ainda sem foto para os títulos, que deverão aparecer ao lado esquerdo
do TListView.

 __________________________________________________________________________________________
29
Ordem de criação dos formulários

Montaremos agora uma aba para mostrar os detalhes do nosso Título. Para isso adicione uma nova aba ao TabCtrl de
Clientes clicando com o botão 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 também suas
margens para 8px em todos os lados.
Ainda na primeira linha do ListBox, adicione um TLayout e dentro dele 2 (Labels). Eles serão nosso Título e SubTítulo
respectivamente. Eles devem receber o Name e o Text como abaixo, assim como outras propriedades:

 Name: lblTitulo
 Text: lblTitulo
 StyleLookup: listboxitemlabel
 Align: Top
 Margins.Right: 8
 Margins.Top: 8

 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 Lançamento.
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 botão será responsável por voltar a listagem de títulos. Agora sim marque o ListBox como Client e vamos ver o
resultado. Nossa janela deverá possuir uma aparência semelhante a da .

 __________________________________________________________________________________________
30
Exemplo de tela de detalhes

O que acabamos de fazer foi criar o layout de nossa janela de detalhes de uma maneira mais profissional. Agora, basta
entrar novamente na Bind Visually e ligar os respectivos lables aos campos da base de dados. Apenas um detalhe aqui.
A segunda linha do ListBox terá a propriedade Text ligada ao campo ANO_LANCAMENTO no Binding, entretanto essa
propriedade não aparece por Default, portanto localize o item de listbox na janela de Binding e clique no botão
reticências dele, assim uma nova caixa de diálogo será aberta e basta marcarmos a propriedade Text e clicar em OK. O
único que ainda não será ligado é o imgFoto, pois ainda não temos um campo de foto no banco de dados. Veja como
todos os campos ficam ligados na .

Também não queremos que as abas na parte inferior sejam mostradas para o usuário final, então deixaremos elas na
tela apenas em tempo de projeto para nos ajudar a desenhar e fazer as devidas manutenções. Mas em runtime
sumiremos com elas assim como marcaremos como default a aba de Listagem. Entre no evento OnCreate desse form
e digite o código a seguir:

?
1 tabctrlTitulos.TabPosition := TTabPosition.None;
2 tabctrlTitulos.ActiveTab := tbitemLisTitulos;

 __________________________________________________________________________________________
31
Bem simples não? Estamos mudando a propriedade TabPosition para None, assim as abas não aparecerão. E também
configuramos a ActiveTab como sendo a listagem. Retorne agora para a aba principal e selecione o evento OnItemClick
do TListView. Digite o código para passar para a aba de Detalhes:
?
1 tabctrlTitulos.Next;
Um último retoque. Se executarmos agora o aplicativo, veremos que no lugar de “Ano Lançamento” aparece apenas o
Ano, e o texto some. Então clique duas vezes no componente BindinsList1 e em seguida selecione o link correspondente
ao Item de ListBox do Ano de Lançamento, provavelmente será o último. Pressione F11 para abrir o Object Inspector
e selecione o campo CustomFormat. Digite na propriedade o texto a seguir:
?
1 'Ano Lançamento: ' + %s
Isso fará com que concatenemos a palavra ‘Ano Lançamento” 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  como
ficou nossas alterações nessa terceira parte.

Nessa terceira parte de nosso tutorial, vimos como implementar o uso de tabelas reais de um banco SQLite para
carregar informações em um TListView. Vimos também como facilmente criar um Layout para mostrar os detalhes de
um item do ListView, nesse caso um Item selecionado pelo usuário final.
Na próxima etapa, veremos como fazer o primeiro CRUD (Funções de Inclusão, Exclusão e Alteração de Dados) no
banco de dados.

 __________________________________________________________________________________________
32
Chegamos a Parte IV de nosso Tutorial: Criando meu app step-by-step em RAD Studio XE7. No capítulo anterior, mais
curto que os demais, aprendemos a montar nossa tela de Listagem de Títulos conectada em dados reais através de um
banco de dados SQLite. Nós fizemos a navegação, vinculamos o banco ao projeto e deixamos tudo preparado para
iniciarmos a parte de Inclusão, Exclusão e Alteração de títulos. Confira abaixo:
1. Criação do DataModule principal;
2. Configuração dos principais componentes de acesso ao banco de dados;
3. Criação dos métodos de listagem de Titulos e Detalhes dos Titulos;
4. Montagem das telas funcionais.
Nessa nova etapa veremos como implementar o CRUD (Create, Read, Update e Delete, ou seja, Inserção, Leitura,
Atualização e Exclusão) em nosso aplicativo. Vejamos a pauta:
1. Criação de campo do tipo imagem na tabela de Títulos;
2. Criação de método para auto-numerar ID de Títulos;
3. Binding da imagem com as listagem e detalhes do Título;
4. Inclusão, Alteração e Exclusão de Títulos;
5. Seleção de fotos da biblioteca ou câmera;

Requisitos
 Leitura: Tutorial: Criando meu app step-by-step parte III;
 Assistir ao vídeo: TDevRocks – Binding vs TListViews

Nossa sessão Retomando o raciocínio de hoje tem a ver com o que fizemos até o presente momento. No capítulo
anterior nós iniciamos, como dito anteriormente, com uma parte crucial: inclusão de dados reais. Entretanto deixamos
para trás duas coisas:
1. Auto-numeração do ID de Títulos;
2. Criação do campo Foto;
A foto será usada para mostrar a capa do título, DVD, em questão. Tanto no TListView quanto em detalhes. E no caso
do ID do título, como vamos ter outros numeradores, vamos criar uma função 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
necessário.

Vamos começar abrindo o SQLite Expert e alterando nossa tabela TITULOS. Clicando em TITULOS acesse a aba Design
e em seguida clique em ADD na parte inferior para adicionarmos um novo campo. Digite FOTO no campo Name e
IMAGE no Type para escolhermos o tipo de dado

Criando o campo FOTO


 __________________________________________________________________________________________
33
Feito isso, teremos que alterar a instrução 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 instrução assim como na
?
1 SELECT
2 ID_TITULO,
3 TITULO,
4 SUBTITULO,
5 ANO_LANCAMENTO,
6 FOTO
7 FROM
8 TITULOS
. Select alterada de TITULOs

Agora precisamos adicionar o novo campo a lista de campos Fields Editor do qryTitulos. Para isso clique com o botão
direito do mouse do componente e selecione Fields Editor. Com o direito na pequena janela que aparece, clique em
Add Fields. Isso fará com que o campo FOTO apareça.
#Dica: Certifique-se de que abriu o banco Locadora.sqlite correto no SQLite Expert e que o banco apontado na
propriedade Database no FDConnection também esteja apontado para o banco que sofreu a alteração, do contrário
nosso campo não aparecerá na janela.
Muito bom até aqui, precisamos somente fazer o binding do novo campo com os componentes de imagem da tela de
títulos frmTitulos.

Há quem prefira salvar as fotos em uma pasta específica. Também prefiro, mas depende muito do tipo de aplicação.
Nesse caso prefiro salvar direto no banco, já que seria mais chato fazer o binding com as fotos soltas no device. Esse
processo é tão simples quanto o que fizemos no capítulo anterior.
Acesse a janela frmTitulos e em seguida acione o Bind Visually. Selecione o TListView correspondente a lista de títulos
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 não apareça a propriedade Bitmap em qualquer dos casos, clique nas reticências do objeto que deseja
fazer a ligação do Binding, e localize a propriedade desejada na caixa de diálogo. Marque-a e então ela aparecerá no
bind.
Pronto! A primeira parte do binding está finalizada. O que precisamos fazer agora é preparar a parte de codificação
para que possamos possibilitar mudar a foto do item na lista. Veja as ligações dessa sessão na

 __________________________________________________________________________________________
34
Binding de fotos

Na Parte II nós fizemos a codificação para vincular nosso banco de dados em runtime no evento OnCreate do
DataModule, mas acabei publicando um erro na utilização de diretivas de compilação que só notei com o início dos
testes nesse capítulo. No OnCreate utilizamos a seguinte linha:
?
1 [...]
2 {$IF DEFINED (IOS) || (ANDROID)}
3 [...]
Quando na verdade o correto seria:
?
1 [...]
2 {$IF DEFINED(IOS) OR DEFINED(ANDROID)}
3 [...]
Alguns leitores também reclamaram que ao passar pela linha Connected := True, o banco dados não abre e ainda indica
um erro na aplicação, que está relacionado a uma configuração não passada no capítulo III. Clicando duas vezes do
componente FDConnection (fdConexao), repare que em nossas configurações existe uma propriedade chamada
OpenMode que está setadacomo CreateUTF8. Troque-a para ReadWrite. Isso se faz necessário, pois estamos
distribuindo o banco de dados SQLite e não criando-o em runtime.
Em outras palavras, já temos o banco de dados criado e faremos a distribuição dele quando fecharmos a aplicação para
a loja ou para nossos testes no device. Para que não fique totalmente confuso, observe a que contém o
código completo corrigido.

 __________________________________________________________________________________________
35
?
procedure TDM.DataModuleCreate(Sender: TObject);
var
sPath: String;
1
begin
2
with fdcConexao do
3
begin
4
{$IF DEFINED(IOS) OR DEFINED(ANDROID)}
5
Params.Values['DriverID'] := 'SQLite';
6
Params.Values['OpenMode'] := 'ReadWrite';
7
try
8
sPath := TPath.Combine(TPath.GetDocumentsPath, 'Locadora.sqlite');
9
Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'Locadora.sqlite');
10
Connected := True;
11
except on E: Exception do
12
begin
13
ShowMessage(E.Message);
14
end;
15
end;
16
{$ELSE}
17
try
18
Params.Values['Database'] := 'CAMINHO_DO_BANCO_DE_DADOS\Database\Locadora.sqlite';
19
Connected := True;
20
except on E: Exception do
21
begin
22
ShowMessage(E.Message);
23
end;
24
end;
25
{$ENDIF}
end;
end;
Código do evento OnCreate do DataModule corrigido
Fonte de estudo clique aqui.

Há inúmeras maneiras de fazemos a edição dos dados em tela, portanto faremos a princípio na maneira mais simples
e objetiva possível. Vá até a aba Detalhes do Título e adicione três novos speedbuttons. Eles farão o trabalho de Editar,
Salvar e Cancelar uma edição. 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 botões possuem a propriedade Visible segadacomo False. Isso porque vamos deixa-los como
visíveis de acordo com a situação. Criaremos um método para fazer esse trabalho. Por isso crie uma nova procedure
na seção Public do formulário e codifique como na

 __________________________________________________________________________________________
36
?
procedure TfrmTitulos.AtualizarBotoes;
1
begin
2
spbVoltar.Visible := (DM.qryTitulos.State = dsBrowse);
3
spbEdicao.Visible := (DM.qryTitulos.State = dsBrowse);
4
5
spbCancelar.Visible := (DM.qryTitulos.State in dsEditModes);
6
spbSalvar.Visible := (DM.qryTitulos.State in dsEditModes);
7
end;
Ativa e Desativa botões
Muito bom, agora precisamos apenas fazer as devidas chamadas ao método AtualizarBotoes. A princípio podemos
colocar nos eventos OnCreate do formulário de Títulos e também no OnItemClick do ListView de listagem de títulos,
assim quando o usuário tocar em um título para ver os detalhes, os botões ficarão disponíveis para a edição. No evento
OnClick de cada botão novo teremos que codificar para fazer a edição do registro selecionado. O código é bem simples.
Veja a com toda a seqüência de código de cada botão.
?
procedure TfrmTitulos.spbCancelarClick(Sender: TObject);
begin
1
DM.qryTitulos.Cancel;
2
AtualizarBotoes;
3
end;
4
5
procedure TfrmTitulos.spbEdicaoClick(Sender: TObject);
6
begin
7
DM.qryTitulos.Edit;
8
AtualizarBotoes;
9
end;
10
11
procedure TfrmTitulos.spbSalvarClick(Sender: TObject);
12
begin
13
DM.qryTitulos.Post;
14
AtualizarBotoes;
end;
Código dos botões de edição
Para quem é mais experiente, esse código realmente é simples ao extremo. Claro que poderíamos fazer uma série
de checks para evitar que o usuário deixe de preencher um determinado campo, tratamentos de erro, etc. Mas por
enquanto faremos o mais grosso da programação. Com isso codificado, já podemos testar nossa aplicação.
Ao tocar no botão Editar, os botões Salvar e Cancelar devem aparecer e o botões Editar e Voltar devem sumir, assim o
usuário somente poderá Salvar ou Cancelar a ação.
Para tirarmos uma foto ou escolhermos da biblioteca, usaremos ações do TActionList. Por isso adicione ao formulário
um TActionList, dê o nome de AcoesGeral e clique duas vezes nele. Na janelinha que se abre clique na setinha preta
que aparece ao lado botão de criação de novas ações ( .

 Criando nova ação

 __________________________________________________________________________________________
37
 Criando nova ação

Fiz o print das telas propositadamente com o cursor selecionado na opção Media Library. Essas são ações prontas do
Delphi. Na seqüência vemos:
 TTakePhotoFromLibraryAction
 TTakePhotoFromCameraAction
 TShowShareSheetAction
As duas primeiras são usadas respectivamente para selecionar uma foto da Galeria (Android) ou Biblioteca (iOS) e a
segunda é usada para tirar uma novo nova. A terceira opção é usada para invocar a tela de compartilhamento nas
redes sociais, etc.
Adicione uma ação para Câmera e outra para Biblioteca. Chame-as de actFotoCamera e actFotoBiblioteca. Depois de
criadas nós podemos clicar na ação e acessar suas propriedades e eventos. O que precisamos aqui é só do evento
OnDidFinishTaking, que será codificado por nós. Clique duas vezes nesse evento para a ação actFotoCamera.
Esse evento ocorre logo depois da captura da foto, ou seja, após o usuário tirar a foto e escolher usa-la. Nós
carregaremos a foto diretamente para o campo FOTO em nosso banco de dados. Para isso apenas digite no evento:
?
1 DM.qryTitulosFOTO.Assign(Image);
O parâmetro Image vem do próprio evento e é carregado automaticamente pelo Delphi após a captura de foto. Essa
mesma linha pode ser digitada no mesmo evento para a segunda ação, faça isso.
Se você escreveu os código corretamente para cada botão como indicado mais acima, então até aqui não teremos
problemas e tudo estará funcionando perfeitamente.
Retornaremos em breve aqui, pois teremos que codificar o momento certo de chamar esses métodos.

No início no post mencionei que iríamos montar uma função para gerar automaticamente nossos IDs, e é isso que
faremos agora. Algo relativamente simples e que nos ajudará com o reaproveitamento de código. Acesse nosso
DataModule e crie uma nova function na seção Public no formulário.

?
1 function GetIDFromTable(ATable: String) : Integer;
Pressione Ctrl + Shift + C para que o Delphi crie o escopo no método e então digite o código da 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 espécie 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 instrução SQL assim:

?
1 SELECT MAX(ROWID)+1 AS NEW_ID FROM TITULOS
Resultaremos o valor do campo NEW_ID.

?
function TDM.GetIDFromTable(ATable: String): Integer;
1 const
2 _SQL = 'SELECT MAX(ROWID)+1 AS NEW_ID FROM %s';
3 begin
4 with qryAuxiliar1 do
5 begin
6 Active := False;
7 SQL.Clear;
8 SQL.Text := Format(_SQL, [ATable]);
9 Active := True;
10 Result := FieldByName('NEW_ID').AsInteger;
11 end;
end;
 Gerando ID da tabela
Também peço que altera a instrução SQL da query qryTitulos incluindo o campo ROWID no início da select e também
incluindo seu campo no Fields Editor. Consulte a parte II desse tutorial para ver como faz caso tenha dificuldades. Por
fim adicione um novo componente query a tela chamando-o de qryAuxiliar1. Todas instruções SQL que precisarmos
fazer e que sejam temporárias, usaremos esse componente.
Agora retorne ao frmTitulos e acessa a primeira aba, a de listagem dos Títulos. Crie um novo speedbutton na tela
dentro de nossa barra de ferramentas superior. Alinhe esse botão a direita com Margem Direita igual a 8px. Selecione
o StyleLoookup addtoolbutton para termos um botão de adição de novo título.
Esse botão deverá fazer algo bem simples.
 Chamar o método de atualização dos botões em tela;
 Adicionar um novo registro a tabela Títulos;
 Chamar a Aba de Detalhes.
A aba de detalhes deverá receber uma alteração grande agora, pois não temos onde digitar os valores Título, SubTítulo
e Ano de Lançamento, pois colocamos apenas Labels nessa tela. Portanto faremos a troca desses labels por Edits.
Troque os três labels por edits, na seqüência: edtTitulo, edtSubTitulo e edtAnoLancamento. Refaça o Binding, você
ligará novamente cada campo da tabela aos respectivos edits. Você já sabe fazer isso, basta consultar os demais
tutoriais ou o vídeo sobre Binding disponível em nosso YouTube.
Veja como deve ficar seu Layout nas

Exemplo de Tela

 __________________________________________________________________________________________
39
Exemplo de Tela

Exemplo de Tela

A mágica é simples. Quando entrarmos em modo de Edição ou Inserção, mudaremos a propriedade Enabled de cada
controle para aceitar nossas digitação. Quando estiver em modo Browse, ou seja, apenas visualização, os edits ficaram
desativados. Mas além disso mudaremos também o StyleLookup de cada controle para que fiquem transparentes,
dando a impressão de Labels.
Retorne a nossa função AtualizarBotoes e acrescente o código da

?
edtTitulo.Enabled := (DM.qryTitulos.State in dsEditModes);
1 edtSubTitulo.Enabled := (DM.qryTitulos.State in dsEditModes);
2 edtAno.Enabled := (DM.qryTitulos.State in dsEditModes);
3
4 if (DM.qryTitulos.State in dsEditModes) then
5 begin
6 edtTitulo.StyleLookup := 'editstyle';
7 edtSubTitulo.StyleLookup := 'editstyle';
8 edtAno.StyleLookup := 'editstyle';
9 end
10 else
11 begin
12 edtTitulo.StyleLookup := 'transparentedit';
13 edtSubTitulo.StyleLookup := 'transparentedit';
14 edtAno.StyleLookup := 'transparentedit';
end;
Complemento do código
Repare que igualamos a propriedade Enabled ao estado da tabela. E ainda modificamos o StyleLookup dos
componentes. Pronto, precisamos apenas fazer a chamada do código para inclusão de títulos.
Retorne a aba principal e clique duas vezes em nosso botão ‘+’. Digite o código a seguir:
?

 __________________________________________________________________________________________
40
1 DM.qryTitulos.Append;
2 tabctrlTitulos.Next;
3 AtualizarBotoes;
Não dá para ser mais simples que isso. Append para criar um novo registro, mudamos para a aba de detalhes e
atualizamos os botões que consequentemente também ativará os edits para inclusão de dados.

Nós preparamos nosso código para ativarmos a câmera ou a biblioteca de fotos, mas não fizemos as devidas chamadas
ainda. Faremos o seguinte: quando o usuário tocar na foto na tela de detalhes, então acionaremos um pop-up menu e
perguntaremos o que o usuário deseja fazer:
 Nova Foto;
 Biblioteca
 Cancelar
Desse modo, cada item do pop-up chamará uma determinada ação. Para fazer esse menu usaremos um artifício bem
comum, um ListBox. Isso mesmo! Insira um ListBox na tela e clique duas vezes nele para adicionar itens. Crie três 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 critério. Também é importante modificar a altura de
todos os itens, use a propriedade ItemHeight do próprio ListBox e altere-a para 40 que é um bom número. A aparência
desse listbox deve ser parecida como a

Popup menu

Arraste esse ListBox para o Layout do frmTitulos. Ele deve ficar como na

Estrutura de componentes.

Para que ele fique com uma sombra em volta, localize o componente TShadowEffect e arraste-o para o listbox, como
na

 Sombra

 __________________________________________________________________________________________
41
Perfeito! Agora temos que preparar a logística para que tudo isso funcione. Nós faremos o menu aparecer de cima
para baixo com uma animação, e desaparecerá do mesmo modo. Para que possamos sumir com o menu quando o
usuário tocar fora, usaremos nossa antiga técnica de criar um retângulo escuro por baixo de tudo. Nós vimos isso no
primeiro tutorial. Voltaremos com a ideia.
Vá até o formulário principal, frmMain, e adicione um TRectangle de qualquer tamanho e modifique sua propriedade
Opacity para 0.5. Na seção Public do form, crie dois métodos:

?
1 procedure ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent = nil);
2 procedure HideBackground;
E codifique-os como na .
?
procedure TfrmMain.HideBackground;
1 begin
2 recBackground.AnimateFloat('opacity', 0, 0.1);
3 recBackground.Visible := False;
4 end;
5
6 procedure TfrmMain.ShowBackground(AParent: TFmxObject; AOnClick: TNotifyEvent);
7 begin
8 recBackground.OnClick := AOnClick;
9 recBackground.Parent := AParent;
10 recBackground.BringToFront;
11 recBackground.Opacity := 0;
12 recBackground.Visible := True;
13 recBackground.AnimateFloat('opacity', 0.5, 0.1);
end;
 Background em principal

O procedimento é exatamente igual ao que fizemos na primeira parte do tutorial, portanto não explicarei novamente.
Apenas para entendermos, nós chamaremos ShowBackground sempre que precisarmos mostrar o fundo escuro e
HideBackground para sumir como ele.
Já na tela frmTitulos nós criaremos um método para sumir com o pop-up, então crie um novo método com o nome
HidePopup e digite o código a seguir:
?
1 frmMain.HideBackground;
2 lstPopUpFoto.AnimateFloat('position.y', lstPopUpFoto.Height * -1);
3 lstPopUpFoto.Visible := False;
Simples não? Chamamos o método HideBackground presente no formulário principal e depois as animações para
esconder o menu. Por default o menu deve ficar invisível e longe do alcance dos olhos, portanto no OnCreate do
formulário de títulos adicione o código da
?
1 lstPopUpFoto.Width := ClientWidth - 20;
2 lstPopUpFoto.Position.X := (ClientWidth - lstPopUpFoto.Width) / 2;
3 lstPopUpFoto.Position.Y := lstPopUpFoto.Height * -1;
4 lstPopUpFoto.Visible := False;
5
6 AtualizarBotoes;
OnCraete do formulário

O que estamos fazendo no método é, em resumo, aumentar sua largura automaticamente para que fique com um
tamanho mais adequado a largura do device e depois posicionamos ele acima da barra de título do aparelho e
deixando-o invisível.
Acesse agora a aba detalhes e clique duas vezes no nosso imgFoto para adicionar um novo código ao evento OnClick
do objeto. Nós chamaremos agora o menu pop-up. Digite o código da .

?
1 procedure TfrmTitulos.imgFotoClick(Sender: TObject);
2 begin
3 if DM.qryTitulos.State in dsEditModes then
4 begin
5 frmMain.ShowBackground(Self.lytTitulos, lstitCancelarClick);
6 lstPopUpFoto.Visible := True;
7 lstPopUpFoto.AnimateFloat('position.y', 0);
8 lstPopUpFoto.BringToFront;
 __________________________________________________________________________________________
42
9 end;
10 end;
Chamada para o popup

Na  fazemos primeiro uma checarem para ver se o usuário colocou o registro em alteração, evitando um
erro na tela. Em seguida mostramos o fundo escuro e descemos o popup usando o método AnimateFloat passando a
nova posição vertical dele, position.y.
Feito. Somente precisamos agora codificar a ação de cada item do ListBox. No OnClick do primeiro item digite:
?
1 HidePopup;
2 actFotoCamera.ExecuteTarget(Sender);

No segundo repita e mude apenas a chamada para a biblioteca.


?
1 HidePopup;
2 actBiblioteca.ExecuteTarget(Sender);
E caso o usuário queira desistir de tirar foto, apenas chame HidePopup e HideBackground para sumir com o popup de
tela.
?
1 HidePopup;
2 frmMain.HideBackground;

Para fecharmos com chave de ouro, precisaremos fazer a exclusão de registros e o PullToRefresh, ou seja, puxe para
atualizar. Usaremos gestos para isso, mas os defaults. Quando o usuário arrastar o dedo para os lados, um botão Delete
deverá aparecer. Se puxar de cima para baixo, então atualizamos a tabela. Isso tudo no ListView.
Bem, o PullToRefresh já está pronto. Apenas ative a propriedade PullToRefresh e então codifique o evento
OnPullToRefresh. Digite apenas:
?
1 DM.qryTitulos.Active := False;
2 DM.qryTitulos.Active := True;
Ou seja, apenas fechamos e abrimos a query.
Para excluir basta ativar a propriedade CanSwipeDelete e codificar o evento OnDeletingItem. Nesse caso vamos a
explicação.
Esse evento ocorre no momento que o usuário clica no botão para exclusão do item e o mesmo entra em modo de
exclusão definitiva. Nós temos uma variável nesse evento chamada ACanDelete. Se não codificarmos nada nesse
evento, o item será apagado do ListView, mas não do banco de dados, o que acabará voltando se o usuário der um
PullToRefresh ou fechar e reabrir o app. Por isso excluiremos também do banco.
Levando em consideração que não sabemos exatamente qual ID do Título estamos excluindo, usaremos o INDEX da
linha excluída como base. Sabemos que o ListView inicia sua contagem em 0 (zero), somaremos +1 para obtermos o
ROWID exato do registro a ser excluído do banco. Portanto faremos um Locate na tabela para pararmos em cima do
registro e apagaremos. Digite então o código da

?
procedure TfrmTitulos.lsvTitulosDeletingItem(Sender: TObject; AIndex: Integer;
1 var ACanDelete: Boolean);
2 begin
3 ACanDelete := MessageDlg('Confirma exclusão de título?', TMsgDlgType.mtConfirmation,
4 [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0 ) = mrYes;
5
6 if ACanDelete then
7 begin
8 DM.qryTitulos.Locate('ID_TITULO', AIndex+1, []);
9 DM.qryTitulos.Delete;
10 end;
end;
Exclusão

Perceba. Perguntamos ao usuário se ele deseja excluir o registro e igualamos o seu resultado a variável ACanDelete.
Caso ela receba True, ou seja, SIM, então localizamos o registro e excluímos.
 __________________________________________________________________________________________
43
Como isso encerramos a quarta parte de nosso tutorial. Ainda será disponibilizado um vídeo com mais alguns detalhes.
Então fiquem de olho, pois esse post sofrerá algumas modificações.

Nesse tutorial vimos muitas das operações triviais de qualquer aplicativo. Mas também vimos técnicas simples, porém
eficazes para criar um pop-up de menu, muito utilizado em aplicações móveis. Vimos também a utilização de ações
padrões e o uso de conteúdo do aparelho, como fotos.

 __________________________________________________________________________________________
44
Bem vindos a parte V de nosso  a partir do desenvolvimento em RADStudioXE7 .
Até agora entendemos uma série de mecanismos que nos ajuda a desenvolver de forma mais rápida e intuitiva, criando
nossas telas, capturando fotos, ligando controles a campos do banco de dados, etc.
Relembrando da seção passada, nós vimos:
1. Criação de campo do tipo imagem na tabela de Títulos;
2. Criação de método para auto-numerar ID de Títulos;
3. Binding da imagem com as listagem e detalhes do Título;
4. Inclusão, Alteração e Exclusão de Títulos;
5. Seleção de fotos da biblioteca ou câmera;
Essa seção será um pouco mais light. Entenderemos como aplicar um estilo mais profissional ao aplicativo, instalação
e configuração do cliente Git para clone de nosso fonte do . E também criaremos uma janela de configuração
para guardar preferências do usuário. Segue a lista:
 Instalação e configuração do Git no Delphi XE7;
 Como aplicar estilos mais profissionais?
 Criando uma janela de preferências;
 Criação de classe para guardar informações de preferências.

Requisitos:
 Leitura: Tutorial: Criando meu app step-by-step parte IV;

A primeira coisa que aprenderemos nesse passo do tutorial, é adicionar um novo estilo ao nosso app. Isso é possível
por conta do . Para quem é novato em , o é um framework pod eroso criado
pela que possui uma infinidade de recursos, e é “culpa” dele que hoje temos a possibilidade de
desenvolver apps para “n” plataformas. Sem contar, é claro, com o novo compilador  que dá vida a tudo.
Em função disso, podemos criar, editar e adicionar novos estilos aos nossos apps tanto para
plataforma  quanto  tais como  e . A Embarcadero disponibiliza um pacote de estilos
prontos para usuários registrados. Basta acessar o site http://cc.embarcadero.com/item/29928 e baixar o pacote
completo. Nesse caso usaremos o pacote
Com o pacote aberto e descompactado nós vamos aprender a instalar o tema nas pastas do XE7. Abra o Windows
Explorer em seu computador e abra a pasta referente ao pacote descompactado. Perceba que temos uma pasta para
cada plataforma conforme a .

Tema descompactado

 __________________________________________________________________________________________
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ê também encontra os arquivos
separados por plataforma, então agora fica fácil. 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 façamos a adição no nosso projeto. Para isso abra o
Delphi XE7 e em seguida nosso projeto. No form principal, frmMain, adicione um componente do
tipo  Localize-o digitando seu nome da caixa de pesquisa na paleta de componentes.
Agora selecione a plataforma Android à sua direita no . Isso é necessário 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 botões na parte superior, um deles é o para ca rregarmos o estilo que
desejamos. Clique nesse botão e localize o arquivo  naquela mesma pasta onde colocamos
os temas. Em seguida clique em . Selecione agora o formulário 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

Estilo aplicado ao formulário


Tema aplicado

Se você desejar aprender mais sobre o esquema de estilos, basta ler ao artigo o artigo na docwiki nesse link.

A grande maioria dos aplicativos que usamos no dia-a-dia possuem configurações de usuário, preferências. Em nosso
app não será diferente. Aprenderemos agora a criar uma janela com preferências do usuário utilizando um arquivo do
tipo INI (Inicialização). Isso mesmo! Da mesma forma que fazemos em Windows.
Vamos primeiro alterar nossa interface. Crie um novo item no nosso ListBox de menu. Esse item deverá se
chamar lstPreferencias e terá seu Text  alterado para “Preferências”, sem áspas claro.
Em seguida crie um novo formulário assim como fizemos nas aulas anteriores. Não esqueça de incluir uma ToolBar  na
parte superior com um SpeedButton  chamado spbBack para que possamos ter um botão para abrir o menu principal
quando desejarmos. Dê o nome a esse formulário de  frmPreferencias e salve a a unit como UntPreferencias.pas.

Adicione um novo botão alinhado à direita com margem direita de 8px. O seu Text  deverá ser “Gravar” e o
name spbGravar.  Esse botão será nosso botão para gravação das preferências em arquivo INI. A tela deverá se parecer
com a .

 __________________________________________________________________________________________
46
Sugestão de tela de configurações

Assim como nas telas de Títulos e Login, inserimos um TLayout  no fundo e dentro dele inserimos o demais
componentes. Nesse caso inseri um ListBox  no formulário alinhado como Client.  Fixei a altura das linhas em 44 usando
a propriedade  e em seguida adicionei um novo item. Para isso, clique duas vezes no ListBox.  Isso fará com
que se abra a janela de gerenciamento dos itens do ListBox.  No à direita selecione a
opção  como na imagem a seguir:

Adicione um Item de cabeçalho e em seguida um item comum. O primeiro deles dê o nome de lstgrpSeguranca  e
seu Text  mude para “Segurança”. 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 e dê o nome a ele
de swtDesconectar.  Alinhe-o a direita com margem direita igual a 8px.

Muito bom até aqui. Com nossa interface pronta, vamos preparar as funções de gravação e leitura do arquivo INI. Para
facilitar todo o trabalho, vamos criar uma classe para ler e escrever no arquivo INI, bem como alimentar as propriedades
do menu principal. Propriedades? Sim, vamos começar a brincar um pouco com orientação a objetos.
Crie uma nova unit em File > New > Unit. Salve-a como ULib.pas. De preferência crie uma pasta no projeto
chamada Lib e salve essa Unit  lá dentro, assim deixamos tudo mais organizado.
Com a unit aberta, adicione uma cláusula Uses abaixo de Interface e declare as UnitsIniFiles e System.IOUtils, como
mostrado abaixo:
?
1 interface
2 uses
3 IniFiles, System.IOUtils
Em seguida escreva o cabeçalho das funções e propriedades que vamos codificar aqui. Veja a  como o código
precisa ser implementado.
?
1 type
2 Lib = class
3 private

 __________________________________________________________________________________________
47
4 FDesconectarAoSair: Boolean;
5 function GetDesconectarAoSair: Boolean;
6 procedure SetDesconectarAoSair(const Value: Boolean);
7
8 public
9 procedure SaveConfig;
10 procedure ReadConfig;
11 published
12 property DesconectarAoSair: Boolean read GetDesconectarAoSair write SetDesconectarAoS
13   end;
Código do cabeçalho dos métodos

Nós criamos uma propriedade chamada  do tipo  (True/False) e guardarmos a informação
se o usuário deseja ou não sair totalmente do sistema ao sair do aplicativo. Em seguida criamos dois métodos:
  Salvar os dados no arquivo INI;
  Ler dados do arquivo INI;
Pressione Ctrl+Shift+C  para que o Delphi crie para nós o escopo dos métodos. Nós faremos algo bem simples já que
temos apenas uma configuração para ser guardada no arquivo INI. Digite o código da

?
function Lib.GetDesconectarAoSair: Boolean;
1
begin
2
Result := FDesconectarAoSair;
3
end;
4
5
procedure Lib.ReadConfig;
6
var
7
Ini : TIniFile;
8
begin
9
try
10
Ini := TIniFile.Create(TPath.Combine(TPath.GetDocumentsPath, 'Config.ini'));
11
FDesconectarAoSair := Ini.ReadBool('SEGURANCA', 'DesconectarAoSair', FDesconectarAoSair);
12
finally
13
Ini.DisposeOf;
14
end;
15
end;
16
17
procedure Lib.SaveConfig;
18
var
19
Ini : TIniFile;
20
begin
21
try
22
Ini := TIniFile.Create(TPath.Combine(TPath.GetDocumentsPath, 'Config.ini'));
23
Ini.WriteBool('SEGURANCA', 'DesconectarAoSair', FDesconectarAoSair);
24
finally
25
Ini.DisposeOf;
26
end;
27
28
end;
29
30
procedure Lib.SetDesconectarAoSair(const Value: Boolean);
31
begin
32
FDesconectarAoSair := Value;
33
end;
 Escopo dos métodos

Em SaveConfig  e ReadConfig nós declaramos uma variável do tipo TIniFile . Criamos o arquivo INI usando o
método Create da classe e então recebemos ou gravamos o valor encontrado, direto na
variável FDesconectarAoSair,  que é a variável referente a nossa propriedade de mesmo nome.
Antes de prosseguirmos com a codificação em  frmPreferencias, necessitamos fazer algumas alterações no frmMain,
ou seja, no formulário principal. Retorne a ele e logo de início faça um File > Use Unit   e adicione a ULib na
seção  do formulário principal. Aproveite e adicione também a unitUntPreferencias.
Na seção public do formulário, adicione uma nova variável para fazermos referência ao formulário de preferências.
Chame-a de FPreferencias do tipo TfrmPreferencias.
Agora crie uma variável chamada FLib do tipo TLib. Essa variável será usada para instanciarmos a classe TLib e usarmos
sempre que precisarmos. Nossas declarações devem ficar como na codificação abaixo:

 __________________________________________________________________________________________
48
?
1 [...]
2 uses
3 ULib,
4 UntPreferencias;
5 [...]
6 public
7 FPreferencias : TfrmPreferencias;
8 FLib : TLib;
9 [...]
Acesse o evento OnCreate do form principal e faça a criação da instância de FLib, como abaixo:
?
1 FLib := TLib.Create;
2 FLib.ReadConfig;
Já no evento OnClose, precisamos dispensar a variável para evitar  Faça como abaixo:
?
1 if Assigned(FLib) then
2 FLib.DisposeOf;
Agora falta apenas, nesse formulário, fazer a chamada para o form de preferências. Clique duas vezes no item de
listbox referente ao menu preferências e codifique-o como na .

?
1 procedure TfrmMain.lstPreferenciasClick(Sender: TObject);
2 begin
3 if not Assigned(FPreferencias) then
4 FPreferencias := TfrmPreferencias.Create(Self);
5
6 MultiView1.MasterButton := FPreferencias.spbBack;
7 MultiView1.HideMaster;
8
9 {Adiciona o Layout de Pedidos ao Layout Principal que controla tudo}
10 lytMain.AddObject(FPreferencias.lytPreferencias);
11
12 try
13 DM.qryTitulos.Active := False;
14 DM.qryTitulos.Active := True;
15 except on E:Exception do
16 ShowMessage('Click em Títulos: ' + E.Message);
17 end;
18 {Deixa todos os layouts invisíveis e deixa o layout alvo visível}
19 ShowForm(FPreferencias.lytPreferencias);
20 end;
Chamada para o form de preferências

Para finalizar essa parte, precisamos acessar o evento OnCreate  do formulário preferências e fazer a chamada a
nossa Lib para que possamos atualizar os controles em tela de acordo com o que está gravado no arquivo INI, bem
como gravar as novas alterações.

Como nossa janela de preferências só possui um item para ser gravado, então vai ser fácil codificarmos. Precisamos
gravar o que o usuário escolheu e na abertura da tela precisamos ler o que foi gravado e atualizar a tela. Publiquei
na  o código completo dos dois eventos, OnCreate e OnClick  (spbGravar).
?
1 procedure TfrmPreferencias.FormCreate(Sender: TObject);
2 begin
3 frmMain.FLib.ReadConfig;
4 swtDesconectar.IsChecked := frmMain.FLib.DesconectarAoSair;
5 end;
6
7 procedure TfrmPreferencias.spbGravarClick(Sender: TObject);
8 begin
9 frmMain.FLib.DesconectarAoSair := swtDesconectar.IsChecked;
10 frmMain.FLib.SaveConfig;
11 end;

 __________________________________________________________________________________________
49
Códigos do OnCreate e OnClick

Note que fazemos referência ao formulário principal,  frmMain, por isso é necessário fazer um UseUnit  nele. Fazemos
isso porque estamos lendo as propriedades da classe TLib através da variável FLib no form principal. No
evento OnCreate nós lemos as informações e atualizamos o controle swtDesconectar. Estamos igualando sua
propriedade IsChecked  ao valor boleano gravado no arquivo INI.
Do mesmo modo, evidentemente ao contrário, gravamos o estamos do controle swtDesconectar   no arquivo INI,
fazemos essas duas operações chamando os métodos ReadConfig e SaveConfig  respectivamente.

Para aqueles que não sabem ainda, o  implementou suporte ao  O   é uma, grosseiramente
falando, plataforma de gerenciamento e código-fonte. Com ele conseguimos fazer controles de código-fonte,
controle de diferenças, e uma série de outras funcionalidades estão disponíveis nele. Atualmente o Git é bastante
utilizado assim como  já existente no Delphi há tempos.
Nessa seção aprenderemos a configurar o  no Delphi e baixar o código-fonte desse tutorial diretamente pelo Delphi.
A primeira providência é instalar o cliente do Git em seu Windows/Mac. Para isso acesse o link http://www.git-
scm.com/download e baixe a versão que melhor se encaixe com seu perfil. Nesse tutorial mostrarei somente o uso
com Windows.
Feito o download do arquivo (até o fechamento desse artigo) , clique duas vezes nele e
clique logo de início em Next em todas as janelas. Deixei propositalmente  em todos os passos. Aguarde a
instalação e então voltemos até o Delphi.
Com o Delphi aberto, precisaremos indicar a ele onde o arquivo principal do Git está instalado. Para isso acesse Tools
>Options>VersionControl>Git . Em  clique no botão reticências à direita e navegue até a pasta de
instalação do Git, normalmente em C:\ProgramFiles(x86)\Git\bin\git.exe.
Feito isso estamos prontos para fazer o download de nosso código-fonte. Acesse o menu File>Openfromsource
control  e em seguida selecione Git. Na janela seguinte cole o endereço completo de nosso fonte no Bitbucket. Caso
não saiba, acesse https://bitbucket.org/tdevrocks e selecione o nosso curso. À direita do site você encontrará o
caminho completo para o site.
O segundo campo dessa caixa de diálogo é o local onde o código-fonte deverá ser baixado. Fica a seu critério nesse
caso. Veja todos esses passos nas imagens abaixo:

Abertura do arquivo fonte

Seleção do Git

Endereço remoto e local do repositório

 __________________________________________________________________________________________
50
Endereço remoto

Download

Finalização

Quando o download finalizar, o Delphi detectará se há algum arquivo .dpr, .dproj e etc e já fará a sugestão de abertura
do arquivo. Você pode cancelar nesse momento se desejar.

O código-fonte desse exemplo encontra-se disponível aqui.

Nesse artigo pudemos aprender como é fácil adicionar um novo estilo as nossas aplicações Delphi para Mobile, bem
como para desktop Windows e Mac. O aprendizado aqui serve não somente para aplicativos multi-device, mas caso
você deseje adicionar um estilo profissional a sua aplicação, os passos também são válidos.
Também aprendemos a usar arquivos INI para ler e gravar informações nos diretórios do dispositivo móvel. Por fim,
aprendemos a configurar o Git para efetuar o clone de nosso projeto no Bitbucket. Os passos vistos aqui, também são
válidos para qualquer outro código-fonte disponível na nuvem ou localmente.

 __________________________________________________________________________________________
51
Criandomeuappstep-by-step tem se tornado uma referência a muitos seguidores do blog, e nós agradecemos muito
;). Mas até o presente momento, estamos vendo coisas básicas no  então é hora de avançarmos um pouco mais.
Nessa sexta parte, iniciaremos a criação de um servidor de aplicativos desenvolvido com , passando pelo
conceito de  no  no futuro, bem como o uso de objetos  para troca de  entre cliente e
servidor. Calma, calma! Para os iniciantes, tanto no quanto no  isso pode parecer uma Hidra de Lerna,
vulgarmente chamada de BichodeSeteCabeças . Mas não, será fácil.
No artigo anterior, nós aprendemos a criar uma janela de configurações utilizando arquivos INI para persistir as
preferências do usuário, além de outras coisas. Confira:
 Instalação e configuração do Git no Delphi XE7;
 Como aplicar estilos mais profissionais?
 Criando uma janela de preferências;
 Criação de classe para guardar informações de preferências.
Nesta sexta parte, veremos como criar nosso servidor  e como configurar nossa aplicação cliente para ler
nossos
 Criação do servidor
 Criação do módulo de conexão com o servidor
 Teste de conexão.

Requisitos:
 Leitura: Leitura do artigo Parte V;
 Vídeo: Assistir ao vídeo complementar em nosso canal no YouTube;

Antes de iniciarmos a criação de nosso servidor, precisamos entender exatamente o que faremos aqui. Atualmente
temos somente uma tabela em nosso banco de dados local, que armazena os DVD’s que podemos alugar em
nossa locadora. Possibilitamos o usuário final (administrador) fazer a inclusão, exclusão e alteração de titulos. Mas isso
hoje fica somente no dispositivo móvel, o que é ruim. Nossa ideia inicial era que o aplicativo fosse apenas um sistema
para uso do administrador da locadora, que poderia alugar, devolver ou ainda conferir quais itens estão emprestados.
A ideia agora é fazer com que possamos atualizar nosso servidor central com informações do que foi efetuado no
mobile, bem como atualizar o mobile com informações dos títulos que estão no servidor central. Faremos isso
com
No esquema da , vemos como funcionará nosso sistema.

. Esquema DataSnap

Note que nossa arquitetura prevê que nossos aplicativos móveis utilizarão internet para chegar ao servidor e
consequentemente, chegar ao banco de dados.

 __________________________________________________________________________________________
52
Com o  aberto e nosso projeto também já aberto na IDE, vamos adicionar um novo projeto clicando
com o botão direito em ProjectGroup1  no ProjectManager a nossa direita ( ). Selecione  AddNewProject .

 Criação do Projeto

Isso fará com que a janela de criação de novos projetos seja aberta pelo Delphi.  Você precisará clicar em DelphiProjects
> DataSnap Server e use o item DataSnap REST Application. Em seguida marque a opção Stand-alone
application  e Next. Aceite a opção default, VCL application  e novamente em Next. A tela seguinte nos dá como
sugestão a . Essa será a porta que nosso aplicativo móvel (ou desktop) usará para se conectar com o servidor.
Vamos usar essa porta mesmo, mas lembre-se se seu Windows precisará ter essa porta liberada no Firewall.

Passe a tela seguinte sem selecionar nenhuma opção adicional e em seguida use   como classe para
nossos Isso fará com que o Delphi crie para nós um onde colocaremos nossos
componentes de acesso a dados. Por fim selecione um caminho para salvar o código-fonte do servidor e clique
em  Como sugestão, criei uma pasta chamada  na raiz de nosso curso.

Depois de clicar em Finish, o Delphi cria para nós todos os arquivos necessários e as respectivas configurações para
que o servidor funcione corretamente em modo Stand-alone, ou seja, em modo executável. Você perceberá que temos
três arquivos abertos:
 : Formulário principal do servidor;
 : Servidor de Métodos;
  Principal unit do servidor, possui os componentes que mantém o servidor no ar, tal como
O primeiro formulário da lista, salve-o como UntMainServer.pas e dê o nome (Propriedade Name) a ele
de  frmMainServer. Em seguida salve o segundo formulário como UntServerMetodos.pas e dê o Name
de SrvServerMetodos. Por fim salve o WebModuleUnit1  como UntWebModulo.pas e troque seu Name
para
Aproveitando que estamos no  vamos analisar esse formulário. O primeiro componente importante desse
formulário é o DSServer1.  É ele que recebe todas as requisições de aplicações cliente, sejam elas mobile, sejam elas
desktop Windows ou Mac.
Em seguida nós temos um DSServerClass1 . Esse componente é responsável por exportar as classe e consequentemente
os métodos do servidor para o cliente. Podemos ter quantos componentes desse quisermos. Clique nesse componente
e acesse seu evento Teremos é seguinte código:
?
1 procedure TwebModulo.DSServerClass1GetClass(
2 DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
3 begin
4 PersistentClass := UntServerMetodos.TSrvServerMetodos;
5 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 métodos de acesso
a banco de dados.
Acesse agora a folha de código do ServerMetodos e localize a parte superior da unit onde encontramos os
métodos  e   Esses dois métodos poderão ser acessados por nossos aplicativos móveis, bem
como outros métodos que venhamos a codificar nessa área.
Para finalizar tudo, salve agora o projeto como Utilize a opção “File>SaveProjectA s…“. Em seguida
compile e execute nosso servidor utilizando Shift+Ctrl+F9  para rodar fora do modo Debug. Você verá que basta clicar
no botão Start para que ele entre em ação e passe a “escutar” nossas requisições.

Agora aprenderemos apenas como fazer a configuração e conexão com nosso servidor de aplicativos DataSnap.
Mantenha o servidor aberto para que possamos fazer as configurações.
#Dica: Clique com o botão direito do mouse em  no  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. Nós
precisaremos incluir uma nova Unit nesse projeto utilizando o menu File>New>Other>DataSnapServer  e logo em
seguida selecione o item DataSnapREST Client Module ( ).

Criação do módulo cliente

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
necessários para acesso ao servidor de dados. Nesse caso temos as opções:
 DataSnap stand alone server: Servidor DataSnap stand-alone, nossa escolha;
 WebBroker and stand alone server: Servidores Web;
 IIS Module: Esse tipo de servidor funciona através 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 então, como mencionado, a primeira opção DataSnap stand alone server. Na tela seguinte, e última, nós
podemos testar nossa conexão bem como modificar ou apenas informar a porta correta para conexão.
Depois de finalizado, nós teremos uma nova Unit que salvaremos como UntModuloCliente. E dê o nome a ele de
ModuloCliente. Nós podemos ter quantos módulos cliente quisermos. Perceba que um único componente foi incluído
nesse formulário. Esse componente, do tipo  é o responsável por conectar-se com nosso servidor
de aplicações. Clicando nele e observando suas propriedades, perceba que podemos a qualquer momento alterar a
porta de conexão na propriedade Port.
Caso você deseje testar se a conexão funciona, basta clicar com o botão direito do mouse no DSRestConnection  e
selecionar TestConnection. Ainda com o botão direito, clique em GenerateDataSnapclientclasses . Esse é principal
 __________________________________________________________________________________________
54
segredo do DataSnap. Clicando nessa opção, uma nova Unit será gerada. Chamaremos essa Unit de  pois é o que
ela faz. Esse proxy tem o objetivo de nos “linkar” com os métodos do servidor. É através dele que recebemos e
enviamos parâmetros, 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 função for criada, excluída, tiver seus parâmetros modificados ou ainda possuir novas
classes para serem exportadas/importadas, utilize o botão direito do mouse e a opção Generate DataSnap client
classes.
#Dica2: Na dica acima, apenas não se esqueça que o servidor precisa estar aberto e iniciado.
#Dica3: A Unit Proxy.pas NUNCA deve ser alterada manualmente. Não é necessário.
 e .

 Escolhendo o tipo de servidor

 Testando e finalizando a criação do Módulo Cliente

#Dica: Como nós alteramos os nomes das duas novas Units, ou seja, UntModuloCliente e Proxy, precisaremos
também refazer a declaração dessas unidades que se enxergam. Para isso, acesse a seção Uses do UntModuloCliente
e acrescente a unit Proxy. Compile o projeto. Um erro ocorrerá apontando para o nome antigo de nosso Proxy.
Apenas apague-o. Nosso Uses ficará semelhante ao código abaixo:

 __________________________________________________________________________________________
55
?
1 uses
2 System.SysUtils, System.Classes, Proxy, IPPeerClient, Datasnap.DSClientRest;

Pois bem, até aqui não digitamos uma só linha de código. Para finalizarmos nosso tutorial de hoje, faremos apenas um
pequeno de teste para entendermos o primeiro conceito de acesso ao servidor de aplicativos.
Retorne ao frmMain, formulário principal de nossa aplicação mobile, e adicione um novo item de  em nosso
menu principal. Será provisório, apenas para testarmos. Aumente a altura desse novo item de modo que caibam 1(Um)
Label , 1(Um)Edit  e 1(Um)SpeedButton . Deseje nosso item semelhante a .

 Menu para teste

Antes de iniciarmos a codificação, precisamos fazer uso da Unit UntModuloCliente, por isso entre em File>UseUnit  e
selecione a unit informada. Não modifiquei o nome de nenhum componente.
No código do botão SpeedButton1 codifique como mostrado a seguir:
?
1 procedure TfrmMain.SpeedButton1Click(Sender: TObject);
2 begin
3 Edit1.Text := ModuloCliente.SrvServerMetodosClient.ReverseString(Edit1.Text);
4 end;
Perceba como o código é simples. Abra a unit ModuloCliente e note que há uma propriedade chamada
SrvServerMetodosClient, que nada mais é que uma referência a nossa classe   no lado servidor.
Através dessa propriedade conseguimos acesso ao método ReverseString. Passamos para ela o valor digitado no Edit1
e recebemos do servidor a String invertida que substitui o conteúdo do próprio Edit.
Esses são os passos e conceitos padrões para acesso ao servidor. No próximo tutorial, faremos a exportação de
um  do servidor para o cliente e com ele alimentaremos uma tabela temporária do lado cliente.
Para não avançarmos demais nessa sexta parte, finalizaremos aqui e continuaremos nosso desenvolvimento na parte
VII.

O uso de DataSnap é uma “mão a roda” para quem deseja separar sua aplicação em camadas. Aqui vimos que é
perfeitamente possível efetuar chamadas ao servidor de aplicativos utilizando a porta 8080 e ler o retorno do servidor
em aplicações mobile.Nossa aplicação está preparada para funcionar também 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 próxima!

 __________________________________________________________________________________________
56
, novo conceito de desenvolvimento de servidores  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 iríamos
avançar um pouco mais em nosso tutorial. Pois bem, chegou a hora. Nessa sétima parte de nossa sequência, veremos
como exportar um  do servidor para o cliente em formato  nova classe no RAD Studio XE.
Também vimos a criação do nosso banco de dados Firebird 2.5 em nossa vídeo-aula complementar no YouTube nos
preparando já para fazer o sincronismo entre servidor e cliente. Vejamos o que foi dito na versão anterior desse post.
 Criação do servidor
 Criação do módulo de conexão com o servidor
 Teste de conexão.
Nessa sétima parte, faremos a exportação da primeira tabela do banco no lado servidor, bem como seu uso no lado
cliente. Veja:
 Criação da tabela do banco de dados no Firebird;
 Criação dos métodos de exportação de Títulos no lado servidor;
 Leitura e atualização da tabela Títulos local no dispositivo móvel;

Requisitos:
 Leitura: Leitura do artigo parte VI;
 Vídeo: Assistir ao vídeo complementar da parte VI;

A primeira providência a ser tomada aqui é criar nossa primeira tabela no banco de dados Firebird. Sendo assim,
faremos a abertura do banco no IBExpert. Não entrarei em detalhes quanto ao uso de outras ferramentas de acesso
ao SGDB Firebird, pois está fora do escopo de nosso projeto.
#Dica: O IBExpert é uma excelente ferramenta de acesso ao Firebird e Interbase e possui uma versão Personal FREE,
que possui recursos limitados, mas suficientes para a maioria das ações que precisamos fazer. Basta cadastrar-se no
nesse linke então receber sua cópia FREE.
Com o IBExpert aberto e seu banco devidamente conectado, clique com o botão direito do mouse em  e em
seguida em . À direita e acima, você encontrará o campo para nomear nossa tabela. Ele estará com o valor
N . Modifique-o para
Crie a tabela do banco exatamente igual a que criamos para a versão SQLite, se preferir confira a  que mostra
a tabela criada no IBExpert. A única diferença está nos campos de imagem, FOTO e MINIATURA que são do
tipo  com

 Tabela Títulos no Firebird

Conforme podemos ver no título desse artigo, veremos um novo conceito de desenvolvimento de nosso servidor
DataSnap: . Um classe foi recentemente adicionada ao Delphi para esse propósito presente na
unit  Nós podemos agora fazer a exportação de DataSets do servidor para o cliente de uma
maneira mais simples e ao mesmo tempo mais inteligente. Por exemplo: se precisarmos enviar  DataSets do
servidor para o cliente em uma única instrução, basta usarmos em um  e podemos adicionar
mais de um DataSet ao  da função. Veremos isso mais delalhadamente, por enquanto vamos fazer a exportação
apenas de um único DataSet, a tabela de pedidos.

 __________________________________________________________________________________________
57
Para isso faremos agora as configurações necessárias para acessar o servidor de banco de dados Firebird usando o
componente  Abra o servidor DataSnap criado no artigo anterior e encontrei nosso ServerMethod que
tem o nome É nele que colocaremos nossas tabelas e conexões 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, não 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
parâmetros na parte de baixo para que sejamos capazes de configurar os dados de acesso. Em DataBase configure
incluindo o endereço completo do arquivo de banco de dados, em nosso caso LOCADORASERVER.FDB. E seguida
configure seu usuário e senha, SYSDBA e masterkey, respectivamente. Em Protolo, marque TCPIP. Clique em Test para
verificar se está tudo ok com a conexão. No nosso caso, estamos usando o Firebird 2.5, conforme demonstrado em
vídeo-aula. Observer a  as configurações básicas.

 Conexões com o servidor DataSnap

Agora basta incluir no ServerMethod um componente do tipo FDQuery, para que possamos fazer uma Query na tabela
TITULOS para exportarmos para o servidor. Dê o nome de qryTitulos a esse query e escreva a seguinte instrução SQL
em sua propriedade de mesmo nome.
?
1 SELECT * FROM TITULOS
Bem simples, não? Exato, não 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 código-fonte e procure a seção Public.
Declare a nossa function como na linha a seguir:
?
1 function GetTitulos: TFDJSONDataSets;
Perceba que estamos usando a classe TFDJSONDataSets como retorno da função. Agora, precisamos pressionar CTRL
+ SHIFT + C para que o Delphi crie o escopo de nosso método. Escreveremos o código da .
?
1 function TSrvServerMetodos.GetTitulos: TFDJSONDataSets;
2 begin

 __________________________________________________________________________________________
58
3 //Devolve para o cliente o DataSet de Pedidos
4 //Elimina cache
5 qryTitulos.Active := False;
6 Result := TFDJSONDataSets.Create;
7 TFDJSONDataSetsWriter.ListAdd(Result, qryTitulos);
end;
8
 Código de exportação do DataSet TITULOS

Moleza para entendermos. Primeiramente nós fechamos a Query qryTitulos para evitar enviarmos ao cliente algo que
 já esteja em cache. Em seguida nós criar uma instância de TFDJSONDataSets (nosso resultado) associando-o ao Result
do método.
Por fim, usamos a classe  para adicionar TODO o conteúdo da Query ao Result, ou seja, quantos
forem as linhas listadas no qryTitulo serão adicionados ao Result e consequentemente recebidos pelo cliente. Eu disse
“linhas listadas”, mas creio que não perceberam que não abrimos a query em momento algum certo? Pois bem, o
método ListAdd já faz isso para nós, então não se preocupe.
Evidentemente que em uma situação real, precisaríamos, talvez, passar um parâmetro do cliente para o servidor
informando um determinado filtro a Query, algo como: TRAGA OS TÍTULOS QUE NÃO ESTÃO ALUGADOS. Mas isso é
assunto para mais tarde.
Compile o servidor e veja se tudo está correto.
#Dica: Provavelmente a classe TFDJSONDataSets não será encontrada, resultando em um “error compiler”. Portanto,
adicione a unit Data.FireDACJSONReflect ao uses do nosso ServerMetodos.
#Dica: Não esqueça de clicar com o botão direito do mouse em nosso qryTitulos escolher Fields Editor e com a janelinha
aberta, clicar com o direito novamente e então usar o Add all fields para que todos os campos da tabela sejam
adicionados.

Execute o servidor DataSnap em modo SEM Debug clicando com o botão direito no Project Manager e em seguida em
Run Without Debbuging ( )

Rodando o servidor em modo stand-alone

 __________________________________________________________________________________________
59
Primeira coisa que quero fazer aqui é testar sua memória. Não, não quero que abra nenhum dos artigos sobre games
da memória publicados aqui no site. Quero apenas que lembre-se. Fomos até o servidor DataSnap
e  nosso servidor incluindo novos recursos, nesse caso um novo método. Então, qual o primeiro passo
aqui para começar a enxergar esse novo recurso?
Se respondeu que devemos abrir a unit , clicar com o direito no  e em seguida em
Generate DataSnap client classes ( ), Bingo! Acertou na mosca.

Atualizando o cliente

Precisamos fazer isso para que nosso Proxy seja atualizado com o novo método, GetTitulos. Ao gerar novamente o
proxy, ele será imediatamente aberto, bastando apenas salvar e fechar essa unit. Lembre-se, não precisamos alterar
nada no Proxy.

Nessa última parte desse artigo, avançaremos 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 código.
Retorne até a tela principal do sistema com o nome de frmMain. No capítulo anterior, nós deixamos um item de ListBox
a mais para testarmos a conexão com o servidor. Quero apenas que apague o Label e o TEdit inserido e deixe o botão.
No código do botão, quero que insira o código da .

?
procedure TfrmMain.spbSincronizarClick(Sender: TObject);
var
1
LDataSetList : TFDJSONDataSets;
2
begin
3
MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation,
4
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
5
procedure (const AResult: TModalResult)
6
begin
7
//Efetua o download da tabela TITULOS vinda do Servidor DataSnap
8
LDataSetList := ModuloCliente.SrvServerMetodosClient.GetTitulos;
9
10
//Prepara o MemoryTable temporário
11
memTemporario.Active := False;
12
13
//Fazemos um teste para verifica se realmente há DataSet no retorno da função
14
Assert(TFDJSONDataSetsReader.GetListCount(LDataSetList) = 1);
15
16
//Adicionamos o conteúdo do DataSet "baixado" ao Memory Table
17
memTemporario.AppendData(TFDJSONDataSetsReader.GetListValue(LDataSetList, 0));
18
end
19
);
end;
Código prévio de sincronismo

Muito bom. A explicação não é longa, mas exige atenção. A primeira coisa que fazemos aqui é declarar uma variável
do tipo TFDJSONDataSets. Lembre-se de adicionar a unit referente a essa classe em nosso uses. Em seguida nós criamos
uma MessageDlg, mas há um porém nisso tudo que terei que dar uma pausa para explicar antes.

 __________________________________________________________________________________________
60
No RAD Studio XE7 houve uma pequena mudança no MessageDlg, agora ele precisa de um novo parâmetro para saber
que é uma janela Modal e que precisa obedecer a um retorno *O sim. Nesse caso, repare que estamos usando um
método anônimo, programação avançada do Delphi. Não entendeu? Vamos separar as coisas então:
Normalmente usamos um MessageDlg assim:
?
1 if MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation,
2 [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then
3 //fazemos algo
4 end;
Somente isso já fazia com que a aplicação parasse e aguardasse o usuário pressionar em Yes ou No, mas agora é
diferente. Precisamos fazer um “algo” mais. Após o último parâmetro, o HelpContext, passamos um método anônimo
para a MessageDlg, ou seja, criamos um PROCEDURE no último parâmetro, veja:
?
1 MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation,
2 [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
3 procedure (const AResult: TModalResult)
4 begin
5 //faz algo
6 end
7 );
8 end;
Dessa forma, quando o Yes for detectado, o código que será executado é o nosso procedure (const AResult:
TModalResult) […]. Entraremos em mais detalhes em outros tutoriais. Apenas entenda a nova sintax.

Em nosso método anônimo nós não temos muita codificação, repare. São apenas 4 (quatro) linhas, o resto
são comentários. Pois bem, a primeira coisa que fazemos é receber na variável LDataSetList a lista de DataSets recebida
do servidor com o uso do método GetTitulos. Nesse caso estamos recebendo apenas UM DataSet. Depois de fazer isso,
nós fechamos o MemoryTable. Adicionei um na janela, pois receberemos o conteúdo da Query do
Servidor e adicionaremos dentro do MemoryTable no cliente, assim podemos fazer qualquer coisa com ele depois.
A próxima 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 método AppendData do MemoryTable para adicionar TODO o conteúdo do DataSet TITULO ao
MemoryTable. O  já deixa o  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.

Nessa sétima parte de nosso tutorial, avançamos para o uso de Reflection do FireDAC como uma forma mais eficaz e
veloz de trazer informações do servidor DataSnap para o cliente. Criamos nossa tabela do Firebird e já estamos prontos
para efetuarmos o sincronismo de dados.

O leitor  fez um comentário pertinente a um ponto de nosso tutorial. Assim como mencionado no  vídeo
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 instalação
do Firebird 2.5. Isso faz com que o instalador renomeie a fdclient.dll para gds32.dll nos diretórios de sistema do
Windows.
Vale lembrar que o Firebird, para conhecimento dos leigos, é derivado do Interbase, mas em um passado bastante
remoto. Para quem não sabe, o Interbase até sua versão 6.0 era gratuito e de código-fonte aberto. Alguns
desenvolvedores russos copiaram o fonte e criaram o Firebird, que aos poucos foi se distanciando em termos de
funcionalidades em comparação ao Interbase. Hoje, são 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  para exportar dados do
servidor   para nosso aplicativo Mobile. Mas não vimos como fazer com que os dados recebidos sejam
inseridos no banco de dados local SQLite, veremos então como utilizar comandos  para fazer rapidamente
essas inclusões.
Na parte VII então vimos os seguintes tópicos:
 Criação da tabela do banco de dados no Firebird;
 Criação dos métodos de exportação de Títulos no lado servidor;
 Leitura e atualização da tabela Títulos local no dispositivo móvel;
Como mencionado, veremos aqui os seguintes recursos:
 Comandos ArrayDML para rápida inserção no banco;
 Ajustes na liberação de memória de objetos FORM;

Requisitos:
 Leitura: Tutorial: Criando meu app step-by-step Parte VII

A grande maioria dos desenvolvedores Delphi que conheço tem como costume usar ClientDataSet  e comandos do
tipo  e para criar rotinas de importação de dados em seus sistemas, isso porque é mais prático e rápido o
desenvolvimento de tais rotinas. Eu mesmo já cansei de criar ferramentas de importação usando esse método.
Entretanto, sabemos que é muito mais rápido fazer a importação usando comandos (instruções) SQL diretamente no
banco, haja vista que o banco processa as instruções com maior velocidade. Para os leigos, a explicação é simples.
Para o uso de  e (com aplicações m ulti-camadas), normalmente é necessário usar uma estrutura
semelhante a .

Estrutura básica de importação de dados

Note que vemos uma estrutura básica 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 temporário fazendo a inclusão em ClientDataSet1 , algo como a .
?
1 procedure TForm1.Importar;
2 begin
3 DataModule.cdsAuxiliar.First;
4 while not DataModule.cdsAuxiliar.EOF do
5 begin
6 DataModule.ClientDataSet1.Append;
7 DataModule.ClientDataSet1.FieldByName('CAMPO1').AsString := DataModule.cdsAuxiliar.FieldByName('CAMPO1').AsString;
DataModule.ClientDataSet1.FieldByName('CAMPO2').AsString := DataModule.cdsAuxiliar.FieldByName('CAMPO3').AsString;
8 DataModule.ClientDataSet1.FieldByName('CAMPO3').AsString := DataModule.cdsAuxiliar.FieldByName('CAMPO3').AsString;
9 DataModule.ClientDataSet1.Post;
10
11 DataModule.cdsAuxiliar.Next;
12 end;
13 DataModule.ClientDataSet1.ApplyUpdates(-1);
14 end;
 __________________________________________________________________________________________
62
Estrutura básica de importação

Essa estrutura é relativamente lenta em função de um fator bastante simples de entender. Quando chamamos o
método Post  do DataSet (nesse caso um ClientDataSet ) os dados são gravamos em memória, utilizando a memória do
computador que está executando o método. Ao final do nosso loop, fazemos então um , que informa
ao ClientDataSet  que os dados devem ser empacotados e enviados ao o . Todo esse processo exige
tempo, por isso a lentidão.
Podemos executar comandos SQL diretamente no que ness e caso já nos dará um ganho de
performance de cerca de 30%, ou seja, 30% mais rápida a inclusão no banco.
Mas creio que ficarão ainda mais surpresos quando disser que o método utlizado com FireDAC  e  ArrayDML nos dará
um ganho de perfomance de até 60%. Isso mesmo! Nos meus testes consegui aumentar em 60% a velocidade de
importação de dados.

A estratégia de uso do FireDAC  com ArrayDML para importação de dados ou simplesmente para qualquer inserção de


dados direto no banco é bem simples e de rápido entendimento. Vejamos.
No FireDAC , mais precisamente no FDQuery, temos o comando Execute assim como outros DataSets , mas nesse caso
podemos passar um número de inserções a ele e fazer o preenchimento de todos os parâmetros da query de uma só
vez. Em nosso exemplo anterior, na parte VII de nosso tutorial, iniciamos a sincronização usando o algoritmo
da
?
procedure TfrmMain.spbSincronizarClick(Sender: TObject);
var
1
LDataSetList : TFDJSONDataSets;
2
begin
3
MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation,
4
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
5
procedure (const AResult: TModalResult)
6
begin
7
//Efetua o download da tabela TITULOS vinda do Servidor DataSnap
8
LDataSetList := ModuloCliente.SrvServerMetodosClient.GetTitulos;
9
10
//Prepara o MemoryTable temporário
11
memTemporario.Active := False;
12
13
//Fazemos um teste para verifica se realmente há DataSet no retorno da função
14
Assert(TFDJSONDataSetsReader.GetListCount(LDataSetList) = 1);
15
16
//Adicionamos o conteúdo do DataSet "baixado" ao Memory Table
17
memTemporario.AppendData(TFDJSONDataSetsReader.GetListValue(LDataSetList, 0));
18
19
end
20
);
end;
 Algoritimo de sincronismo parte VII

Repare que paramos na parte que recebemos do servidor DataSnap os dados para importação e deixamos
um MemoryTable preparado para isso: . Ele possui os registros da tabela TITULOS vinda da
base Firebird  no servidor DataSnap. O que precisamos fazer aqui é percorrer esse MemoryTable e então incluir cada
registro da tabela em nossa tabela TITULOS no SQLite local.
Crie então um novo procedimento chamado  recebendo um único parâmetro do tipo ,
como na linha abaixo:
?
1 procedure AtualizarTitulos(AMemoryTable: TFDMemTable);
Receberemos nesse método a tabela que contém os dados a serem importados, ou seja, nosso memTemporario.
Pressione Ctrl + Shift + C para que o Delphi crie o escopo de nosso método e vamos a codificação. Digite o código
da

?
1 procedure TfrmMain.AtualizarTitulos(AMemoryTable: TFDMemTable);
2 const
3 _INSERT =

 __________________________________________________________________________________________
63
4 'INSERT INTO TITULOS ' +
5 '( ' +
6 ' ID_TITULO , ' +
7 ' TITULO , ' +
8 ' SUBTITULO , ' +
9 ' FOTO , ' +
10 ' MINIATURA ' +
11 ') ' +
12 'VALUES ' +
13 '( ' +
14 ' :ID_TITULO , ' +
15 ' :TITULO , ' +
16 ' :SUBTITULO , ' +
17 ' :FOTO , ' +
18 ' :MINIATURA ' +
19 '); ';
20 var
21 intNumInserts : Integer;
22
23 begin
24 {Número de registros recebidos do servidor}
25 intNumInserts := AMemoryTable.RecordCount;
26
27 DM.qryAuxiliar1.Active := False;
28 DM.qryAuxiliar1.SQL.Text := _INSERT;
29
30 {Informamos a Query Auxliar qual o número de Inserts será efetuado}
31 DM.qryAuxiliar1.Params.ArraySize := intNumInserts;
32 AMemoryTable.First;
33 while not AMemoryTable.Eof do
34 begin
35 DM.qryAuxiliar1.ParamByName('ID_TITULO').AsIntegers[AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('ID_TITULO').AsInteger;
36 DM.qryAuxiliar1.Para mByName('TITULO') .AsStrings [AMemoryTable.RecNo -1] := AMemoryTable.FieldByNa me('TITULO') .AsString;
DM.qryAuxiliar1.ParamByName('SUBTITULO').AsStrings [AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('SUBTITULO').AsString;
37 DM.qryAuxiliar1.Para mByName('FOTO') .AsBlobs [AMemoryTable.RecNo-1] := AMemoryTable.FieldByNa me('FOTO') .AsVariant;
38 DM.qryAuxiliar1.Para mByName('MINIATURA').A sBlobs [AMemoryTable.RecNo -1] := AMemoryTable.FieldByNa me('MINIATURA').AsVar iant;

39
40 AMemoryTable.Next;
41 end;
42
43 {Se houver mais de um registro a ser aplicado, então chama o Execute da Quuery Auxiliar}
44 if intNumInserts > 0 then
45 DM.qryAuxiliar1.Execute(intNumInserts, 0);
46
47 DM.qryAuxiliar1.Active := False;
48 end;
49
Código de sincronismo atualizado

A princípio parece longo o código e talvez confuso, mas acalme-se porque é fácil. Logo de início criamos uma constante
chamada que receberá a instrução SQLINSERT  para executarmos no servidor (nesse caso local). Não entrarei
em detalhes, sobre os comandos.
Em seguida declaramos uma variável que receberá a quantidade de registros presente no MemoryTable ,
o RecordCount . Isso será usado para alimentar a subpropriedade ArraySize de Params. O que queremos dizer aqui é
que teremos um array de conteúdos de campos para a LISTA de parâmetros de cada registro. Preenchemos esse array
com o conteúdo de cada campo e por último executamos.
Repare que efetuamos um Loop do MemoryTable  e preenchemos cada parâmetro usando seu respectivo tipo de dados
no plural (O plural foi apenas para chamar a atenção do leitor), veja:

?
1 DM.qryAuxiliar1.ParamByName('ID_TITULO').AsIntegers[AMemoryTable.RecNo-1] :=

Nos colchetes passamos o RecNo -1 (o array começa em 0 (zero)) do registro da MemoryTable  no momento de cada
interação do Loop. E recebemos o valore referente ao campo da tabela em questão.
Após terminar o loop, nós precisamos apenas executar a query usando o método Execute do qryAuxiliar1. O primeiro
parâmetro serve para indicarmos quantas vezes será executado o comando, nesse caso o número de registros
presentes no MemoryTable . O segundo parâmetro deixamos em 0 (zero) pois indica ao query que iremos começar as
inserções a partir do primeiro registro.

 __________________________________________________________________________________________
64
Por fim apenas fechamos a tabela. Esse mecanismo pode ser usado para basicamente qualquer inserção em lote que
você precise efetuar em seus sistemas.
A última providência que devemos tomar é retornar ao evento do botão Sincronizar e adiciona a linha abaixo para fazer
a chamada ao método AtualizarTitulos.
?
1 //Chamamos a rotina para incluir os dados recebidos na tabela Temporária,
2 //dentro da tabela no SQLite.
3 AtualizarTitulos(memTemporario);

Vamos voltar no tempo até a primeira parte de nosso tutorial. Nós criamos um método
no  frmMain chamado ShowForm que recebe um TFmxObject   como parâmetro. Esse método é responsável por abrir
os formulários de nosso aplicativo móvel. Recordemos o código:

?
1 procedure TfrmMain.ShowForm(AObject: TFmxObject);
2 var
3 I : Integer;
4 begin
5 for I := 0 to Pred(Self.lytMain.Children.Count) do
6 TControl(Self.lytMain.Children[I]).Visible :=
7 TControl(Self.lytMain.Children[I]) = TControl(AObject);
8 end;
 Código do ShowForm

A codificação aqui é bem simples como podemos ver. Apenas estamos deixando todos os formulários invisíveis, exceto
o formulário recebido no parâmetro. Entretanto temos um problema aqui, memória. Por enquanto temos apenas um
formulário a mais,  frmTitulos. Quando tivermos mais formulários poderemos ter problemas de estouro de memória,
algo que em Desktop pode ser facilmente ignorado pois temos mais processamento e mais memória, embora não seja
uma boa prática manter MemoryLeaks.
?
1 if not Assigned(FTitulos) then
2 FTitulos := TfrmTitulos.Create(Self);
Pegando como exemplo o item de menu Titulos, vemos que estamos fazendo um primeiro teste para verificar se existe
instância do formulário de títulos e o criamos usando um Create(Self). A liberação de memória desse formulário,
definitiva, fazemos no OnClose do formulário principal.
?
1 if Assigned(FTitulos) then
2 FTitulos.DisposeOf;
Até aqui nenhum problema e nenhuma novidade. Iniciantes e usuários Avançados do Delphi irão concordar que não
há nada de novo. Mas precisamos pensar na hipótese iminente de termos mais formulários. Quando isso acontecer,
não podemos deixar nossos forms sempre ativos na memória, pois como mencionado anteriormente, poderemos
receber mensagens de erros e um grande problema com . Resolvi esse problema de forma até simples,
embora trabalhosa.
#Dica: MemoryLeaks, para os leigos, é o estouro de memória na aplicação, ou seja, objetos não liberados de memória.
Vamos lá. No mesmo evento criaremos uma lista de objetos a serem destruídos e então os liberaremos de
memória. Para começarmos essa rotina, primeiro precisamos de um novo formulário. Pegando a ideia inicial de nosso
app, vamos criar um novo formulário chamado frmUsuarios. Clique em File>New>Multi-DeviceForm– Delphi . Use HD
Form como template. Modifique a propriedade  para  e salve a unit como . Não faremos
nada com o formulário agora. Apenas o usaremos como parte de nossa rotina para testes em nossa versão 2
de ShowForm.
Lembre-se de retirar a variável com o nome do formulário na área  do form. Localize a instrução no código-
fonte e apague-a.
?
1 var
2 frmUsuarios: TfrmUsuarios;

 __________________________________________________________________________________________
65
Retorne ao formulário principal e adicione o novo form a seção  usando File>UseUnit . Crie uma nova variável
em Private com o nome  do tipo . No evento  do segundo item de menu, digite o código
da :

?
1 procedure TfrmMain.lstitUsuariosClick(Sender: TObject);
2 begin
3 if not Assigned(FUsuarios) then
4 FUsuarios := TfrmUsuarios.Create(Self);
5
6 MultiView1.MasterButton := FUsuarios.spbBack;
7 {Forçamos o fechamento do menu no clique do item}
8 MultiView1.HideMaster;
9
10 {Adiciona o Layout de Pedidos ao Layout Principal que controla tudo}
11 lytMain.AddObject(FUsuarios.lytUsuarios);
12
13 {Deixa todos os layouts invisíveis e deixa o layout alvo visível}
14 ShowForm(FUsuarios.lytUsuarios);
15 end;
Código de abertura do formulário de usuários

Isso já será suficiente para termos acesso aos usuários. Claro, precisamos trabalhar no form, mas isso deixarei a cargo
de cada um. O que quero que observem aqui é a primeira linha do código. Estamos testando a variável FUsuarios e
criando o formulário se ele não existir, como fizemos com o form de títulos. Se executarmos o app, poderemos
alternar agora de usuários para títulos e vice-versa, mas o formulário de usuários sempre estará no ar, exceto quando
o usuário fechar a aplicação. O que faremos?
Acesse o método ShowForm e vamos começar a trabalhar nele. Digite o código completo da .
?
1 procedure TfrmMain.ShowForm(AObject: TFmxObject);
2 var
3 I : Integer;
4 strFRM : String;
5 FListaForms : TStringList;
6 begin
7 FListaForms := TStringList.Create;
8
9 for I := 0 to Pred(Self.lytMain.Children.Count) do
10 begin
11 TControl(Self.lytMain.Children[I]).Visible :=
12 TControl(Self.lytMain.Children[I]) = TControl(AObject);
13
14 strFRM := UpperCase(TControl(Self.lytMain.Children[I]).Owner.Name);
15 if ((strFRM <> UpperCase(frmMain.Name)) and (strFRM <> UpperCase(FTitulos.Name))) and
16 not (TControl(Self.lytMain.Children[I]).Visible) then
17 {Adiciona na Lista de Destruição dos Forms}
18 FListaForms.Add(strFRM);
19 end;
20
21 for I := Pred(FListaForms.Count) downto 0 do
22 begin
23 if (Assigned(FUsuarios)) and (FListaForms[I] = UpperCase(FUsuarios.Name)) then
24 begin
25 FUsuarios.DisposeOf;
26 FUsuarios := nil;
27 FListaForms.Delete(I);
28 end;
29 end;
30
31 FListaForms.DisposeOf;
32 end;
Código modificado de ShowForm

Repare que fizemos modificações significativas. Criamos duas variáveis para receber o nome do formulário e outra para
gerenciar os objetos que serão destruídos. Basicamente o que faremos é detectar quando trocamos de um formulário
para outro e destruímos o formulário anterior, exemplo:
 Quando o usuário acessar o menu Usuários / Clientes, criaremos o formulário na memória.

 __________________________________________________________________________________________
66
 Ao retornar para Títulos, destruiremos Usuários / Clientes.
 Assim acontecerá com outros objetos.
Nesse esquema, o único formulário que não será destruído, por ser nosso default, será o de Títulos. Por isso detectamos
quando estamos passando por sua instância e não o destruímos.
Criamos a variável  do tipo  e iniciamos o Loop que já tínhamos antes, porém com uma alteração.
A variável recebe o nome do formulário da interação atual do Loop. Se esse formulário NÃO for o formulário
Principal nem Títulos, adicionamos ele a lista de formulários a serem destruídos ou não.
Após o término do primeiro loop, fazemos um loop na lista de formulários. Ai começa nossa mágica que não é nada
complicada. Nós fazemos um loop de trás para frente na lista de formulários (FListaForms). Se o formulário estiver
criado em memória E for igual a iteração atual do loop, então liberamos ele usando DisposeOf, marcamos sua variável
como NIL e deletamos na lista de formulários.
Eu já expliquei, mas não custa falar novamente. Usamos em Mobile o método , recomendação encontrada
em eBooks do e  outros autores. O .Free ou .FreeAndNil , como estamos acostumados, funciona,
entretanto pode demorar até que o sistema operacional passe pelo objeto e o libere de memória. Quem faz isso é
o   (Coletor de Lixo) no  Android  e iOS. Para evitar que o formulário demore para ser destruído,
usamos DisposeOf que envia instrução ao sistema operacional para destruir imediatamente o nosso objeto. Isso
funciona não só para formulários, mas para outras variáveis e objetos. É o que fazemos logo em seguida.
?
1 FListaForms.DisposeOf;
Com todas essas verificações e cuidados, conseguimos manter um app mais fluido e confiável.

Fizemos basicamente duas grandes modificações nesse tutorial. Aprendemos a aproveitar o conteúdo recebido do
servidor DataSnap e incluímos os registros em nossa base de dados local usando ArrayDML. Também vimos como fazer
uma modificação significativa em nossa rotina de abertura de formulários 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
botões de hardware no  Android, os botões  e  Esses botões são comuns e aparecem em todos os aparelhos
munidos de sistema operacional Android, sejam botões físicos ou virtuais. O botão Home também existe e é comum,
mas varia um pouco o uso em cada aparelho. O aparelho que usamos para testar nossas aplicações por exemplo,
um SamsungWinDuos , possui todos esses botões em formato físico, comum em aparelhos Samsung.  Nosso Tablet
Multilaser  por outro lado, possui apenas botões virtuais.
Como devem ter notado, essa fase de nosso tutorial será mais light, mas não menos importante. Além de vermos como
fazer uso dos botões Back e Menu em nosso aplicativo, aprenderemos dicas importantes relacionadas ao controle da
aplicação usando tais botões.
Para relembrarmos o que vimos na edição passada, veja abaixo em forma de tópicos. Nós vimos basicamente o uso
de  ArrayDML e algumas dicas para liberação de memória.
 Comandos ArrayDML para rápida inserção no banco;
 Ajustes na liberação de memória de objetos FORM;
E como mencionado, veremos aqui:
 Como fazer uso dos botões Back e Menu?

Requisitos
 Leitura: Artigos de I a VIII desse tutorial.

Antes de codificarmos nosso sistema, vamos entender qual a ideia de usar os botões 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 são acessadas via Menu Principal . Algumas delas possuem navegação, ou seja, botões virtuais
Próximo e  Anterior. É aqui que entra o botão Back.Queremos que ao tocar no botão, uma aba (TabControl)  retorne. Já
o botão Menu, vamos usa-lo em dois momentos:
1. Quando o usuário desejar abrir o Menu Principal;
2. E quando houverem menus Pop-up;

Agora, onde detectar que o usuário tocou nos botões? Os botões de hardware no Android precisam ser programados
manualmente, praticamente hardcoded,  isso porque eles não 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 navegação. Temos
um TLayout   no form principal e outro TLayout   em cada nova janela, e ao abrir uma nova janela, nós adicionamos o
Layout do alvo ao Layout do form principal. ( )

 __________________________________________________________________________________________
68
 Exemplo de tela com menu

Em outras palavras, é como se adicionássemos os demais formulários ao formulário principal, portanto o comando
central é o Form Principal. Se colocarmos algum código nos evento   do formulário alvo, esse não será
acionado, ao contrário, o evento acionado será o  do form principal. Por isso é nele que programaremos tudo.
Selecione o evento OnKeyUp e clique duas vezes nele para iniciarmos a programação.
A primeira providência é declararmos uma nova variável a esse evento.
  do tipo  Essa variável será responsável por verificar se o teclado está visível, pois
se estiver, ignoramos os botões Back e Menu.
O escopo do nosso evento pode ser visto na .
?
1 var
2 FService : IFMXVirtualKeyboardService;
3
4 begin
5
6 end;
 Início da codificação do OnKeyUp

Agora vamos implementar todo o mecanismo de detecção dos botões na   Continuemos a codificação
recebendo o estado do teclado na variável FService. A primeira linha do evento OnKeyUp segue como abaixo:
#Dica: Para termos acesso aos TPlatformServices e a Interface IFMXVirtualKeyboardService, declare as units
FMX.VirtualKeyboard, FMX.Platform, FMX.Helpers.Android, FMX.Platform.Android, no uses do form.
?
1 {Recebe o estado do teclado virtual}
2 TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FSe
Em seguida começamos toda a brincadeira. Para o botão Back basta checarmos o estado da variável  presente no
evento. Perceba que a assinatura do evento OnKeyUp possui um  um  e um  Testaremos Key para
verificar qual tecla (ou botão) foi pressionada. Podemos usar apenas:

?
1 if Key - vkHardwareBAck then
2 //Codificação

Veja como é simples. Para o botão menu, basta testarmos se o Key é igual a  O código-fonte da
 refere-se ao código completo do nosso mecanismo, então vamos entender uma por uma das chamadas.
?
1 procedure TfrmMain.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char;
2 Shift: TShiftState);
3 var
4 FService : IFMXVirtualKeyboardService;
5
 __________________________________________________________________________________________
69
6 begin
7 {Recebe o estado do teclado virtual}
8 TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(FService));
9 {Se o botão back pressionado e o teclado virtual ativo, não faz nada}
10 if Key = vkHardwareBack then
11 begin
12 if (FService <> nil) and (TVirtualKeyboardState.Visible in FService.VirtualKeyBoardState) then
13 begin
14 //Reservado, não faz nada
15 end
16 else
17 begin
18 {Verifica qual formulário está ativo e então chama o método Voltar}
19 {Se NÃO estiver com a listagem de pedidos aberta}
20 {$Region 'Menu'}
21 if MultiView1.IsShowed then
22 begin
23 MultiView1.HideMaster;
24 Key := 0;
25 end
26 {$EndRegion}
27
28 {$Region 'Titulos'}
29 else if (FTitulos.lytTitulos.Visible) and not (FTitulos.tabctrlTitulos.ActiveTab = FTitulos.tbitemLisTitulos) then
30 FTitulos.PressionouVoltar
31 else if (FTitulos.lytTitulos.Visible) and (FTitulos.tabctrlTitulos.ActiveTab = FTitulos.tbitemLisTitulos) then
32 begin
33 MessageDlg('Deseja sair do aplicativo?', TMsgDlgType.mtConfirmation,
34 [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
35 procedure (const AResult: TModalResult)
36 begin
37 if AResult = mrYes then
38 begin
39 {$IFDEF ANDROID}
40 MainActivity.finish;
41 {$ELSE}
42 exit;
43 {$ENDIF}
44 end;
45 end
46 );
47 end
48 {$EndRegion}
49
50 {$Region 'Preferências'}
51 else if (Assigned(FPreferencias)) then
52 begin
53 MessageDlg('Deseja sair do aplicativo?', TMsgDlgType.mtConfirmation,
54 [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
55 procedure (const AResult: TModalResult)
56 begin
57 if AResult = mrYes then
58 begin
59 {$IFDEF ANDROID}
60 MainActivity.finish;
61 {$ELSE}
62 exit;
63 {$ENDIF}
64 end;
65 end
66 );
67 end;
68 {$EndRegion}
69
70 Key := 0;
71 end;
72 end
73 {Botão Menu do Android}
74 else if Key = vkMenu then
75 begin
76 if (FService <> nil) and (TVirtualKeyboardState.Visible in FService.VirtualKeyBoardState) then
77 begin
78 //Reservado, não faz nada
79 end
80 {O menu está sendo mostrado, apenas fecha o menu}
81 else
82 begin
83 if MultiView1.IsShowed then
84 HideBackground
85 {Verifica se o Pedidos está sendo mostrado e não está na lista de pedidos, para então abrir o menu}
86 else if (FTitulos.lytTitulos.Visible) then
87 FTitulos.PressionouMenu;
88
89 Key := 0;
90 end;
91 end;
92
end;
 Código Completo

O código não contempla todas as situações, a ideia é somente dar o caminho das pedras. Na primeira parte de nosso
código referente ao botão Back,  nós verificamos se o menu principal está aberto. Caso ele esteja, nós verificamos se o
menu principal está aberto, por isso a instrução MuiltiView1.HideMaster. Ela fecha o menu. Caso contrário, passamos
a verificar qual janela está aberta. Fazemos isso usando as variáveis de cada formulário, ex. Se o layout   principal
de  estiver visível, significa que a janela de  está aberta no momento. Para que o menu back funcione,
 __________________________________________________________________________________________
70
testamos também se estamos na aba nesse caso chamamos o método  do
formulário Titulos. Esse método deverá ser criado como a seguir:
?
1 procedure TfrmTitulos.PressionouVoltar;
2 begin
3 if tabctrlTitulos.ActiveTab = tbitemDetalhes then
4 tabctrlTitulos.Previous();
5 end;
Perceba como é simples. Após verificar que o menu não está aberto e que não estamos na aba principal de Titulos, nós
chamamos o método PressionouVoltar  da tela alvo e deixamos que o método decida o que fazer. Nesse caso
verificamos se a aba  está aberta, caso esteja, então voltamos uma aba.
Dessa maneira faremos em todas as janelas, criando um método  e codificando o que queremos que
aconteça, tela a tela. A mesma codificação, fazemos para a tela de preferências de sistema, a única diferença é que
testamos se a janela está criada usando um na variável do form  isso porque preferências é criada e destruída
sempre.
Retornando ao formulário principal, o final da codificação diz respeito ao botão menu. Nesse caso testamos se o Key é
igual a para então fazermos os devidos testes. Em nosso exemplo, temos apenas um teste que é referente a
 janela Titulos. Caso ela esteja visível, então chamamos o método  do próprio  ou seja, mais
uma vez o controle é dado ao formulário. O método  deverá ser criado como a seguir:
?
1 procedure TfrmTitulos.PressionouMenu;
2 begin
3 if (tabctrlTitulos.ActiveTab = tbitemLisTitulos) then
4 frmMain.MultiView1.ShowMaster
5 else if (tabctrlTitulos.ActiveTab = tbitemLisTitulos) and (DM.qryTitulos.State in dsEditModes) then
6 imgFotoClick(imgFoto);
7 end;

Como mencionado, mais uma vez o formulário tem o controle da situação. Aqui nesse caso estamos verificando qual
aba está aberta. Se a aba visível for a principal, abrimos o menu principal. Se  for a aba visível e estivermos em
modo de  descemos o menu  para que o usuário troque a foto do título.
Basicamente é só isso que precisamos fazer. Parece complicado, mas na verdade somente é trabalhoso e precisamos
ter muita atenção na codificação. A última coisa a explicar aqui é sobre a linha  vista em vários lugares no
código da tela principal,  Isso é necessário, pois se o Key não receber zero a após o pressionamento, o evento
continuará a executar linha a linha e então teremos problemas.
Fica agora ao seu gosto, codificar o restante das telas usando como base o código explicado acima.

O usuário Android está bastante acostumado a usar os botões de hardware para voltar telas ou abrir menus. Por isso
é importantíssimo que codifiquemos cada botão para que a navegação do app fique mais transparente. Em iOS isso
não é possível, isso porque existem poucos botões e o que exitem estão destinados a funções específicas. A Apple não
permite que você utilize um botão de hardware para alguma função diferente da que ele foi criado, exemplo. Um botão
para aumentar volume, apenas aumenta volume e nada mais. Recentemente a Apple liberou o uso do botão Aumentar
Volume para que seja usado em aplicativos de foto, nada mais.
Outro detalhe não mencionado na codificação foi a instrução  Essa instrução finaliza totalmente a
aplicação Android, como se fosse um  em aplicativos Desktop. Isso é de muita importância, só
com essa instrução garantimos que o app será totalmente fechado e que todas as variáveis, forms, etc sejam liberados
de memória. Em iOS isso não é necessário.
Caso tenha interesse em ver mais informações sobre outros botões, verifique a  DocWiki da Embarcadero.

 __________________________________________________________________________________________
71
Chegamos a última parte de nosso . Até agora vimos como fazer toda a parte de
criação do aplicativo desde a concepção, 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 . Nesse tutorial nós veremos como fazer a exclusão,
atualização e inserção de novos títulos no servidor Firebird usando o aplicativo Mobile.
Na parte anterior vimos:
 Comandos ArrayDML para rápida inserção no banco;
 Ajustes na liberação de memória de objetos FORM;
Como mencionado veremos a seguir:
 Como criar um método para excluir registros do aplicativo móvel 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

Antes de iniciarmos nosso tutorial, vamos relembrar algumas partes importantes para que possamos dar continuidade,
começando pelo nosso DataModule na aplicação Mobile. Nós temos em nosso DMapenas um
componente FDConnection  para acesso ao nosso banco de dados SQLite e duas queries. Uma para listar os títulos da
locadora e outra para efetuar pesquisas. Em nosso evento OnCreate,  nós atribuímos as devidas configurações de
acesso ao banco local e então conectamos a ele. Podemos ver isso na  e em nossa .

 DataModule Mobile
?
1 procedure TDM.DataModuleCreate(Sender: TObject);
2 var
3 sPath: String;
4 begin
5 with fdcConexao do
6 begin
7 {$IF DEFINED(IOS) OR DEFINED(ANDROID)}
8 Params.Values['DriverID'] := 'SQLite';
9 Params.Values['OpenMode'] := 'ReadWrite';
10 try
11 sPath := TPath.Combine(TPath.GetDocumentsPath, 'Locadora.s3db');
12 Params.Values['Database'] := TPath.Combine(TPath.GetDocumentsPath, 'Locadora.s3db');
13 Connected := True;
14 except on E: Exception do
15 begin
16 ShowMessage(E.Message);
17 end;
18 end;
19 {$ELSE}
20 try
21 Params.Values['Database'] := '$(DB_LOCADORA_SQLITE)';
22 Connected := True;
23 except on E: Exception do
24 begin
 __________________________________________________________________________________________
72
25 ShowMessage(E.Message);
26 end;
27 end;
28 {$ENDIF}
29 end;
30 end;
 OnCreate do DataModule

Até o presente momento, nosso aplicativo é capaz apenas de listar os títulos já disponíveis no aparelho celular assim
como fazer um breve sincronismo trazendo os títulos do servidor para o aparelho celular através de um
botão Sincronizar  presente na tela principal.
Em nossa janela de títulos, nós preparamos para que ela possa mostrar os títulos em uma lista e ao tocar nela podemos
ver seus detalhes. Em  frmTitulos temos um TabControl   com duas abas, tbitemTitulos  e tbitemDetalhe como visto
na .

 Design da tela de Títulos

Na aba Detalhes  faremos a inclusão, alteração e exclusão de títulos da tabela em questão. Teremos que criar alguns
métodos no servidor para que possamos trabalhar essas integrações.
Retornando a tela principal, nosso botão Sincronizar   temos a função de buscar no servidor os dados atualizados e
gravar no banco de dados local. Vejamos o código-fonte na .
?
1 procedure TfrmMain.spbSincronizarClick(Sender: TObject);
2 var
3 LDataSetList : TFDJSONDataSets;
4 begin
5 MessageDlg('Confirma sincronismo de dados?', TMsgDlgType.mtConfirmation,
6 [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
7 procedure (const AResult: TModalResult)
8 begin
9 //Efetua o download da tabela TITULOS vinda do Servidor DataSnap
10 LDataSetList := ModuloCliente.SrvServerMetodosClient.GetTitulos;
11
12 //Prepara o MemoryTable temporário
13 memTemporario.Active := False;
14
15 //Fazemos um teste para verifica se realmente há DataSet no retorno da função
16 Assert(TFDJSONDataSetsReader.GetListCount(LDataSetList) = 1);
17
18 //Adicionamos o conteúdo do DataSet "baixado" ao Memory Table
19 memTemporario.AppendData(TFDJSONDataSetsReader.GetListValue(LDataSetList, 0));
20
21 //Chamamos a rotina para incluir os dados recebidos na tabela Temporária, dentro da tabela no SQLite.
22 AtualizarTitulos(memTemporario);
23
24 end
25 );
26 end;
27

 __________________________________________________________________________________________
73
28 //Método de atualização
29 procedure TfrmMain.AtualizarTitulos(AMemoryTable: TFDMemTable);
30 const
31 _INSERT =
32 'INSERT INTO TITULOS ' +
33 '( ' +
34 ' ID_TITULO , ' +
35 ' TITULO , ' +
36 ' SUBTITULO , ' +
37 ' FOTO , ' +
38 ' MINIATURA ' +
39 ') ' +
40 'VALUES ' +
41 '( ' +
42 ' :ID_TITULO , ' +
43 ' :TITULO , ' +
44 ' :SUBTITULO , ' +
45 ' :FOTO , ' +
46 ' :MINIATURA ' +
47 '); ';
48 var
49 intNumInserts : Integer;
50
51 begin
52 {Número de registros recebidos do servidor}
53 intNumInserts := AMemoryTable.RecordCount;
54
55 DM.qryAuxiliar1.Active := False;
56 DM.qryAuxiliar1.SQL.Text := _INSERT;
57
58 {Informamos a Query Auxliar qual o número de Inserts será efetuado}
59 DM.qryAuxiliar1.Params.ArraySize := intNumInserts;
60 AMemoryTable.First;
61 while not AMemoryTable.Eof do
62 begin
63 DM.qryAuxiliar1.ParamByName('ID_TITULO').AsIntegers[AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('ID_TITULO').AsInteger;
64 DM.qryAuxiliar1.Para mByName('TITULO') .AsStrings [AMemoryTable.RecNo -1] := AMemoryTable.FieldByNa me('TITULO') .AsString;
DM.qryAuxiliar1.ParamByName('SUBTITULO').AsStrings [AMemoryTable.RecNo-1] := AMemoryTable.FieldByName('SUBTITULO').AsString;
65 DM.qryAuxiliar1.Para mByName('FOTO') .AsBlobs [AMemoryTable.RecNo-1] := AMemoryTable.FieldByNa me('FOTO') .AsVariant;
66 DM.qryAuxiliar1.Para mByName('MINIATURA').A sBlobs [AMemoryTable.RecNo -1] := AMemoryTable.FieldByNa me('MINIATURA').AsVari ant;
67
68 AMemoryTable.Next;
69 end;
70
71 {Se houver mais de um registro a ser aplicado, então chama o Execute da Quuery Auxiliar}
72 if intNumInserts > 0 then
73 DM.qryAuxiliar1.Execute(intNumInserts, 0);
74
75 DM.qryAuxiliar1.Active := False;
76 end;
77
 Sincronizando dados

Apenas para relembrar, nós estamos criando uma variável do tipo TFDJSONDataSets   que é a classe utilizada para
exportar os dados do servidor para o mundo externo, nesse caso para nosso cliente. Essa classe traz o
próprio DataSet  aberto do servidor no cliente de acordo com os devidos filtros aplicados. Em seguida nós adicionamos
esse DS em nosso componente MemTable através do método AppendData do componente. Feito isso basta
criarmos algum método para percorrer os registros. É o que fazemos no método  AtualizarTitulos. Aqui nós
percorremos a MemTable  e adicionamos um a um no banco de dados local. Algo parecido pode ser efetuado no
servidor, ou seja, podemos enviar um FDJSONDataSets  para o servidor e fazer o trabalho de inclusão no banco.

Antes de iniciarmos o sincronismo, faremos com que nossa tela de títulos se torne totalmente independente, ou seja,
poderemos incluir, excluir e alterar registros na tela do celular. Nós montaremos a tela completa de edição, inclusive a
inclusão de fotos. Vamos lá:
Nossa janela de títulos a essa altura do campeonato deve conter um componente Layout   chamado lytTitulos  e dentro
dele um TabControl  com o nome tbctrlTitulos. Caso ainda não tenha adicionado a aba de detalhes
nesse tabcontrol, faça isso agora. Nós precisamos de duas abas. Uma se chamará tbitemTitulos e a outra
tbitemDetalhe. Mude para a aba de detalhe e adicione a ela duas  A primeira delas ficará alinhada ao topo e
a segunda abaixo da TabItem.
Na toolbar superior insira os seguintes componentes e configure-os de acordo com o descrito:
1. SpeedButton:

 __________________________________________________________________________________________
74
1.  spbVoltar
2. backtoolbutton
3.  left
4.  8
2. SpeedBuuton:
1.  spbCancelar
2. : deletetoolbutton
3.  left
4. :8
3. SpeedButton:
1.  spbSalvar
2. : donetoolbutton
3.  right
4.  8
4. SpeedButton:
1.  spbEditar
2. : composetoolbuttonbordered
3.  right
4.  8
5. Label:
1. lblTituloDet
2. : listboxheaderlabel
3.  Contents
4.  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) próximos
de 89px.
Nesse mesmo item de listbox  adicione um TLayout  e coloque-o como alinhamento Client. Dentro desse layout adicione
outro ListBox que conterá dois novos itens. Insira em cada item um componente TEdit   para cada campo da tabela
de Títulos,  ou seja, um para Título  e outro para SubTitulo,  veja abaixo:
 TEdit:
o  edtTitulo
o  Client
o  todas como 8px
 TEdit:
o edtSubTitulo
o  Client
o  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, nós termos algo parecido
com a .

 __________________________________________________________________________________________
75
 Aba de detalhe

Agora precisaremos criar os devidos métodos para ativar e desativar botões e também para colocar em modo de edição
ou adição.

A primeira providência é criarmos um método para ativar e desativar os botões. Para isso, acesse a
área Public do  form e crie um método com o nome  AtualizarBotoes, como abaixo:
AtualizarBotoes;
Pressione Ctrl+Shift+C   para criar o escopo do método e codifique-o como na . E vamos a explicação. Nós
deixamos os botões Voltar,Editar  e Excluir   visíveis somente se estivermos em modo Browse, ou seja, visualizando os
dados. Os botões Salvar  e Cancelar   somente ficam visíveis se estivemos em modo de edição. Ainda mudamos a
propriedade ReadOnly  de alguns componentes para permitir digitação.
?
1 procedure TfrmTitulos.AtualizarBotoes;
2 begin
3 spbVoltar.Visible := (DM.qryTitulos.State = dsBrowse);
4 spbEdicao.Visible := (DM.qryTitulos.State = dsBrowse);
5 spbExcluir.Visible := (DM.qryTitulos.State = dsBrowse);
6
7 spbCancelar.Visible := (DM.qryTitulos.State in dsEditModes);
8 spbSalvar.Visible := (DM.qryTitulos.State in dsEditModes);
9
10 edtTitulo.Enabled := (DM.qryTitulos.State in dsEditModes);
11 edtSubTitulo.Enabled := (DM.qryTitulos.State in dsEditModes);
12 edtAno.Enabled := (DM.qryTitulos.State in dsEditModes);
13
14 edtTitulo.ReadOnly := (DM.qryTitulos.State = dsBrowse);
15 edtSubTitulo.ReadOnly := (DM.qryTitulos.State = dsBrowse);
16 edtAno.ReadOnly := (DM.qryTitulos.State = dsBrowse);
17
18 if (DM.qryTitulos.State in dsEditModes) then
19 begin
20 edtTitulo.StyleLookup := 'editstyle';
21 edtSubTitulo.StyleLookup := 'editstyle';
22 edtAno.StyleLookup := 'editstyle';
23 lblTituloDet.Text := 'Editando...';
24 end
25 else
26 begin
27 edtTitulo.StyleLookup := 'transparentedit';
28 edtSubTitulo.StyleLookup := 'transparentedit';
 __________________________________________________________________________________________
76
29 edtAno.StyleLookup := 'transparentedit';
30 lblTituloDet.Text := 'Detalhes';
31 end;
32 end;
AtualizarBotões

Acesse o evento OnClick do botão voltar  e digite o código abaixo para que possamos Cancelar  a edição caso o usuário
deseje retornar para a tela anterior.
?
1 if DM.qryTitulos.State in dsEditModes then
2 DM.qryTitulos.Cancel;
3
4 DM.qryTitulos.Active := False;
5 DM.qryTitulos.Active := True;
6
7 tabctrlTitulos.Previous;
Uma providência que poderíamos criar aqui seria perguntar ao usuário com um MessageDlg  se ele realmente deseja
sair da tela e cancelar o cadastro. Mas isso fica a critério do leitor.
No botão cancelar insira o código:
?
1 DM.qryTitulos.Cancel;
2 AtualizarBotoes;
Assim nós cancelamos a edição e atualizamos os botões de tela. Em seguida vamos mexer no evento OnClick  do
botão Salvar, veja como fica:
?
1 if DM.qryTitulos.State in [dsInsert] then
2 DM.qryTitulos.FieldByName('ID_TITULO').AsInteger := DM.GetIDFromTable('TITULOS');
3
4 DM.qryTitulos.Post;
5 AtualizarBotoes;
Aqui é simples entendermos. Se o cadastro estiver em estado de inserção, ou seja, cadastro novo. Nós chamamos o
métodos de criação de ID para esse registro. Então gravamos o registro e atualizamos novamente os botões da tela.
Por fim, codifique o botão Editar  como a seguir:
?
1 DM.qryTitulos.Edit;
2 AtualizarBotoes;
3 edtTitulo.SetFocus;
Muito fácil, apenas editamos e atualizamos novamente os botões. Focamos em cima do primeiro edit   para que o
teclado suba. O último botão é o de exclusão. Nesse codificaremos como abaixo, mas voltaremos mais tarde aqui para
fazermos uma alteração.
?
1 MessageDlg('Confirma exclusão do título selecionado?', System.UITypes.TMsgDlgType.mtConfirmation,
2 [System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo], 0,
3 procedure(const AResult: TModalResult)
4 begin
5 case AResult of
6 mrYES :
7 begin
8 DM.qryTitulos.Delete;
9 Self.spbVoltarClick(Sender);
10 end;
11 end;
12 end
13 )
Apenas perguntamos ao usuário se confirma a exclusão e em caso positivo chamamos o método Delete do Query e o
botão voltar automaticamente para que a tela seja atualizada. Nós teremos que voltar aqui mais tarde para poder
colocar a exclusão também no servidor.
Se você rodar sua aplicação nesse momento, tudo funcionará perfeitamente com exceção da parte de fotos que não
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 . Seu StyleLookup  será  e
seu código como a seguir:
?
1 DM.qryTitulos.Append;
2 tabctrlTitulos.Next;
3 AtualizarBotoes;

 __________________________________________________________________________________________
77
Aqui apenas chamamos o método de inclusão do  e mudamos para a aba de detalhes sem esquecer de atualizar
os botões de tela.

Agora faremos a parte de seleção de fotos através da câmera ou da biblioteca. Insira na tela um
componente TActionList   e clique duas vezes nele. Clique no botão de seta da janelinha que aparece e selecione New
Standard Action. Localize as opções Media Library e adicione um TTakePhotoFromLibraryAction e um
TTakePhotoFromCameraAction. Dê os nomes de actFotoBiblioteca  e actFotoCamera, respectivamente.
No evento OnDidFinishTaking  digite o código para uso da foto, como abaixo:
?
1 DM.qryTitulosFOTO.Assign(Image);
Como isso nós estamos recebendo a foto tirada/escolhida pelo usuário e inserindo direto no respectivo campo da base
de dados. Por fim, vá até o evento OnClick do imgFoto e adicione o código abaixo:
?
1 if DM.qryTitulos.State in dsEditModes then
2 begin
3 frmMain.ShowBackground(Self.lytTitulos, lstitCancelarClick);
4 lstPopUpFoto.Visible := True;
5 lstPopUpFoto.AnimateFloat('position.y', 0);
6 lstPopUpFoto.BringToFront;
7 end
8 else
9 ShowMessage('Você precisa estar em modo de edição!');
Perceba que é bem fácil entendermos. Estamos primeiro verificando se a tabela está em modo de edição e então
mostramos umpop-upmenu criado em aulas anteriores. Nesse pop-up  nós teremos as opções NovoFoto,Bibliotecae
Cancelar . Basta voltar no tutorial que falamos disso e veja a codificação. Finalizamos por aqui.
Teste a aplicação e verifique se tudo funcionou.

Nossa brincadeira agora começa a ficar mais séria. Até o momento estamos alterando somente no dispositivo móvel,
ou seja, se excluirmos algo no aparelho, o registro será excluído apenas do aparelho. Quando o usuário fizer uma nova
sincronização, o dado virá novamente. Então voltemos ao código-fonte do servidor e vamos criar um método para
exclusão. Acesse o nosso único ServerMethod no servidor DataSnap  e insira na área   o seguinte método e
pressioneCtrl+Shift+C  para criar o escopo do método:
?
1 function ExcluirTitulo(ATitulo: Integer): Boolean;
Codifique esse métodos como abaixo. Insira nesse ServerMethod  um FDQuery  e dê o nome de qryAuxiliar. O que
estamos fazendo é bem simples. Criamos uma constante com a instrução DELETE  para excluir título da base de dados.
Fechamos a query, inserimos o valor do parâmetro  ATitulo que será enviado pelo Cliente e então usamos
o ExecSQL.  Caso dê tudo certo, resultamos True, caso contrário Falsepara que possamos enviar uma mensagem ao
usuário.
?
1 function TSrvServerMetodos.ExcluirTitulo(ATitulo: Integer): Boolean;
2 const
3 _DELETE = 'DELETE FOM TITULOS WHERE ID_TITULO =:ATITULO';
4 begin
5 try
6 qryAuxiliar.Active := False;
7 qryAuxiliar.ParamByName('ATITULO').AsInteger := ATitulo;
8 qryAuxiliar.ExecSQL;
9
10 Result := True;
11 except
12 Result := False;
13 end;
14 end;
Compile o servidor e execute. Em seguida inicie o servidor.

 __________________________________________________________________________________________
78
Retorne agora ao nosso cliente e vamos fazer as devidas alterações para que possamos excluir o dado nos dois locais.
Abra nosso módulo cliente onde o componente DSRESTConnection  se encontra. Clique com o direito nele e mande
gerar novamente nosso arquivo de Proxy. Note que agora temos o método ExcluirTitulo.  Abra o formulário  frmTitulos e
vamos fazer a alteração no botão de exclusão. Caso ainda não tenha incluído a unit ModuloCliente  ao formulário,
acesse File>UseUnit  e insira a unit que contem o componente DSRESTConnection.
Agora acesse o evento OnClick do botão de exclusão e altere seu código como abaixo:
?
1 procedure TfrmTitulos.spbExcluirClick(Sender: TObject);
2 begin
3 MessageDlg('Confirma exclusão do título selecionado?', System.UITypes.TMsgDlgType.mtConfirmation,
4 [System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo], 0,
5 procedure(const AResult: TModalResult)
6 begin
7 case AResult of
8 mrYES :
9 begin
10 if ModuloCliente.SrvServerMetodosClient.ExcluirTitulo(DM.qryTitulosID_TITULO.AsInteger) then
11 begin
12 DM.qryTitulos.Delete;
13 Self.spbVoltarClick(Sender);
14 end
15 else
16 ShowMessage('Ocorreu um erro ao excluir!');
17 end;
18 end;
19 end
20 )
21 end;
Perceba que fizemos uma pequena alteração no miolo de nosso método. Chamamos o server
método ExcluirTitulo passando para ele o ID_TITULO do título selecionado. Se o método retornar verdadeiro, significa
que conseguimos excluir no servidor, então excluímos também off-line. Caso contrário, mensagem ao usuário.

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 método chamado  ApplyUpdates do ClientDataSet  que faz o
trabalho de enviar as alterações para o servidor de banco de dados. Nós teremos que criar nosso próprio método de
atualização do lado do servidor. Retorne ao servidor DataSnap e adicione um novo método como abaixo:
?
1 procedure TSrvServerMetodos.ApplyUpdadesTitulos(const ADeltaList: TFDJSONDeltas);
2 var
3 LApply: IFDJSONDeltasApplyUpdates;
4 begin
5 LApply := TFDJSONDeltasApplyUpdates.Create(ADeltaList);
6 LApply.ApplyUpdates(sTitulos, qryTitulos.Command);
7 end;
O que nós fazemos aqui é criar uma instância da interface IFDJSONDeltasApplyUpdates   para que possamos fazer
o apply.  Instanciamos a variável e então chamamos o método  ApplyUpdates da Interface  passando como parâmetro o
nome da tabela gravado na constante sTitulos  (constsTitulos=‘TITULOS’ ) na área Private no do servidor DataSnap.  E
o segundo parâmetro nós chamamos o método Command  do qryTitulos. Somente isso. O restante a própria interface
faz o trabalho para nós. Gere novamente o servidor e execute-o.
Voltando ao aplicativo mobile, retorne no nosso módulo cliente e então atualize o arquivo Proxy.  Antes de fazermos a
alteração, precisamos de um componente MemoryTable  no DataModule principal. Adicione um
componente FDMemTable  no DataModule  e dê o nome de memTitulos.  Nós usaremos esse componente para receber
os dados alterados e enviá-lo ao servidor. Nós precisamos alterar o botão Salvar.   Volte no código-fonte e então
modifique-o como a seguir:
?
1 procedure TfrmTitulos.spbSalvarClick(Sender: TObject);
2 var
3 LDeltaList : TFDJSONDeltas;
4 LDataList : TFDJSONDataSets;
5 begin
6 if DM.qryTitulos.State in [dsInsert] then
7 DM.qryTitulos.FieldByName('ID_TITULO').AsInteger := DM.GetIDFromTable('TITULOS');
8
9 DM.qryTitulos.Post;
10
 __________________________________________________________________________________________
79
11 LDeltaList := TFDJSONDeltas.Create;
12 LDataList := TFDJSONDataSets.Create;
13 TFDJSONDataSetsWriter.ListAdd(LDataList, DM.qryTitulos);
14 TFDJSONDeltasWriter.ListAdd(LDeltaList, sTitulos, DM.memTitulos);
15
16 ModuloCliente.SrvServerMetodosClient.ApplyUpdadesTitulos(LDeltaList);
17 AtualizarBotoes;
18 end;
O que nós fazemos aqui é bem simples. Nós precisamos criar uma instância da classe FDJSONDeltas. Essa instância
receberá os dados alterados da query para envio ao servidor. Também precisamos de uma variável 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 método  ApplyUpdatesTitulos passando o LDeltaList  como
parâmetro. Feito isso o servidor receberá a lista de Deltas e aplicará ao banco de dados.

Na seção anterior, nós fizemos a parte de  ApplyUpdates, como mencionado. Se voltarmos no tempo para falarmos
de DBExpress,  vamos lembrar que o  ApplyUpdates  na verdade é o envio de um pacote com Deltas dos registros
alterados, excluídos e incluídos do ClientDataSet  para o DataSetProvider.  O Provider  se encarregava de fazer o trabalho
de receber esses Deltas e criar as instruções UPDATE,DELETEeINSERT   de acordo com o tipo de registro recebido. E
essas instruções são aplicadas ao banco de dados.
Com FireDAC  e Reflection, o processo é semelhante, mas evidentemente que não precisamos usar
o DataSetProvider, tão pouco o ClientDataSet. Nosso único deve é usar a classe TFDJSONDeltas para extrair
o Delta da query e só então enviar esses dados para o outro lado do sistema, o servidor. E então aplicar esse pacote ao
banco como vimos.
Automaticamente, não precisamos fazer um método para inserção tão pouco exclusão. Nesse caso só fizemos um
método para excluir, pois precisamos ter um retorno do servidor. Mas facilmente poderíamos seguir apenas com a
opção ApplyUpdates.
Para um maior entendimento do processo, recomendo que leiam e testem o exemplo completo de Reflection  presente
na pasta Samples do Delphi.

Finalizamos aqui nosso Tutorial: Criando meu app step-by-step que iniciamos em RAD Studio XE6 e finalizamos em XE7
(ou XE8 que também funcionará normalmente). O que vimos nesse tutorial é que com poucos detalhes e até com
pouca programação, conseguimos criar um aplicativo totalmente compatível 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 código-fonte. Em nosso app, temos acesso a um banco de dados local SQLite e ainda incluímos 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 próxima
#GoToDelphi

Nessa última parte de nosso tutorial, alguns leitores detectaram problemas na função ApplyUpdates e resolvemos
revisar o artigo. De fato, o ApplyUpdatesTitulos criado aqui não funciona perfeitamente, isso porque estamos tentando
extrair os Deltas do qryTitulos (Query), mas isso não é possível. A codificação utilizada não consegue extrair justamente
por não existirem Deltas em FDQuery. Para corrigir o problema, devemos fazer algumas alterações no nosso projeto.
Vamos lá:
A primeira alteração é redirecionar todos os binds para o memTitulos presente em nosso DataModule. Então, nosso
memTitulos deverá possuir os campos da tabela Títulos. Nós 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 formulário títulos, acione a janela de Binding e refaça todos os links de campos apontando-os para o
memTitulos, como na .
 __________________________________________________________________________________________
80
Links refeitos no binding.

Agora o que precisamos fazer é refazer a codificação toda apontando para o memTitulos ao invés do qryTitulos. O
primeiro lugar que devemos mexer é no OnCreate, onde abrimos a querie. Localize a linha onde fechamos e abrimos
a querie e troque por memTitulos onde for necessário.
Localize ao longo do código-fonte todos os lugares que fazem menção ao qryTitulos e altere.
A última e mais importante alteração, diz respeito ao botão Salvar da tela de edição. Esse código precisamos dar uma
atenção maior.
Na  logo a seguir, nós podemos visualizar todo o código que utilizamos para gravar os dados no banco local
e no servidor. O problema aqui é que estamos tentando extrair o delta do qryTitulos, coisa que não será possível como
mencionamos anteriormente.
?
1 procedure TfrmTitulos.spbSalvarClick(Sender: TObject);
2 var
3 LDeltaList : TFDJSONDeltas;
4 LDataList : TFDJSONDataSets;
5 begin
6 if DM.memTitulos.State in [dsInsert] then
7 DM.memTitulos.FieldByName('ID_TITULO').AsInteger := DM.GetIDFromTable('TITULOS');
8
9 DM.memTitulos.Post;
10
11 LDeltaList := TFDJSONDeltas.Create;
12 LDataList := TFDJSONDataSets.Create;
13 TFDJSONDeltasWriter.ListAdd(LDeltaList, sTitulos, DM.memTitulos);
14
15 TFDJSONDataSetsWriter.ListAdd(LDataList, DM.memTitulos);
16
17 ModuloCliente.SrvServerMetodosClient.ApplyUpdadesTitulos(LDeltaList);
18 AtualizarBotoes;
19 end;
 Código Original do Salvar

Nossa codificação ficará ainda mais simples agora. Basta omitirmos as linhas referentes a variável LDataList. Então o
código final ficará como na  abaixo:
?
1 procedure TfrmTitulos.spbSalvarClick(Sender: TObject);

 __________________________________________________________________________________________
81

Você também pode gostar