I was curious about how preferences were handled with HB++. This article pulls together information from the Help files, the web site and my current undertanding.
Color key: Main text in black, Help files in green, comments in red.
To understand preferences, it is necessary to start with the Application Class. Note the pattern of inheritance, up to the Object Class. Each Class has its own Members. Note the Members Preferences and Preference Strings.
Application
Class
+ Object + Database + GenericDB + ResourceDB + Application
Description
The Application
class implements the behaviors necessary for interfacing Palm OS®
and your application. This class is not instantiable or clonable. Its functions
are only available by derivation.
All
applications written in HB++ must declare a single unique class deriving from
the Application class. This is the main class of your project, which. the system automatically creates an instance, accessible via
the global App variable. If your project does not contain a
class deriving from Application, or it contains more than one, a warning
is generated and your program may not work properly.
You can see
in the Autograph sample an implementation of the Application
class called clsApplication which manages different launch modes.
Members
|
Members |
Description |
|
|
|
|
Date and time of the next alarm. |
|
|
Activation of an alarm. |
|
|
Custom application launch. |
|
|
Activation of an alarm. |
|
|
Data reception request. |
|
|
Data reception. |
|
|
Global search. |
|
|
Display a record. |
|
|
Normal application launch.
ß This looks familiar from the Autograph
sample. |
|
|
Notification. |
|
|
Launch of a preference panel. |
|
|
Access application preferences.
ß |
|
|
Access application preferences as a string. ß |
|
|
Closes the application. |
|
|
Registers the application for the reception of data. |
|
|
Registers a notification request. |
|
|
Launch after closing a configuration panel. |
|
|
Indicates if the application is already running. |
|
|
Startup after modifying application databases. |
|
|
Startup after system is reinitialized. |
|
|
Application Title. |
|
|
Unregisters the application for reception of data. |
|
|
Unregister a notification request. |
|
|
Application version. |
|
|
Inherited from ResourceDB |
Description |
|
|
|
|
Finds a resource in a database. |
|
|
Accesses a resource in a database. |
|
|
Inherited from GenericDB |
Description |
|
|
|
|
Deletes a record from a database. |
|
|
Opens a database from a DatabaseInfo object. |
|
|
Opens a database from its name. |
|
|
Accesses a record in a database. |
|
|
Number of records in a database |
|
|
Inherited from Database |
Description |
|
|
|
|
Set or return a category name |
|
|
Closes a database. |
|
|
Internal database reference. |
|
|
Returns a DatabaseInfo object. |
|
|
Inherited from Object |
Description |
|
|
|
|
Destination of events sent by the object. |
|
|
Serialization of an object into a stream. |
|
Ok, that was interesting. But what is a Preference? Actually, most palm programmers know the answer to this well. Let’s take a look at the Preference Member first. It uses StreamMemory, which can be confusing, but it has a nice description of the Palm Preference sysem. Just below that , we will look at the PreferenceString Member, which uses the more familiar String.
Preferences
Property
Access application preferences.
Syntax
Public
Property Get Preferences(ByVal iId As Integer) As
StreamMemory
Public Property Set Preferences(ByVal iId As Integer, ByRef objStream As
StreamMemory)
|
Parameter |
Description |
|
|
|
|
iId |
Index of preference block to set or retrieve. |
|
objStream |
A StreamMemory object containing preferences. We will come back to this later… |
Remarks
The Palm OS®
plateform associates configuration information with each application on the
handheld device. Each application thus has access to 32767 distinct memory
blocks, which are saved and then restored at each
synchronization. The contents of these memory blocks are not interpreted
by the system. You should store all the necessary information for your program
to function correctly here.
The iId
parameter specifies the index of the memory block you which to access. Its
value should be between 0 and 32766 inclusive. When reading,
this property returns a StreamMemory object initialized with the
contents of the memory block stored by the system. When writing, the objStream
parameter specifies a StreamMemory object whose contents will be
copied and stored by the system.
Typically,
you use this property to save and restore the state of your application when
launching it. The following example shows how to save and restore the state of
two global variables iOption1 and sOption2 in the block 0 of the
application preferences:
Public iOption1 as IntegerPublic sOption2 as String Public Sub SavePrefs() Dim s as New StreamMemory Write s, iOption1, sOption2 Set App.Preferences(0) = sEnd Sub Public Sub LoadPrefs() Dim s as StreamMemory Set s = App.Preferences(0) Read s, iOption1, sOption2End Sub
PreferenceStrings
Property
Access application preferences as a string.
Syntax
Public
Property Get PreferenceStrings(ByVal iId As Integer) As String
Public Property Let PreferenceStrings(ByVal iId As Integer, ByRef sString As String)
|
Parameter |
Description |
|
|
|
|
iId |
Index of preference block to set or retrieve. |
|
sString |
String to store in preferences.
This
may look more familiar. |
Remarks
This property
allows access to application preferences directly using a string, instead of
using a StreamMemory object. Refer to the Preferences property for more information on
managing preferences.
The following
example shows how to save and restore the state of two global variables iOption1
and sOption2 in the blocks 1 and 2 of the application preferences:
Public iOption1 as IntegerPublic sOption2 as String Public Sub SavePrefs()App.PreferenceStrings(1) = CStr(iOption1) convert to string before saving.
App.PreferenceStrings(2) = sOption2 can save directly
End Sub Public Sub LoadPrefs()iOption1 = CInt(App.Preferences(1)) and then back to an integer
sOption2 = App.Preferences(2) and back directly.
End Sub
If there are many variables whose state you want to save, or they
are not of type String, it is more efficient to write them in a StreamMemory and use the Preferences property. The Autograph sample implements a class, easily
reused in your own applications, to manage preferences in a simple way. Actually, this is in the CountDown sample. Let’s take a look at that now.
The CountDown Sample adds a Class called clsPrefs, which extends Object, which is the root of the Class heirarchy. Part of the script for this Class is noted below:
'----------------------------
Store configuration --------------
Public Sub SavePrefs()
dim s as new StreamMemory
' Serialize this object in a StreamMemory,
' and store it in the application preferences
Write
s, Me
Set
App.Preferences(0)=s
End Sub
'---------------------------- Load
configuration ---------------
Public Sub LoadPrefs()
dim s as StreamMemory
' Retrieve the application preferences, and try
' to serialize it in this object
On
Error Goto NoPref
Set
s=App.Preferences(0)
Read
s, Me
Exit
Sub
' An error occured. Initialize with default
values.
NoPref:
bRing=True
iRingCount=8
eSortOption=hbSortText
szNextAlarmName=""
End Sub
Then in frmMain, we see the
following:
Public Prefs as new clsPrefs '
Configuration
And then code in that app such as
the following:
Private Sub Application_NormalLaunch()
Prefs.LoadPrefs
And
On Error Goto 0
Prefs.bRing=bRing
Prefs.iRingCount=iCount
Prefs.eSortOption=eSort
Prefs.SavePrefs
' Close this form and exit.
Unload Me
Exit Sub
Here is a comment from the User Forum about this application:
See
the clsPrefs class. This class had some members and methods. The members are
the prefs.
We
define 2 methods: LoadPrefs and SavePrefs, that
directly deal with the App.preferences -ie the storage. The Object_Serialize method define how this object behave when it must deal with
a stream -ie when a Read or a Write method is called with an instance of this
class as parameter. (see the Read and Write calls in
the LoadPrefs and SavePrefs functions)
It's
powerful because the serialization principe can be
used in several ways. If I define a StreamSocket object then Write
the Prefs class to this object, the same Object_Serialize event is raised, and
my prefs are then sent over the internet for example.
If
I define a StreamFile object then Write the Prefs class to this object, the
same Object_Serialize event is raised, and my prefs are then stored on a SD
card...
OK, I was
wondering about the Object_Serialize method.
Here it is…
Private
Sub Object_Serialize(ByVal stream As Stream, ByVal
eDirection As HbStream, ByVal lSize As Long)
If eDirection=hbStreamRead Then
' Read member variables from the stream
Read stream, bRing,
iRingCount, eSortOption,szNextAlarmName
Else
'
Write member variables to the stream
Write stream, bRing,
iRingCount, eSortOption,szNextAlarmName
End If
End
Sub
Here are
some other tidbits from the Users Forum:
To
delete a Preference, just set the specified preference to Nothing.
HB++
relies on the PrefGetAppPreferences/PrefSetAppPreferences APIs to implement the
App.PreferenceStrings property, always passing True
for the parameter specifying whether the preference should be saved or not
during HotSync. If you do need preference not being saved, you'll have to
declare the native function.
If you find any errors in this article or if you have suggestions for improvement, please drop me a note.
Jon Blackman
Updated July 5, 2004