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 Oliveira



Programaçã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.

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.

Tabela 3. Propriedades do formulário.

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.

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.

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.

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

Wellington Pinto de Oliveira

Wellington Pinto de Oliveira - Autor do livro "Desenvolvendo Aplicações Palm com NS Basic", atualmente trabalha com automação de processos industriais e códigos de barras. http://www.softpalm.com.br.