Java™-based development framework for PalmOS™ devices (PDAs) Copyright© 2000 by Bernd R. Fix. All Rights Reserved. |
|
DynaWorks TutorialHow to write applications with the DynaWorks framework |
DynaPage: Table Of Content |
|||||||||||||||||||||||||||||||||||||||||||||||||
DynaPage - creating multi-screen applications easily |
|||||||||||||||||||||||||||||||||||||||||||||||||
DynaPage is the application and GUI oriented part of
the framework. You can use the these classes to create an application
Most applications have different screens or views where
application-specific data is displayed and manipulated by the user.
For example you can have a view with a listbox of all data records
in your custom database; if the user selects a single entry you may want
to display a new 'view' where the user can manipulate the data in that
record and can switch back to the 'view' with the overall selection list. The layout and functionality of each 'view' is application-specific; the DynaWorks framework only supports you in creating such views easily. Just to get the words right: A screen or view is called a Page in the DynaWorks framework. A Page will contain UserWidget controls, that are the user interface elements that display the data and interact with the user. All standard controls like Button, CheckBox, ComboxBox, RadioButton, ListBox, TreeView and many more are part of DynaWorks. It is very easy to write your own widgets as described in a seperate chapter. If you use the MVC (Model-View-Controler) paradigm as a base for your software development, you already have separated the data (Model) from the display process (View) and your GUI logic (Controler) and you will probably find no difficulties in using DynaWorks because the framework supports the MVC approach in some primitve way; otherwise you might take a closer look on the examples supplied with the framework. The following sections will explain how to write an application using the DynaWorks framework.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
"Keep it as simple as possible - but no simpler..." |
|||||||||||||||||||||||||||||||||||||||||||||||||
these words accredited to Albert Einstein, are the leading idea behind
DynaWorks framework - maybe because I am a
physicist myself. In the beginning I "only" wanted a simple, easy-to-use but still flexible framework for Java-based PalmOS application development for myself. But the developing the framework itself was so exciting and so much fun, that I thought it might be of interest to more than just me - so I released it as Open Source. A lot of people have downloaded DynaWorks - much more than I ever expected. And there where a lot of wishes too: and wherever they made sense to me, I have incorporated them. But the goal is still to keep it as simple as possible. If you want to learn more about the internal technology of DynaWorks in the Technologysection. In the DynaWorks part of the framework every application consists of one or more so-called pages. A page can hold any number of user interface controls like buttons, checkboxes and the like. By utilizing more pages in an application you can present different views of the app to the user. When I thought of developing a GUI framework I decided not to use the standard AWT approach which I find oversized for Palm apps. If you have a screen of just 160x160 pixel, there is for example no real need for a layout manager. So my goal was to keep the framework as small as possible but nevertheless to allow fullfledged application development.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
A very simple demo |
|||||||||||||||||||||||||||||||||||||||||||||||||
Let's write a small demo application that will help you to catch the basic ideas
behind the scenes. It will consist of only one page that contains a 'exit' button
and a text.
First we write the class that will be executed by the JVM; let's call the file
MyApp.java: (You can find all the example source files in the examples directory of your Dynaworks installation)
The static main() method instanciates a new named Application object. The name of the application must be unique; at least if different DynaWorks applications run inside the same KVM.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Adding a page to the application |
|||||||||||||||||||||||||||||||||||||||||||||||||
The next step is to add a Page object to the application.
A Page object encapsulates an user interface screen
representation, e.g. a full-screen fixed-size dialog that can hold user
interface controls. Every application needs at least one page to be
functional! A page is identified by a name that also needs to be unique for the application. You can have the same name for pages in different applications without problems. You start the application by calling the application's run() method with the page you want to start with. All user interaction and rendering is handled by a Page object; let's assume we implemented our page class in a file called MyPage.java:
In this easy case there are three methods that need to be implemented/overridden: |
|||||||||||||||||||||||||||||||||||||||||||||||||
Overriding the constructor that instanciates the user interface elements | |||||||||||||||||||||||||||||||||||||||||||||||||
You can add all of the available user interface element types to a page;
DynaWorks even allows you to write your
own user interface widgets! All you have to do is
to call the add() of the Page
with the user interface object as an argument. Because you will need the object
reference to the control later in the event processing, you better store the
object in a private attribute. You can use the following predefined controls:
Don't forget to call the super(name) method at the beginning of the constructor! |
|||||||||||||||||||||||||||||||||||||||||||||||||
A handleEvent() method to react to user interaction | |||||||||||||||||||||||||||||||||||||||||||||||||
The underlying DynaWorks framework 'converts' user
interface interactions with controls on a page into ActionEvents
that are passed into the handleEvent() method of that page. To find out what type of event occured and which user control initiated the event you have two methods available:
Object source = (ActionEvent) e.getSource(); int code = (ActionEvent) e.getCode();The source object refers directly to the control that you created in the constructor of the page so you can find out which user interface object initiated the event. The code value helps you to find out which type of event occured. Not all events that occur on the kjava level are reflected to the handleEvent() method; most of the events are passed directly to the controls and are processed there. The following table tells you what event types can show up for what class of user control (your custom widgets of course can send all event types):
Although this table may look rather sparse it supports all basic interactions with controls. That some 'usefull' events are not triggered (like a VALUE_CHANGE event from a Slider) is a kjava problem because there is no access to the internal state (value) of a Slider. So you will probably end up like me: Writing your own widgets that send all events neccessary. In the following section you will find an example of a slider widget that triggers all these events. |
|||||||||||||||||||||||||||||||||||||||||||||||||
A paint() method to render the page on the screen. | |||||||||||||||||||||||||||||||||||||||||||||||||
Note that user interface elements that are added to a page are painted thru the base
class. So don't forget to call super.paint() at the beginning
of your own paint() method. You can use this method to draw additional graphic on the page; you don't have to care for your user controls!
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Page-based event handling |
|||||||||||||||||||||||||||||||||||||||||||||||||
The are probably some more methods you want to override in your page class; especially the
keyDown() event handler is interesting, if you want to process the
PAGEUP, PAGEDOWN or any of the
KEY_HARD<x>> or <???>ICON key
events in your page class (or its controls!). A sample implementation looks like this:
Your keyDown() handler receives an integer argument representing the key, the user has entered or pressed; it can have on of the following values:
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Creating an application with more pages |
|||||||||||||||||||||||||||||||||||||||||||||||||
The last thing you must know is how to work with more than one page
in your application. So we will extend our little demo app from chaper
2 and include two more pages. First we extend the source code in MyApp.java:
As you can see we have added two more page objects to the application; a ViewPage and a SearchPage (don't care about the names - it's just an example). The demo should show the following behaviour: If you start the application you enter an 'intro' page (MyPage) that has a text and three buttons: an exit button (which quits the app), a 'view' button and a 'search' button. If you click the view button, you go to the page ViewPage which has an 'exit' button (that quits the application if clicked) and a 'search' button. The search button in either case displays the "SearchPage" page with a 'back' button. If you click that button you return to the calling page! How is that achieved? Let's have a (simplified) look at the page classes:
Every page terminates by passing a String object back to the application object. The following rules apply to the String object:
|
|||||||||||||||||||||||||||||||||||||||||||||||||
What happens in a multi-page application? |
|||||||||||||||||||||||||||||||||||||||||||||||||
The little example we have just discussed is a very simple one. In fact, it does nothing
than flipping some pages and having buttons to be pressed. Real-world applications process data - and so almost all pages in a multiple page application need to share the application data. The object store for these application-wide, cross-page data objects is explained in a later chapter. Whenever a page is about to be activated, its perform() method is called. This is the place to initialize attributes, read from the application data objects and to setup user controls when neccessary. A standard perform() method can look like this:
N.B.: It is very important to call the super.perform() method at the end of your initialization! The page design even allows to start threads at the perform() method. The thread can even continue to run when you flip to another page! But keep two things in mind: A Palm is not a full-fledged desktop computer and can handle threads at much less speed, so keep the number of threads small and and thread execution time short. And make sure that all threads terminate (at latest) on application exit.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Using the object store |
|||||||||||||||||||||||||||||||||||||||||||||||||
The DynaPage framework includes the concept of data stores for data shared
accross DynaPage applications or across pages within a single application. The base class for all this is a DataDictionary that maps String keys to value objects. Any Java object can be used as a value. All DynaPage applications have a global hashtable that maps String names against DataDictionary entries. All DynaPage applications share a global DataDictionary called System and have a private DataDictionary that has the same name as the application.
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Global data dictionary 'System' |
|||||||||||||||||||||||||||||||||||||||||||||||||
The global DataDictionary System is a place where
DynaPage application can
share data between each other. The following code fragments show how to add
and retreive entries in the System dictionary; remember that the code
can only be included in methods of a class derived from Application.
// add a variable to "System" Application.os.get("System").put("VarName", var); // get a variable from "System" Object var = Application.os.get("System").get("VarName");The global dictionary remains available, until all DynaPage-based applications have been terminated and are removed from memory. The System dictionary is not persistent between application invocations; don't rely on something like a persistent data store in a data dictionary!
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Local data dictionary |
|||||||||||||||||||||||||||||||||||||||||||||||||
The local data dictionary is stored globally under the application name
(and can be accessed from other DynaPage applications,
see example further below). Any DynaPage application has simplified access methods for the local dictionary inside the classes Application and Page:
// add a variable to the local dictionary. addVariable ("VarName", var); // get a variable from the local dictionary. Object var = getVariable (var);So you can easily store data in the local dictionary during construction of the application object (like opening a database) and then later re-use this data for the specific processing on the application pages. If you want to access the local dictionary of another application concurrently running on the Palm, all you have to know is the specific application name. You can and retreive entries in the dictionary with the following code lines; remember that the code can only be included in methods of a class derived from Application.
// add a variable to "System" Application.os.get("AppName").put("VarName", var); // get a variable from "System" Object var = Application.os.get("AppName").get("VarName");The local dictionary remains available, until all instances of the specific DynaWorks-based application have been terminated and are removed from memory. The local dictionary is not persistent between application invocations; don't rely on something like a persistent data store in a data dictionary!
|