Michael L Brereton - 31 December 2007, http://www.ewesoft.com/
<<
Previous: Setting up the SDK
>>
Next: Using EveMaker
Displaying
a User Interface – Forms
Displaying SoftKeyBars in Forms
This chapter deals with some issues that will be important to experienced Java programmers who wish to get working on Eve as quickly as possible. Since the Eve VM can execute applications from separate class files, just like a Java VM, the use of the EveMaker Program Builder during initial program development is not necessary. EveMaker is really used for packaging your application for deployment. Hence programmers can start writing and testing programs without reading the chapter on EveMaker.
You can start your Eve
application using a static void main(String []args) method as in
standard Java, however you must begin and end the method with two
special function calls. GUI Applications should do this:
import eve.ui.Application;
import eve.ui.MessageBox;
public class HelloWorld {
public static void main(String[] args)
{
Application.startApplication(args);
new MessageBox("Hello World","This is my first message box!",
MessageBox.MBOK).execute();
Application.exit(0);
}
}
As you can see, the first line of the main() method should be Application.startApplication (String args[]). This starts and initializes the Eve System and GUI library. This is only necessary if you are using the main() method for starting your Eve application. It is not necessary if you are starting your Eve application by overriding the Application class or any of the other allowed starting classes. You should also use Application.exit(int code) to exit your Eve application.
A non-GUI, command line only application should start like this:
import eve.sys.Vm;
public class HelloWorld {
public static void main(String[] args)
{
Vm.startEve(args);
System.out.println("Hello World!");
Vm.exit(0);
}
}
Note that the System.out.println() method has no effect when run on a mobile system that does not support consoles (e.g. WindowCE/PocketPC).
Also, avoid using
System.exit(), System.loadLibrary() and System.getProperty() - they will fail when
running as an Applet. Instead use Application.exit() or Vm.exit(),
Vm.loadLibrary() and Vm.getProperty().
This is a special optional method very similar to the main() method and has the same form:
public static void eveMain(String[] args);
This method is called before main() is called and can be used to customize the behavior of the VM before it creates the Application’s default main window. The first window created by the VM becomes the Application’s main window and if one is not created within eveMain() then the VM creates a default window that is appropriate for the current platform. In eveMain() you are given a chance to explicitly create the window yourself thereby achieving behavior that may be required by your particular Application.
Like most GUI systems, Eve UI elements consist of Control objects placed within Container objects (which are themselves types of Control objects) to form a tree of displayable Controls. In order for the Controls to be displayed, the top-level Container must be placed in a Frame which must be then placed in a Window. While this is a fairly complicated process, you will most likely never have to do it. Instead you would have a Form as your top level Control.
A Form “knows” how to place itself correctly in a Frame and then how to display that Frame within a Window (and whether or not a new Window should be opened or whether an existing Window should be used instead). You would simply call one of the show() or execute() methods of the Form to display the Form on the screen. All options regarding the Frame and Window used by the Form (e.g. if the created Window should be maximized) are set using the Form itself.
After the Form is
displayed it receives UI events (user
input, repainting and resizing) from its containing Window. Each Window has its
own Event Thread which is used to receive native UI events from the underlying
OS and then convert them to Eve events which are sent to the correct Control
objects within the Window. When writing Event Handlers (covered in a later
chapter) you must be careful not to block the Thread that called the Event
Handler for any significant amount of time, as this will block the Window
from receiving UI Events and make the application unresponsive. The only
exception to this is the execute() method, which is explained below.
In the first example above we did this:
new MessageBox("Hello World","This is my first message box!",
MessageBox.MBOK).execute();
A MessageBox is a type of Form and you
can see that we used the execute() method which displays it modally and
then waits for it to close. There are three ways of displaying a Form:
1.
execute() – which displays a Form modally and
waits for the Form to close (via the exit(int exitCode)) method.
When a Form is opened modally it blocks user input to other Forms until it
closes or until another Form is also opened modally.
2.
exec() – which displays a Form modally
but returns immediately. You can call waitUntilClosed() at any
time after to wait until the Form has been closed and to get the exitCode
value.
3.
show() – which displays a Form non-modally
and returns immediately.
Note that execute() and exec()
will create a new Event Thread to handle UI events for the current Window, so
that even though waitUntilClosed() blocks the current Thread (which may have
been the original Event Thread) the original Window will still receive UI
events because of the newly created Event Thread. This is why it is safe to
call execute() at any time, including within an Event Handler.
You can specify that you wish the Form to be
displayed within an existing Window instead of in a new Window by using execute(Frame
parent) or show(Frame parent). To get the containing Frame for any
Control call getFrame() on the Control.
Here is an example of a Form that we add a
Panel to containing a number of Controls. The addNext(), addLast()
and other methods will be explained in the next Chapter.
package evesamples.ui;
import eve.fx.Insets;
import eve.fx.gui.WindowConstants;
import eve.ui.Button;
import eve.ui.Form;
import eve.ui.Panel;
import eve.ui.Gui;
//##################################################################
public class TestForm extends Form{
//##################################################################
//===================================================================
public TestForm()
//===================================================================
{
title = "Testing Panel";
Panel p = new Panel();
p.setText("Testing the panel");
p.addNext(new Button("Hello"));
p.addLast(new Button("There!"));
p.addNext(new Button("How"));
p.addLast(new Button("are you?"));
addLast(p);
doButtons(OKB|DEFCANCELB);
}
//##################################################################
}
//##################################################################
Note that there is no main() method in this
class. Because it inherits from Form the VM will automatically create it using
the public default constructor and then call execute() on it. When the
Form exits the application will automatically exit as well. We can therefore
run this by doing:
eve evesamples.ui.TestForm
or:
java -cp eve.jar;./ Eve
evesamples.ui.TestForm
The doButtons(int buttons) method is a
quick way of adding buttons to the bottom of a Form. The values you can use
here are:
OKB – the OK button.
CANCELB – the Cancel button.
DEFOKB – the OK Button where Enter is the hotkey for
the button.
DEFCANCELB – the Cancel button where Esc (or Cancel on a
mobile device) is the hotkey for the button.
YESB – the Yes button.
NOB – the No button.
Pressing these buttons results in a call to exit()
with the following constant int values:
IDOK – the OK button was pressed.
IDCANCEL – a Cancel button was pressed.
IDYES –
(same as IDOK) the Yes button was pressed.
IDNO – the No button was pressed.
If the user presses the ‘X’ button for the
Window then exit() is called with a value of IDCANCEL.
It is possible to validate a Form before
exiting (and possibly aborting the exit) by overriding the boolean
canExit(int exitCode) method. For example if we add this method to the Form
above:
//===================================================================
protected boolean canExit(int exitCode)
//===================================================================
{
if (exitCode != IDCANCEL){
Gui.flashMessage("Please cancel!",this);
return false;
}
return true;
}
Run this new code and the Form will not exit
unless the Cancel or ‘X’ button is pressed. The Gui.flashMessage(String
message, Control parent) is a convenient way of flashing a simple message
to the user – particularly appropriate for mobile devices.
The main way of controlling how a Form is
displayed is by adjusting the windowFlagsToSet and windowFlagsToClear
fields of the Form. Normally a new Window is displayed in a way that is
consistent with the underlying OS – however you can explicitly turn on or off
certain Window properties by setting bits in either or both of these two
fields.
The bit values to use should be any of the eve.fx.gui.WindowConstants.FLAG_XXX
values (see the API). For example
if we modify the constructor by adding the following two lines:
…
doButtons(OKB|CANCELB);
windowFlagsToSet |= WindowConstants.FLAG_MAXIMIZE;
windowFlagsToClear |= WindowConstants.FLAG_HAS_CLOSE_BUTTON;
}
If you run this using the native Eve VM
– the Form will be maximized on the screen (since we set the FLAG_MAXIMIZE bit)
and will not display an ‘X’ button (since we clear the FLAG_HAS_CLOSE_BUTTON
bit). However under Java the ‘X’ button is still displayed since there
does not seem to be any way to remove it under Java.
The title of a Form can be set and the
Window title will normally be set to this value when the Form is displayed.
There is also a windowTitle for a Form. If this is not null it will
override the title field and it will be used for the Window title
instead. However if windowTitle has the special constant value WINDOW_TITLE_DONT_CHANGE
then the Window will not have its title changed by the display of the Form.
The windowIcon can be set for a Form to
be an ImageData object (explained later) or a DeviceIcon (a
better choice) created by eve.sys.Device.createIcon().
Some other options for a Form include (their
names explain their purpose):
public boolean inheritSoftKeys = false;
public boolean resizable = !Gui.isPDA;
public boolean moveable = !Gui.isPDA;
public boolean hasTitle = true;
public boolean resizeOnSIP = false;
public boolean keepFrame = true;
public boolean noBorder = Gui.hasSoftKeys;
public boolean hasTopBar = !Gui.hasSoftKeys;
public boolean exitSystemOnClose = false;
SoftKeys refer to the two Button/Menus that appear at
the bottom of Windows Mobile 5/6 devices and other mobile devices. This is the preferred method for selection
options and actions for modern mobile devices. The Eve UI library fully
supports the use of SoftKey bars in any number of configurations and SoftKeyBar
setup and event handling should normally be done in your application Forms.
The image below shows the Eve Launcher running
simulating a Windows Mobile 5 device. The SoftKeyBar displayed for the active
Form has a menu assigned to the first key (on the left) and a single button
(Exit) assigned to the right.
When you create a Form you should determine what
type of SoftKeyBar (if any) is available on the system using: SoftKeyBar.getType().
This returns:
o
TYPE_NONE – for no SoftKeyBar support.
o
TYPE_SINGLE – for a SoftKeyBar with only one
button/menu item.
o
TYPE_DOUBLE – for a SoftKeyBar with two buttons/menu
items (the maximum supported by Eve).
o
TYPE_MENU – for a SoftKeyBar with only one
item that must be a menu and which may be hidden until the user presses the
special “Menu” key (e.g. on Android)
Once you determine the type and number of keys you
can begin setting up the SoftKeyBar for your Form. You do this by creating a
new SoftKeyBar object and then setting the one or two keys for the bar using
one of the setKey() methods. Then you assign the created SoftKeyBar to
the Form using the Form.setSoftKeyBarFor() method.
Forms actually allow you to specify different
SoftKeyBars for different Controls on the Form depending on which Control has
the keyboard focus. The Form method:
public void setSoftKeyBarFor(Control c, SoftKeyBar bar)
Will set up the Form such that when the
specified Control has the focus the assigned SoftKeyBar will be displayed. If
the c parameter is null, then this will be the default SoftKeyBar for
the Form and is displayed for all Controls which do not have a specific
SoftKeyBar assigned to them. The method below is used to assign a SoftKeyBar to
a number of Controls in a Vector.
public void setSoftKeyBarForAll(Vector controls, SoftKeyBar bar)
The simplest way to handle SoftKey commands is
to assign an Action to each Button or MenuItem used within a SoftKeyBar.
When the Button is pressed or when the MenuItem is selected the handleAction(String
action) method of the Form will be called. Note that MenuItems and Buttons
have an individual field called action. If this field is not set the
default behaviour is for the normal text for the Button or MenuItem to be used
as the action.
To summarize, to correctly use the SoftKeyBar
in a Form you should follow these steps:
1.
Determine
how many keys, if any, are available on the current platform.
2.
Create
Menus and/or Buttons for assignments to the SoftKeys.
3.
Create
a SoftKeyBar and assign the created Menus and Buttons to the keys.
4.
Assign
the SoftKeyBar to the Form.
5.
If
there are different Menus/Button combinations for different active Controls in
the Form, then create SoftKeyBars for the different Controls as necessary.
6.
Override
the handleAction() method to handle the user selection of the SoftKeyBar
Menus and Buttons.
There is also a special method call: Gui.simulateSoftKeysOnPDA(int
softKeyBarType). This method will ensure that, if run on a PDA (or a
simulated PDA – a device with a touch screen, no mouse pointer and no keyboard)
which does not normally use SoftKey bars (e.g. PocketPC 200x) the Eve library
will run as if the system did in fact have a SoftKey bar. This is useful when
writing software targeting Windows Mobile 5/6 devices but which may also be run
on a PocketPC or other PDA which does not normally have native SoftKey bars.
The Eve VM Launcher uses this method so that its interface on a PocketPC is
exactly the same as on Windows Mobile devices.
This method, if used, must be called in the eveMain()
method so as to have effect before any native windows are created.
All these concepts are shown in the example
shown below:
package evesamples.ui;
import eve.ui.Application;
import eve.ui.Button;
import eve.ui.Control;
import eve.ui.Form;
import eve.ui.Gui;
import eve.ui.Input;
import eve.ui.InputStack;
import eve.ui.Menu;
import eve.ui.MenuItem;
import eve.ui.SoftKeyBar;
public class SoftKeyDemo extends Form{
Input myInput, secondInput;
public SoftKeyDemo()
{
title = "SoftKeyBar Demo";
maximizeOnPDA();
InputStack is = new InputStack();
myInput = is.addInput("Input:","");
secondInput = is.addInput("Another:","");
addLast(is).setCell(HSTRETCH);
addLast(new Button("Hello Button")).setCell(HSTRETCH);
//
Button b = new Button("Exit Now","eve/exitsmall.png");
b.action = "exit_action";
//
if (SoftKeyBar.getType() != SoftKeyBar.TYPE_NONE){
//
if (true){
//
// Create a bar that is different for the inputs.
//
SoftKeyBar sk = new SoftKeyBar();
Menu left = new Menu();
//
// Make a menu with three items.
//
Menu fixedText = new Menu(new String[]{"One","Two","Three"},"Fixed Text");
left.addItem(fixedText);
left.addItem(new MenuItem("Clear","clear_action"));
if (SoftKeyBar.numberOfKeys() == 1){
left.addItem("-");
left.addItem(sk.createMenuItem(b));
}else{
sk.setKey(2,b);
}
sk.setKey(1, "Actions", left);
setSoftKeyBarFor(myInput, sk);
setSoftKeyBarFor(secondInput, sk);
}
if (true){
//
//Create a default bar for all other controls.
//
SoftKeyBar sk = new SoftKeyBar();
sk.setKey(SoftKeyBar.numberOfKeys(),b);
setSoftKeyBarFor(null, sk);
}
}else{
addButton(b);
}
}
public static void eveMain(String[] args)
{
//
// Try using these other values: TYPE_SINGLE, TYPE_MENU
//
Gui.simulateSoftkeysOnPDA(SoftKeyBar.TYPE_DOUBLE);
}
public boolean handleAction(String action)
{
Control c = Gui.focusedControl();
if (action.equals("clear_action")){
if (c != null) c.setText("");
return true;
}else if (action.equals("exit_action")){
exit(IDOK);
return true;
}else{
if (c != null) c.setText(action);
return true;
}
}
public static void main(String[] args)
{
Application.startApplication(args);
new SoftKeyDemo().execute();
Application.exit(0);
}
}
Here is how it looks when run as a PDA. The
left image is what is displayed when one of the inputs has the focus, the
center image is what is displayed when the user selects the “Actions” SoftKey
and the right image is what is displayed when none of the inputs have the
focus.
eve
/p5 evesamples.ui.SoftKeyDemo
and here is how it looks when run as a normal
desktop application:
eve
evesamples.ui.SoftKeyDemo
You will note that in the line:
Menu fixedText = new Menu(new String[]{"One","Two","Three"},"Fixed Text");
I created a Menu from an array of Strings. This
creation method does not allow me to specify at that time what the action
String should be. I could have instead created an empty Menu and then added
MenuItems to it instead. When creating the individual MenuItem objects I can
specify what the action for each item should be. There is also a convenience
SoftKeyBar method called createMenuItem(String label, String action, Iimage
icon) that can be used to create a new MenuItem for adding to a Menu that
will be set to a SoftKeyBar.