Olá pessoal, nos últimos artigos sobre FireMonkey, no Delphi XE2, foi mostrado como fazer na plataforma FireMonkey algumas práticas utilizadas no dia a dia de desenvolvimento na já tradicional plataforma VCL. Nos próximos artigos vamos continuar com esta ideia, mostrando algumas adaptações a serem feitas para utilizar a plataforma Firemonkey, e além de se utilizar das mesmas técnicas da VCL, ainda poder incrementar a interface de sua aplicação com os mais variados recursos visuais do FireMonkey.
Neste artigo mostraremos como criar um formulário base para telas de cadastro, com uma barra de ferramentas para navegação entre registros. Este formulário servirá de base para a criação de outros formulários de cadastro, ele não será exibido na aplicação, apenas servirá para manter um layout padrão de seus formulários, além é claro de centralizar os códigos mais comuns em formulários deste tipo, reutilizando-os nos formulários que utilizarem este como base. Os formulários que herdarem este formulário base herdarão além do layout, que manterá um padrão para todos os formulários de cadastro, herdará também os seus códigos, e isto é muito importante, porque assim cada novo formulário pode se preocupar apenas com os seus códigos específicos, pois os códigos comuns já estarão prontos.
Este primeiro artigo focará na criação do formulário base e na criação da barra de navegação entre os registros. Então sem mais delongas vamos à criação de um novo projeto FireMonkey HD Application - Delphi no Delphi XE2.
Criando o projeto FireMonkey_FormBase
Abra o seu Delphi XE2 e crie um novo projeto FireMonkey HD Application – Delphi através do menu (File/ New/ FireMonkey HD Application - Delphi). Crie uma pasta em seu computador com o nome FireMonkey_FormBase, salve dentro dela a primeira unit com o nome de unPrincipal e o projeto com o mesmo nome do diretório, FireMonkey_FormBase. Nesta pasta serão salvos os todos os arquivos do projeto.
Criando o formulário base de cadastro
Com a unPrincipal e o projeto já salvos, criaremos agora o formulário que servirá como base para novos formulários do projeto. Crie um novo Firemonkey HD Form – Delphi através do menu (File/ New/ Firemonkey HD Form - Delphi), salve a unit deste form na pasta do projeto com o nome de unFormBase. Na propriedade name do formulário renomeie para frmFormBase, assim poderemos identifica-lo mais facilmente.
Agora vamos adicionar os componentes que iremos utilizar neste formulário. Adicione uma TToolBar (Standard), um TPanel (Standard), um TStatusBar (Standard) e doze TSpeedButton (Additional), altere as propriedades Name, Text, Tag e Width dos doze TSpeedButtons seguindo o valores da tabela 1:
Tabela 1 – Propriedades dos componentes TSpeedButtons
Como podemos perceber na tabela 1 no FireMonkey, não tem a propriedade Caption nos componentes como na VCL, a sua substituta é a propriedade Text. Como podemos ver, distribuímos sequencialmente um número para cada um dos botões em sua propriedade Tag, isto servirá para identifica-los genericamente mais tarde.
Disponha os componentes no formulário como mostra a figura 1.
Figura 1 – Sugestão de layout para o formulário base
No FireMonkey, como na plataforma VCL, tem um recurso onde um objeto do layout do formulário pode controlar algumas propriedades de outros objetos ,desde que estes façam parte de seu nó no menu TreeView (janela Structure), ou seja, possua objetos filhos. Se alterar a propriedade Enabled do objeto pai para false, todos os filhos deste não poderão executar nenhuma ação mesmo que estejam habilitados, até que o objeto pai seja habilitado novamente. A diferença é que na plataforma FireMonkey, este recurso não se limita apenas à componentes containers como TPanels e TGruopBox por exemplo, no Firemonkey qualquer objeto visual do layout pode ter componentes filhos, até mesmo TLabels e TButtons. Mencionei este recurso, pois os TSpeedButtons adicionados ao form devem pertencer a ToolBar, e também devem ser independentes um do outro, ou seja, nenhum deve controlar o outro. Caso algum botão seja filho de outro na hierarquia deve-se deixa-lo como filho da ToolBar, pois cada botão terá uma ação diferente na navegação dos registros e dependendo da ação de um botão os outros poderão ficar desabilitados, por isso se faz necessário deixar todos como filhos da ToolBar. Caso haja um caso assim, basta arrastar o SpeedButton para o nó da ToolBar. Veja um exemplo na Figura 2.
Figura 2 – Alterando a hierarquia dos objetos do formulário
Os componentes visuais já estão devidamente alocados no layout do formulário, vamos agora adicionar os componentes de acesso a dados. Devemos lembrar que por se tratar de um formulário base, ele não fará nenhum vinculo direto com banco de dados, porém, deverá fornecer uma estrutura para tal função, aos formulários que receberem sua herança.
Adicione um TDataSetProvider (DataAccess), um TClientDataSet (DataAccess), um TDataSource (DataAccess), um TBindScopeDB (LiveBindings) e um TBindingList (LiveBindings). Siga a tabela 2 para fazer a configuração destes cinco componentes.
Tabela 2 – Propriedades dos componentes de acesso a dados
Explicando o funcionamento dos componentes de acesso a dados no formulário
No geral o trio de componentes de acesso a dados (SQLDataSet, DataSetProvider e ClientDataSet) são alocados em um DataModule, e ligados aos formulários através de um DataSource. Porém a ideia apresentada neste artigo é de deixar um ClientDataSet já com as configurações básicas de ligações já realizadas. Outra vantagem deste método é que os códigos do ClientDataSet serão configurados no próprio Formulário, facilitando a visualização dos códigos do mesmo.
No Delphi 7 esta mesma técnica se faz sem a necessidade de trazer ao formulário junto com o ClientDataSet o DataSetProvider. Porém fazia uso de um componente da palheta DataSnap chamado TLocalConnection. Este componente era adicionado ao DataModule, no ClientDataSet bastava informar na propriedade RemoteServer o componente TLocalConnection presente no DataModule, e o ClientDataSet visualizará o DataSetProvider como se estivesse no Próprio DataModule.
No Delphi XE2 não tem o componente TLocalConnection, e é por isso que o DataSetProvider veio junto com o ClientDataSet ao formulário, para manter o mesmo método utilizado no Delphi 7. Desta forma no DataModule, iremos ter apenas o componente que faz a conexão com o banco de dados, TSQLConnection, e o componente que acessa individualmente cada tabela do banco de dados, TSQLDataSet, ambos da palheta DBExpress.
Explicado o porquê de tantos componentes de acesso a dados no formulário, vamos então explicar rapidamente a configuração deles.
O dspBase (TDataSetProvider) não terá nenhum valor mesmo na propriedade DataSet, pois este será preenchido pelo formulário que receber a herança do frmFormBase, outra propriedade a ser alterada é a Options/poAllowCommandText, esta permitirá que o ClientDataSet execute consultas SQL na base de dados, por fim, para melhorar a performance das transações de alteração e exclusão, foi alterada a propriedade UpdateMode para upWhereKeyolny, que significa que apenas realizará as atualizações pelas primary keys.
O cdsBase (TClientDataSet) apenas fará a ligação com o dspBase através da propriedade ProviderName.
O dsBase (TDataSource) deve fazer ligação com o cdsBase, através de sua propriedade DataSet.
Como foi visto nos artigos anteriores sobre FireMonkey, esta plataforma não possui o grupo de componentes da palheta DataControls, e é por este mesmo motivo que foi agregado ao Delphi à tecnologia LiveBindings (ligações ao vivo), em suma esta tecnologia permite manipular as propriedades de componentes visuais em tempo de execução, ou até mesmo criar BindingLinks para os Fields de um DataSource, este que será o nosso caso. Para possibilitar criarmos estes BindingLinks, necessitaremos de um escopo de binding próprio para a ligação com o banco de dados, esta é a função do BindScopeDBBase (TBindScopeDB), deve-se informar qual DataSource ele manipulará através da propriedade DataSource, neste caso é o dsBase.
Por fim, o BindingList (TBindingList) não terá nenhuma configuração, mas sua a função é de suma importância para os próximos formulários, pois é nele que serão listados todos os BindingLinks e as LiveBindings do formulário. Tanto o BindScopeDBBase quanto o BindingList são do grupo de componentes da palheta LiveBindings.
Definindo variáveis públicas para o frmFormBase
As variáveis públicas serão preenchidas pelos formulários que receberem a herança do frmFormBase, estas variáveis possibilitarão a manipulação dinâmica do código, a partir delas manipularemos o código base dos botões e outros procedimentos que serão comuns em formulários de cadastro. Como mencionado estas serão variáveis públicas, ou seja, serão declaradas na sessão pública da unit. Veja na tabela 3 a lista das variáveis públicas que serão utilizadas do frmFormBase.
Tabela 3 – Lista de variáveis públicas do frmFormBase
A maioria destas variáveis servirá como parâmetro para a chamada de um formulário de pesquisa. Vamos utilizar como exemplo o formulário de pesquisa criado no artigo “FireMonkey - utilizando mestre-detalhe e formulário pesquisa - parte II” da revista The Club do mês de outubro deste ano, o conteúdo desta revista também pode ser acessado na sessão de revistas do site oficial da revista The Club (www.theclub.com.br). Você pode seguir o artigo para criar o formulário de pesquisa neste projeto ou caso já tenha construído o formulário de pesquisa em outro projeto, basta copiar os arquivos unPesquisa.pas e unPesquisa.fmx para o diretório deste projeto, e depois adicionar ao projeto usando o menu (Project / Add to Project) e selecionando a unit a ser adicionada no projeto, neste caso a unPesquisa. Depois de adicionado a unPesquisa ao projeto FireMonkey_FormBase, é só adicioná-la na cláusula Uses da unFormBase. Veremos posteriormente como passar os parâmetros ao frmPesquisa.
As duas primeiras variáveis, SQL_PADRAO E TABELA, farão o revezamento no código, ou seja, se informar a SQL_PARAO não precisa informar a TABELA e vice-versa, isso quer dizer que quando tiver uma SQL_PADRAO informada, o código fará a manipulação de SQL através dela, caso não tenha, o código manipulará uma SQL mais simples utilizando o nome da tabela informado na variável TABELA. Percebe se que a utilização da primeira variável, SQL_PADRAO, se faz necessário em caso de uma consulta SQL mais complexa que exija, por exemplo, algum JOIN entre outras tabelas, no mais, basta informar o nome da tabela.
A variável GEN_NAME armazenará o nome do Generator responsável por armazenar o valor da chave primária da tabela base. Com esta variável, será possível fazer uso de uma função de auto-incremento para as chaves primárias, que estará acessível neste formulário. Para poder acessar o banco de dados genericamente, foi criado a variável CONEXAO do tipo TSQLConnection. Para utilizar o componente TSQLConnection é preciso declarar na sessão uses a biblioteca Data.SqlExpr a qual ela pertence.
A variável FOCO se encarregará de jogar o foco automático para o objeto a ela atribuído.
Criando os métodos para o funcionamento da barra de navegação
Criaremos dois métodos para realizar a tarefa de dar mobilidade á barra de ferramentas, como vimos anteriormente, nossa barra de ferramentas possui 12 botões identificados pelas suas propriedades Tag. O que teremos que fazer é, por exemplo, desabilitar alguns botões dependendo da ação que está sendo executada no formulário. O primeiro método é uma função, que retornará um valor booleano que se refere ao estado que o botão deverá assumir conforme a sua tag, a função se chama EstadoBotao. Veja na listagem 1 como é feita a sua declaração na sessão pública da unit e o corpo do código.
// DECLARAÇÃO DA FUNCÇÃO
public
{ Public declarations }
function EstadoBotao(Sender : TObject; DS : TDataSource): Boolean;
// CORPO DA FUNÇÃO
function TfrmFormBase.EstadoBotao(Sender: TObject; DS: TDataSource): Boolean;
begin
Result := False;
// EDITAR, EXCLUIR E LOCALIZAR
if (TSpeedButton(Sender).Tag in [3, 4, 12]) then
Result := (DS.DataSet.RecordCount > 0) and (DS.DataSet.State = dsBrowse)
else
// INCLUIR E ATUALIZAR
if (TSpeedButton(Sender).Tag in [2, 7]) then
Result := DS.DataSet.State = dsBrowse
else
// GRAVAR E CANCELAR
if (TSpeedButton(Sender).Tag in [5, 6]) then
Result := DS.DataSet.State in [dsInsert, dsEdit]
else
// PRIMEIRO E ANTERIOR
if (TSpeedButton(Sender).Tag in [8, 9]) then
Result := (DS.DataSet.State = dsBrowse) and not (DS.DataSet.Bof)
else
// PRÓXIMO E ÚLTIMO
if (TSpeedButton(Sender).Tag in [10, 11]) then
Result := (DS.DataSet.State = dsBrowse) and not (DS.DataSet.Eof)
else
// SAIR
if (TSpeedButton(Sender).Tag in [13]) then
Result := True;
end;
Listagem 1 – Função EstadoBotao
Ao observar o código da função, percebe-se que ela verifica quais estados os botões, identificados pela sua propriedade Tag, podem assumir referente ao estado atual do DataSet ligado ao DataSource passado como parâmetro. Esta função será utilizada pelo próximo método que é um procedimento, de nome ControlaBotoes, ele executará a ação de habilitar e desabilitar cada botão, a partir do resultado obtido pela função EstadoBotao. Ele deve estar declarado na sessão pública logo abaixo da declaração da função EstadoBotao. Veja na listagem 2 o exemplo do seu código.
procedure TfrmFormBase.ControlaBotoes;
begin
sbIncluir.Enabled := EstadoBotao(sbIncluir, dsBase);
sbEditar.Enabled := EstadoBotao(sbEditar, dsBase);
sbExcluir.Enabled := EstadoBotao(sbExcluir, dsBase);
sbGravar.Enabled := EstadoBotao(sbGravar, dsBase);
sbCancelar.Enabled := EstadoBotao(sbCancelar, dsBase);
sbAtualizar.Enabled := EstadoBotao(sbAtualizar, dsBase);
sbPrimeiro.Enabled := EstadoBotao(sbPrimeiro, dsBase);
sbAnterior.Enabled := EstadoBotao(sbAnterior, dsBase);
sbProximo.Enabled := EstadoBotao(sbProximo, dsBase);
sbUltimo.Enabled := EstadoBotao(sbUltimo, dsBase);
sbLocalizar.Enabled := EstadoBotao(sbLocalizar, dsBase);
sbSair.Enabled := EstadoBotao(sbAtualizar, dsBase);
end;
Listagem 2 – Procedimento ControlaBotoes
Estes dois métodos juntos, farão a manipulação do estado dos botões, como ativá-los ou desativá-los. Porém ainda não fizemos a chamada destes métodos, eles devem ser chamados toda vez que tiver alguma alteração no estado do dataset. Sendo assim vamos fazer a chamada do procedimento no evento onDataChange do dsBase (TDataSource), veja na listagem 3 como é feito a chamada deste método.
procedure TfrmFormBase.dsBaseDataChange(Sender: TObject; Field: TField);
begin
ControlaBotoes;
end;
Listagem 3 – Fazendo a chamada do procedimento no evento onDataChange do dsBase
Configurando as ações de cada botão
Outro componente que é comumente utilizado na VCL é o TActionList, principalmente para centralizar as ações de botões. Porém, este também não está disponível na plataforma FireMonkey, portanto iremos manipular as ações dos botões da barra de ferramentas a partir do evento onClick do botão sbIncluir, depois disso basta vincular este evento (procedimento) a todos os demais botões. Veja na listagem 4 a implementação do código.
procedure TfrmFormBase.sbIncluirClick(Sender: TObject);
begin
if (Sender is TSpeedButton) then
begin
case TSpeedButton(Sender).Tag of
2: begin
cdsBase.Insert;
if (Assigned(FOCO)) then
TControl(FOCO).SetFocus;
end;
3: begin
cdsBase.Edit;
if (Assigned(FOCO)) then
TControl(FOCO).SetFocus;
end;
4: begin
if MessageDlg('Confirma a exclusão?', TMsgDlgType.mtConfirmation,
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then
cdsBase.Delete;
end;
5: begin
if MessageDlg('Confirma a gravação?', TMsgDlgType.mtConfirmation,
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then
cdsBase.Post;
end;
6: begin
if MessageDlg('Cancelar edição?', TMsgDlgType.mtConfirmation,
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then
cdsBase.Cancel;
end;
7: cdsBase.Refresh;
8: cdsBase.First;
9: cdsBase.Prior;
10: cdsBase.Next;
11: cdsBase.Last;
12: begin
frmPesquisa := TfrmPesquisa.Create(Self);
if (SQL_PADRAO <> '') then
frmPesquisa.SQL_PADRAO := SQL_PADRAO
else
frmPesquisa.TABELA := TABELA;
frmPesquisa.CAMPO_CHAVE := CAMPO_CHAVE;
frmPesquisa.CAMPO_BUSCA := CAMPO_BUSCA;
frmPesquisa.DESCRICAO := DESCRICAO_PESQUISA;
frmPesquisa.CDS := cdsBase;
frmPesquisa.ShowModal;
FreeAndNil(frmPesquisa);
end;
13: Close;
end;
end;
end;
Listagem 4 – Definindo as ações de cada botão no evento onClick do sbIncluir
A primeira verificação que fazemos neste evento é se o parâmetro Sender é um componente da classe TSpeedButton. Sendo assim, utilizamos a classe TSpeedButton utilizando o parâmetro Sender para recuperarmos o valor de sua Tag, dentro do método Case Of. Assim passamos qual o procedimento a ser tomado dependendo do botão clicado, identificados pelo valor de sua Tag.
Se for o botão excluir, gravar ou o cancelar, faremos uma verificação utilizando o método nativo do Delphi MessageDialog, exibindo uma mensagem de confirmação para o usuário e dependendo de sua resposta executa a ação do botão.
Outra observação é no botão de pesquisar, Tag 12. É nesta parte que passamos os parâmetros globais para o frmPesquisa, observe que após criarmos o form em memória já passamos todos os parâmetros a ele, depois é só chamá-lo pelo método ShowModal, por fim, eliminá-lo da memória. Lembrando que o formulário de pesquisa utilizado como exemplo, é o mesmo que foi criado no artigo de Firemonkey da revista The Club do mês de outubro de 2012, não foi alterado nada, apenas foi adicionado a este projeto da forma como foi criado.
Após adicionar o código da listagem 4 no evento onClick do sbIncluir, basta amarrar este evento a todos os demais botões. Uma forma bem simples de se fazer isto é pressionar a tecla Shift e clicar em cada botão exceto o sbIncluir, desta maneira irá selecionar todos de uma só vez, depois de feito isso é só ir à janela Object Inspector e abrir a aba Events, no evento onClick selecione a opção sbIncluirClick, feito isso dê um duplo clique no evento para finalizar a amarração, se der certo, o cursor do mouse ficará piscando na primeira linha do procedimento sbIncluirClick na unit.
Até este momento nosso projeto possui três units, unPrincipal, unFormBase e unPesquisa. Nossa barra de ferramentas está pronta e totalmente funcional, porém, continuaremos com este projeto no próximo artigo, onde descreveremos mais alguns métodos comuns para um formulário de cadastro.
Conclusão
Neste artigo foi mostrado a primeira parte de como criar um formulário base de cadastro, o foco neste artigo foi como construir a barra de ferramentas do formulário base, vimos as adaptações a serem realizadas se comparadas com a plataforma VCL, e também o porque de trazer o componentes TClientDataSet para o formulário unificando os códigos referentes à tabela a ser trabalhado no formulário. O próximo artigo terá a continuação deste projeto, mostraremos mais alguns métodos padrões em formulários de cadastro e também como fazer uma herança deste formulário base. Espero que tenham gostado do que viram até aqui e que tenha sido útil de alguma forma, até o nosso próximo artigo, um abraço a todos.
|