Desenvolvimento - Mobile
Palm OS: Linguagem HB++ (Parte 2)
Embora seja possível desenvolver softwares estruturados com o HB++ seu enfoque principal é a programação orientada a objetos. O tempo de execução de um software OO é bem menor que o mesmo desenvolvido em uma filosofia estruturada.
por Wellington Pinto de OliveiraProgramação Orientada a Objetos
Embora seja possível desenvolver softwares estruturados com o HB++ seu enfoque principal é a programação orientada a objetos. O tempo de execução de um software OO é bem menor que o mesmo desenvolvido em uma filosofia estruturada.
Classes
Em orientação a objeto, uma classe abstrai um conjunto de objetos com características similares. Uma classe define o comportamento de seus objetos através de métodos e os estados possíveis destes objetos através de atributos. Em outros termos, uma classe descreve os serviços providos por seus objetos e quais informações eles podem armazenar.
Estrutura de uma classe
Uma classe define estado e comportamento de um Objeto geralmente implementando métodos e atributos (nomes utilizados na maioria das linguagens modernas). Os atributos, também chamados de campos (do inglês fields), indicam as possíveis informações armazenadas por um objeto de uma classe, representando o estado de cada objeto. Os métodos são procedimentos que formam os comportamentos e serviços oferecidos por objetos de uma classe.
Outros possíveis membros de uma classe são:
construtores - definem o comportamento no momento da criação de um objeto de uma classe.
destrutor - define o comportamento no momento da destruição do objeto de uma classe. Normalmente, como em C++, é utilizado para liberar recursos do sistema (como memória).
propriedades - define o acesso a um estado do objeto.
eventos - define um ponto em que o objeto pode chamar outros procedimentos de acordo com seu comportamento e estado interno.
Construtores e Destrutores
Cada classe definida possuem por padrão dois métodos, são eles o construtor(Initialize) e o destrutor(Terminate).
Construtores: Quando uma nova instancia da classe for criada utilizando a palavra New ou clonada, o membro Initialize é executado. Este membro é chamado para inicializar valores ou executar algum código específico. No exemplo da classe lâmpada poderia inicializar a lâmpada já com status "Ligada", para isso basta inserir na classe o código da listagem abaixo.
Exemplo:
Listagem 15. Construtor de uma classe HB++.
Private Sub Initialize()
me.iEstado = true
End Sub
Destrutores: Quando a instancia da classe for destruída o código do método Terminate() é executado, geralmente utilizamos este método para finalizar alguma ação, como a execução de um Timer, fechamento de uma conexão, etc.. No exemplo a seguir estamos desligando a lâmpada sempre que a classe for finalizada, em um sistema de controle de funcionamento de lâmpadas este membro ajudaria a economizar energia.
Exemplo:
Listagem 16. Destrutor de uma classe HB++.
Public Sub Terminate()
me.iEstado = false
End Sub
Técnica de Encapsulamento
Em programação orientada a objetos, encapsulamento é o mecanismo que permite separar um mecanismo de funcionamento de sua interface. Um exemplo disso é que para utilizarmos um liquidificador, não precisamos saber detalhes do funcionamento de seu motor. A única interface que conhecemos são seus botões. Um exemplo clássico de encapsulamento é o padrão Mediator.
Uma grande vantagem do encapsulmento é que toda parte encapsulada pode ser modificada sem que os usuários da classe em questão sejam afetados. Novamente, no exemplo do liquidificador, o técnico poderia substituir o motor do equipamento por um outro totalmente diferente, sem que a dona de casa seja afetada - afinal, ela continuará somente tendo que pressionar o botão.
O encapsulamento protege o acesso direto (referência) aos atributos de uma instância fora da classe onde estes foram declarados. Esta proteção consiste em se usar modificadores de acesso mais restritivos sobre os atributos definidos na classe. Depois devem ser criados métodos para manipular de forma indireta os atributos da classe.
Encapsular atributos também auxilia a garantir que o estado e o comportamento de um objeto se mantenha coeso. Por exemplo, no caso da classe semáforo poderíamos ter um método de acesso chamado lerCor(), e um modicador chamado proximaCor(). O estado é mantido pois os usuários da classe não podem alterar as cores de um semáforo ao seu bel prazer e, por exemplo, fazer a seguinte troca de cores: vermelho-amarelo-vermelho.
Na listagem 17 temos um exemplo de classe bem montada, com encapsulamento.
Listagem 17. Classe Lâmpada.
"Armazena o estado da lâmpada
private iEstado as Boolean
"Propriedade que retorna o Estado da Lâmpada
public Property Get Estado() as String
dim resultado as String
if me.iEstado then
resultado = "Ligada"
else
resultado = "Desligada"
end if
Estado = resultado
End Property
"Modifica o Estado da Lâmpada para Desligada
public Sub desligar()
me.iEstado = false
End Sub
"Modifica o Estado da Lâmpada para Ligada
public Sub ligar()
me.iEstado = true
End Sub
No exemplo acima a variável iEstado está protegida da ação humana, caso seja necessário alterar o valor desta variável obrigatoriamente ele deve utilizar Desligar() ou Ligar().
Herança
A herança é um relacionamento pelo qual uma classe, chamada de sub-classe, herda todos comportamentos e estados possíveis de outra classe, chamada de super-classe ou classe base. É permitido que a sub-classe extenda (herde) os comportamentos e estados possíveis da super-classe (por isso este relacionamento também é chamado de extensão). Essa extensão ocorre adicionando novos membros a sub-classe, como novos métodos e atributos.
É também possível que a sub-classe altere os comportamentos e estados possíveis da super-classe. Neste caso, a sub-classe sobrescreve membros da super-classe, tipicamente métodos.
Polimorfismo
Na programação orientada a objetos, o polimorfismo permite que referências de tipos de classes mais abstratas representem o comportamento das classes concretas que referenciam. Assim, um mesmo método pode apresentar várias formas, de acordo com seu contexto. O polimorfismo é importante, pois permite que a semântica de uma interface seja efetivamente separada da implementação que a representa. O termo polimorfismo é originário do grego e significa "muitas formas" (poli = muitas, morphos = formas).
No exemplo abaixo temos uma rotina capaz de carregar um ListBox ou um PopUp(ComboBox) isso porque ambos herdam de ChoiceControl e possuem implementações semelhantes.
Figura 3. Demostração da hierarquia de classes.
Exemplo:
Listagem 18. Exemplo de rotina que carrega qualquer objeto que seja uma instancia de sub-classes herdeiras de ChoiceControl.
Public Static Sub dbCONTATO(ByRef choice as ChoiceControl,Optional ByRef sql as String = "UNIQUEID > 0 ORDER BY UNIQUEID ASC")
Dim rs as new dbCONTATO
rs.OpenRecordset sql, hbModeOpenAlways+hbModeReadOnly,hbCompareText
choice.Clear
while not rs.EOF
choice.AddItem rs.NOME ,rs.UniqueID
rs.MoveNext
wend
if choice.ListCount > 0 then
choice.ListIndex = 0
end if
rs.Close
Set rs = nothing
End Sub
Boa parte dos padrões de projeto de software baseia-se no uso de polimorfismo, por exemplo: Abstract Factory, Composite, Observer, Strategy, Template Method, etc.
Utilizando os Conceitos – Um exemplo Real
Agora que estamos afiados nos conceitos implementados na linguagem adotada pelo HB++ vamos desenvolver um pequeno software utilizando alem da sintaxe estudada uma abordagem semântica baseada em padrões de projetos.
Inicie um novo projeto no HB++, utilize a opção “Blank Project”, utilize o nome “Agenda” e o CreatorID “SPFW”. Com o projeto aberto adicione um arquivo Module (Project | Add Module...), utilize as os seguintes dados para configuração da propriedade deste novo arquivo.
Propriedade |
Valor |
Name |
FW_SP_Base |
Tabela 2. Propriedades do arquivo Module.
Escreva o código da listagem 19 neste arquivo Module.
Listagem 19. Código do arquivo Module.
Public Const sysTrapPrefGetPreference as Long = &HA2D1
Public Const sysTrapPrefSetPreference as Long = &HA2D2
Public Declare SUB PrefSetPreference( ByVal ichoice as SystemPreferencesChoice, ByVal value as Long) Trap sysTrapPrefSetPreference
Public Declare FUNCTION PrefGetPreference( ByVal ichoice as SystemPreferencesChoice) as Long Trap sysTrapPrefGetPreference
Public SUB SavePref( ByVal value as Long, ByVal ichoice as SystemPreferencesChoice)
Dim s as New StreamMemory
Write s, value
Set App.Preferences(ichoice) = s
End SUB
Public FUNCTION LoadPref( ByVal ichoice as SystemPreferencesChoice) as Long
Dim s as StreamMemory
Dim value as Long
try
Set s = App.Preferences(ichoice)
Read s, value
catch
value = 0
err.Clear
end catch
LoadPref= value
End FUNCTION
Public Enum EnCRUD
NULL =-1
INSERT =0
UPDATE =1
DELETE =2
End Enum
Public Enum SystemPreferencesChoice
prefVersion
prefCountry
prefDateFormat
prefLongDateFormat
prefWeekStartDay
prefTimeFormat
prefNumberFormat
prefAutoOffDuration
prefSysSoundLevelV20
prefGameSoundLevelV20
prefAlarmSoundLevelV20
prefHidePrivateRecordsV33
prefDeviceLocked
prefLocalSyncRequiresPassword
prefRemoteSyncRequiresPassword
prefSysBatteryKind
prefAllowEasterEggs
prefMinutesWestOfGMT
prefDaylightSavings
prefRonamaticChar
prefHard1CharAppCreator
prefHard2CharAppCreator
prefHard3CharAppCreator
prefHard4CharAppCreator
prefCalcCharAppCreator
prefHardCradleCharAppCreator
prefLauncherAppCreator
prefSysPrefFlags
prefHardCradle2CharAppCreator
prefAnimationLevel
prefSysSoundVolume
prefGameSoundVolume
prefAlarmSoundVolume
prefBeamReceive
prefCalibrateDigitizerAtReset
prefSystemKeyboardID
prefDefSerialPlugIn
prefStayOnWhenPluggedIn
prefStayLitWhenPluggedIn
prefAntennaCharAppCreator
prefMeasurementSystem
prefShowPrivateRecords
prefAutoOffDurationSecs
prefTimeZone
prefDaylightSavingAdjustment
prefAutoLockType
prefAutoLockTime
prefAutoLockTimeFlag
prefLanguage
prefLocale
prefTimeZoneCountry
prefAttentionFlags
prefDefaultAppCreator
prefDefFepPlugInCreator
prefColorThemeID
prefHandednessChoice
prefHWRCreator
End Enum
Public Enum DateFormatType
dfMDYWithSlashes
dfDMYWithSlashes
dfDMYWithDots
dfDMYWithDashes
dfYMDWithSlashes
dfYMDWithDots
dfYMDWithDashes
dfMDYLongWithComma
dfDMYLong
dfDMYLongWithDot
dfDMYLongNoDay
dfDMYLongWithComma
dfYMDLongWithDot
dfYMDLongWithSpace
dfMYMed
dfMYMedNoPost
dfMDYWithDashes
End Enum
Iniciamos o arquivo criando constantes, estas variáveis devem armazenar o numero da rotina desenvolvida na API do sistema operacional, ela está escrita em C. Logo em seguida utilizamos as declarações “PrefSetPreference” e “PrefGetPreference”, repare que as constantes foram utilizadas aqui, poderíamos ter eliminado o uso das constantes entrando diretamente com os valores hexadecimais.
A procedure “SavePref” foi implementada para salvar informações numéricas em espaços de memória destinadas a aplicação, estes espaços de memória só são eliminados quando o software é excluído do handheld. Para capturar estes informações foi implementado a rotina “LoadPref”.
O HB++ vem preparado para trabalhar em qualquer formato de Data e Numero porem trabalhando nesta área sentimos a necessidade de se eleger um padrão, como o sistema operacional da Palm vem preparado para o formato inglês utilizaremos este formato como padrão, utilizaremos estas duas procedures para sempre que o usuário entrar no programa vamos salvar o formato escolhido pelo usuário na memória e trocar automaticamente o formato de Data e Numero do sistema operacional. Quando o usuário sair do sistema o software deverá ler a memória e voltar com os formatos escolhidos pelo usuário antes da execução de nosso software. Utilizaremos em todos os projetos este arquivo Module.
Adicione agora dois formulários (Project | Add Form...), utilize as seguintes propriedades para suas configurações.
Propriedade |
Valor |
Name |
frmViewContato |
Caption |
Dados de Contato |
SaveBehind |
True |
Tabela 3. Propriedades do formulário.
Propriedade |
Valor |
Name |
frmListContato |
Caption |
Lista de Contatos |
SaveBehind |
False |
Tabela 4. Propriedades do formulário.
Adicione agora uma classe (Project | Add Class...), utilize as os seguintes dados para configuração da propriedade deste novo arquivo.
Propriedade |
Valor |
Name |
clsApplication |
Extends |
Application |
Tabela 5. Propriedades da classe base.
Edite o seguinte código para esta classe
Listagem 20. Classe base.
Private SUB Application_NormalLaunch()
Dim f as new frmListContato
"Save PrefDateFormat
SavePref PrefGetPreference(prefDateFormat),prefDateFormat
PrefSetPreference prefDateFormat,dfMDYWithSlashes
"Save PrefNumberFormat
SavePref PrefGetPreference(prefNumberFormat),prefNumberFormat
PrefSetPreference prefNumberFormat,0
f.Show hbFormModeless+hbFormGoto
End SUB
"Destrutor da classe
Private SUB Terminate()
on error goto Erro
PrefSetPreference prefDateFormat,LoadPref(prefDateFormat)
PrefSetPreference prefNumberFormat,LoadPref(prefNumberFormat)
Erro:
if err.Number > 0 then err.Clear
End SUB
Na procedure Application_NormalLaunch() estamos utilizando as procedures e definições escritas no arquivo Module para salvar as configurações padões. Já o destrutor Terminate() deverá voltar com as configurações escolhidas pelo usuário.
Vamos agora criar o Layout da tabela que deverá armazenar os dados, para isso adicione uma tabela ao projeto. Altere suas propriedades conforme a tabela abaixo.
Propriedade |
Valor |
Name |
dbContato |
Tabela 6. Propriedades da tabela que representa a entidade Contato.
Adicione os seguintes campos a esta tabela utilizando a interface do HB++ (Table | Insert Field) Figura 4.
Campo |
Tipo |
Tamanho |
NOME |
String |
50 |
TELEFONE |
String |
20 |
DATA |
Date |
--- |
Tabela 7. Dicionário de Dados.
Figura 4. Descrição da função.
Para cada entidade adicionada no projeto devemos desenvolver uma classe responsável pela manipulação dos dados, como na plataforma PalmOS não existe SGBD temos que simular as Constraints para validar a informação, nos próximos artigos estaremos com um projeto muito complexo de força de vendas e estas classes serão fundamentais para segurança da informação.
Crie uma classe chamada clsDALContato e edite o seguinte código para este arquivo.
Listagem 21. Classe responsável pela manipulação de dados da entidade Contato.
Protected iUNIQUEID as Long
Protected iSECRET as Boolean
Protected iCATEGORY as Integer
Protected iDIRTY as Boolean
Protected iNOME as String
Protected iTELEFONE as String
Protected iData as Date
"Propriedades que permitem a segurança da informação
Public Property GET UNIQUEID() as Long
UNIQUEID = me.iUNIQUEID
End Property
Public Property LET UNIQUEID( iUNIQUEID as Long)
me.iUNIQUEID = iUNIQUEID
End Property
Public Property GET NOME() as String
NOME = me.iNOME
End Property
Public Property LET NOME( iNOME as String)
me.iNOME = iNOME
End Property
Public Property GET TELEFONE() as String
TELEFONE = me.iTELEFONE
End Property
Public Property LET TELEFONE( iTELEFONE as String)
me.iTELEFONE = iTELEFONE
End Property
"Data é somente leitura
Public Property GET DATA() as Date
DATA = me.iData
End Property
"Eventos utilizados
Public Event BeforeUpdate(ByVal action as EnCRUD)
Public Event AfterUpdate(ByVal action as EnCRUD)
"Funções de Leitura e Escrita, a base da camada DAL
Public FUNCTION Load() as Boolean
Dim rs as new dbCONTATO
Dim sql as string
On Error Goto Erro
if not me.iUniqueID <= 0 then
sql= "UniqueID = " & Cstr(UniqueID) & " "
else
if not me.iNOME = "" then
sql= "NOME = "" & (NOME) & "" "
else
end if
end if
rs.OpenRecordset sql, hbModeOpenAlways+hbModeReadOnly
if not rs.EOF then
iUNIQUEID = rs.UNIQUEID
iSECRET = rs.SECRET
iCATEGORY = rs.CATEGORY
iDIRTY = rs.DIRTY
iNOME = rs.NOME
iTELEFONE = rs.TELEFONE
iData = rs.DATA
Load = true
end if
Erro:
if err.Number > 0 then
err.MsgBox
err.Clear
end if
rs.Close
Set rs = Nothing
End FUNCTION
Public FUNCTION Save( Optional ByRef operacao as EnCRUD = -1) as Boolean
Dim rs as new dbCONTATO
Dim sql as string
On Error Goto Erro
if not me.iUniqueID <= 0 then
sql= "UniqueID = " & Cstr(UniqueID) & " "
else
if not me.iNOME = "" then
sql= "NOME = "" & (NOME) & "" "
else
end if
end if
rs.OpenRecordset sql, hbModeOpenAlways+hbModeReadWrite,hbCompareText
if not rs.EOF then
rs.Edit
operacao = UPDATE
else
rs.AddNew
operacao = INSERT
if me.iUniqueID > 0 then rs.UniqueID = me.iUniqueID
end if
rs.SECRET = me.iSECRET
rs.CATEGORY = me.iCATEGORY
rs.DIRTY = me.iDIRTY
rs.NOME = me.iNOME
rs.TELEFONE = me.iTELEFONE
rs.DATA = Now
"Forçando a execução de um evento, passaremos como parametro o ditpo de atualização (INSERT|UPDATE)
RaiseEvent BeforeUpdate(operacao)
rs.Update
RaiseEvent AfterUpdate(operacao)
Save = true
if operacao = INSERT then me.iUniqueID = rs.UniqueID
Erro:
"Caso haja erro
if err.Number > 0 then
err.MsgBox
err.Clear
end if
rs.Close
Set rs = Nothing
End FUNCTION
Public Function Delete() as Boolean
Dim rs as new dbCONTATO
Dim sql as string
On Error Goto Erro
if not me.iUniqueID <= 0 then
sql= "UniqueID = " & Cstr(UniqueID) & " "
else
if not me.iNOME = "" then
sql= "NOME = "" & (NOME) & "" "
else
end if
end if
rs.OpenRecordset sql, hbModeOpenAlways+hbModeReadWrite,hbCompareText
if not rs.EOF then
rs.Delete hbRecordDelete
end if
Delete = true
Erro:
if err.Number > 0 then
err.MsgBox
err.Clear
end if
rs.Close
Set rs = Nothing
End Function
Iniciamos a classe utilizando o conceito de encapsulamento, protegemos as nossas variáveis internas e liberamos seu acesso por meio de propriedades. Esta classe ainda posssue dois eventos, são eles “BeforeUpdate” e “AfterUpdate”, o primeiro é executado antes da gravação dos dados no arquivo e o segundo é executado logo após a persistência dos dados no arquivo.
Agora que a camada DAL já está pronta devemos criar uma classe de apoio para carregamento de ListBox e ComboBox, adicione uma nova classe e altere seu nome para “clsChoiceControl”, digite o seguinte código para esta classe.
Listagem 22. Exemplo de rotina que carrega qualquer objeto que seja uma instancia de sub-classes herdeiras de ChoiceControl.
Public Static Sub dbCONTATO(ByRef choice as ChoiceControl,Optional ByRef sql as String = "UNIQUEID > 0 ORDER BY UNIQUEID ASC",Optional ByVal lItemData as Long = 0)
Dim rs as new dbCONTATO
rs.OpenRecordset sql, hbModeOpenAlways+hbModeReadOnly,hbCompareText
choice.Clear
while not rs.EOF
choice.AddItem rs.NOME ,rs.UniqueID
rs.MoveNext
wend
if choice.ListCount > 0 then
if lItemData > 0 then
if choice.FindItemData(lItemData) >= 0 then
choice.ListIndex = choice.FindItemData(lItemData)
else
choice.ListIndex = 0
end if
else
choice.ListIndex = 0
end if
end if
rs.Close
Set rs = nothing
End Sub
Este método estático recebe obrigatoriamente um controle ChoiceControl, por polimorfismo podemos passar um ListBox ou um PopUp(ComboBox) sem alterar em nada nosso código. Neste método também temos um bom exemplo do uso de parâmetros.
Somente com o fim da edição dos arquivos modules, tabelas e classes e que vamos poder editar o código dos formulários. Nosso primeiro formulário a ser editado é o formulário frmListContato, escreve o código exibido na listagem 23.
Listagem 23. Código do formulário frmListContato.
"Ação que realiza um filtro na base segundo algo que foi digitado
Public Sub Carregar(Optional ByVal lItemData as Long = 0)
Dim sql as String
sql = "NOME LIKE "*"& fldSerch.Text &"*""
clsLoadChoice.dbCONTATO lstContato,sql,lItemData
End Sub
"Botão que executa o metodo Carregar
Private Sub btSerching_Click()
Carregar 0
End Sub
"Botão que movimenta para o formulário de cadastro
Private Sub btNew_Click()
Dim frm as new frmViewContato
frm.Show hbFormModal+hbFormPopup
End Sub
"Carrega o formulário de edição, passando como parametro
"o item selecionado no ListBox
Private Sub btNext_Click()
Dim contato as new clsDALContato
Dim frm as new frmViewContato
"Se nada foi selecionado
if lstContato.ListIndex < 0 then
MsgBox "Selecione um item na lista."
Exit Sub
end if
"Estou capturando a chave e armazenado na classe
contato.UNIQUEID = lstContato.ItemData(lstContato.ListIndex)
"Caso consiga carregar os dados da entidade vou para o proximo
"formulário passando o objeto contato como parametro
if contato.Load then
Set frm.CONTATO = contato
frm.Show hbFormModal+hbFormPopup
Carregar contato.UNIQUEID
end if
End Sub
"Finaliza a aplicação
Private Sub btBack_Click()
App.Quit
End Sub
Para o formulário responsável pela visualização e edição de dados digite o código segundo a listagem 24.
No código deste formulário chamamos apenas a atenção para a procedure btNext_Click(), pois nela estamos capturando o lItemData do item selecionado no ListBox e carregando o objeto contato utilizando a procedure Load().
Após carregar os dados é enviado todos os dados deste contato para o próximo formulário, em seguida exibimos o formulário utilizando o método Show().
Listagem 24. Código do formulário frmViewContato.
Private Dim iCONTATO as new clsDALContato
"Propriedade que protege a variável membro, utilizamos Encapsulamento
Public Property SET CONTATO(iCONTATO as clsDALContato)
Set me.iCONTATO = iCONTATO
End Property
"Botão que salva o contato
Private Sub btSave_Click()
"O contato deve conter pelo menos o nome
if fldNome.Text = "" then
MsgBox "Entre com um nome válido."
Exit Sub
end if
"Carego a classe com os dados alterados pelo usuário
me.iCONTATO.NOME = fldNome.Text
me.iCONTATO.TELEFONE = fldTelefone.Text
"O campo Data é protegido pelo encapsulamento
"Caso não consiga salvar, exibiremos a mensagem.
if not me.iCONTATO.Save then
MsgBox "Erro ao gravar dados."
end if
End Sub
"Descarregando o formulário
Private Sub btBack_Click()
unload me
End Sub
"Evento da camada DAL
Private Sub iCONTATO_AfterUpdate(ByVal action As EnCRUD)
"Caso a ação executada no arquivo foi a inclusão de um novo
"registro vamos limpar o campo para facilitar a entrada de dados em sequencia
if action=INSERT then
Set me.iCONTATO = new clsDALContato
fldNome.Text = ""
fldTelefone.Text = ""
fldData.Text = Format(now,"dd/mm/yy")
end if
End Sub
"Evento executado quando o formulário é carregado
Private Sub Form_Load()
"Se for solicitado um novo registro, UNIQUEID = 0
if me.iCONTATO.UNIQUEID = 0 then
fldData.Text = Format(now,"dd/mm/yy")
else
fldNome.Text = me.iCONTATO.NOME
fldTelefone.Text = me.iCONTATO.TELEFONE
fldData.Text = Format(me.iCONTATO.DATA,"dd/mm/yy")
end if
End Sub
Quando o formulário é carregado na memória ele executa automaticamente o evento Form_Load(), quando ele é executado ele verifica se existe um contato carregado em memória, para isso ele verifica se UNIQUEID é diferente de 0 (Zero). Isso porque segundo nossas regras UNIQUEID é uma Primary Key numérica e que possui um algorítimo de autoincremento na qual parte de um numero entre 1 e 2147483647. Utilizamos a função Format() para formatar a data no displey pois internamente estamos trabalhando no formato inglês.
Quando pressionamos o botão Salve estamos executando a procedure btSave_Click(), nesta rotina devemos validar algumas informações antes de qualquer coisa, neste caso somente vamos verificar se existe um nome qualquer. Caso não exista devemos informar através de um MsgBox() e em seguida parar a execução da sub rotina. Se tudo estiver certo devemos atribuir a classe os dados existentes nos Fields e logo em seguida utilizar a função Save().
Se a gravação for efetuada com sucesso o software irá disparar o evento iCONTATO_AfterUpdate() que deve limpar os Fields e o objeto caso o update tenha sido um INSERT, com isso esperamos maior produtividade nas inserções em massa.
Os formulários apresentados aqui fazem parte de um padrão de interface adotado pela Palm Source e descrita em seus livros. A Palm Source disponibiliza gratuitamente dezenas de livros referentes a programação em PDA.
Testando o Aplicativo
Iniciamos nosso aplicativo diretamente no formulário que lista contatos, montamos um esquema de filtro pois acreditamos que há pessoas com inúmeros contatos. Como nossa agenda telefônica está vazia nenhuma informação ser exibida Figura 6.
Figura 5. Formulário frmListContato.
Ao clicar em New será exibido um novo formulário (ver Figura 6), adicione dados a este formulário e pressione Save.
Como é um ato de inserção ele irá limpar os objetos de interface aguardando a entrada de novos dados.
Figura 6. Formulário frmViewContato.
Agora podemos filtrar, veja que ao digitar “w” e pressionar o botão ... será exibido os registros com “w” no inicio do nome.
Figura 7. Formulário frmListContato.
Conclusão
Podemos perceber que o HB++ possui uma linguagem flexível e muito poderosa, aliada a umas boas práticas de programação e a padrões de projetos podemos ter softwares complexos em poucas linhas de código.
Links:
Site do desenvolvedor do HB++
www.handheld-basic.com
Site dedicado a programação em HB++, fórum, artigos, exemplos, etc.
www.softpalm.com.br
Fontes do projeto abordado neste artigo.
http://www.softpalm.com.br/arquivo.aspx?ID=80
Palm Source - Área dedicada a desenvolvedores.
www.palmsource.com
- Como criar um player de audio para Windows PhoneDisp. móveis
- Windows Phone: Criando e lendo arquivos de textoDisp. móveis
- Inserindo, editando e lendo dados no Windows Phone com IsolatedStorageSettingsDisp. móveis
- Introdução ao jQuery MobileJavascript
- Entendendo a navegação entre páginas no Windows Phone 7Disp. móveis