home
products
education
support
partners
company

introduction

get started

articles

manual

tutorials

reference docs

case studies

knowledge base

goodies

screenshots

demos

echoes

Carousel zone




home

forums

downloads

bugs

mailing list
XUI Zone - manual

number of ratings 0
average rating 0.00

10 Building pages with Java

Building a Carousel application with Java is a little more complicated than using XML by its very nature however if the same sort of steps are followed in constructing the code then a simple UI application will result.

Java has many advantages over XML and notable amongst these is the reusability engendered by the object oriented nature of the language. Pages created in XML can be reused and extended (they can even be extended with XML). While an XML page is processed once as the page is loaded a Java page can have an extended lifecycle and hence a more extensive setup process. However, that said, Java and XML can be used in unison, mixing and matching as appropriate for your application.

Many of the steps and techniques used in the last chapter will be reused in this chapter, so even if you are not using XML for page declarations we would advise your to read the preceeding chapter for background information. The steps involved are much the same and differ only in implementation. Since the native Java objects are being used directly instead of via XML more features will be available, but for the purposes of the simple examples being used few of these additional features are required. As with other introductory chapters later chapters will cover the features employed in more detail.

Basic form building

At its very simplest a Carousel-Java page requires a class derived from XPage , the basis of all Carousel pages. The traditional HelloWorld example can thus be coded:

Code Sample 10-1 - Hello World coded in Java

import net.xoetrope.xui.*;

public class HelloWorld extends XPage

{

public HelloWorld()

{

componentFactory.addComponent( LABEL, 10 , 40 , 90 , 20 , "Hello World" );

}

}

In the above example the page's base class, XPage , has defined a component factory to help construct components. The addComponent method of this factory is used to create a new component at the specified position, add it to the page, and sets its content. The constant ' LABEL ' is also defined by XPage as a convenience to help identify the component type consistently. Constants are defined for all the built in types, other types are identified by name (a string value).

The use of the factory saves several method calls that are normally used when an IDE generates the UI. The more compact form produced makes it easier to see what is going on and in the long run it is thus easier to maintain.

Using stylesheets

Stylesheets specify sets of colors and fonts. These styles are arranged hierarchically and are intended to add consistency to an application's look. Using styles with the component factory also saves some more setup code.

Like many of the components in Carousel the styles are defined in a styles file. The startup file should include a setting for a ' StyleFile ' which points to the styles file.

Code Sample 10-2 - Startup Properties including a style file reference

UseWindow=false

ClientWidth=240

ClientHeight=300

StartPackage=net.xoetrope.samples.simple

StartClass=StyleSheet

Title=Simple Form Sample

StyleFile=stylesheetstyle.xml

To use the styles the component factory addComponent method signature has been extended to take an extra parameter, the name of the style. The XLabel components might all use the explicit style 'prompt', whereas the XEdit components are styled implicitly by including the XEdit style (if it exists) in the stylesheet. In fact each component has a default style name based upon its type name, but you can override these defaults and specify the style explicitly by appending the style name to the addComponent method call. The fragment below shows two such component additions.

Code Sample 10-3 - Adding a label and an edit field

componentFactory.addComponent( LABEL, 5 , 10 , 90 , 20 , "Firstname:" , "prompt" );

txtFirstname = (XEdit)componentFactory.addComponent( EDIT, 100 , 10 , 100 , 20 , "Joe" );

The construction of the buttons shows the explicit and implicit use of styles. Following on from this the ' Proceed ' button has the XButton style applied because it does not specify a style whereas the ' Cancel ' has specified it's own style.

Code Sample 10-4 - Adding OK and Cancel buttons

btnOK = (XButton)componentFactory.addComponent( BUTTON, 40 , 10 , 60 , 20 , "Proceed" );

btnCancel = (XButton)componentFactory.addComponent( BUTTON, 110 , 10 , 60 , 20 , "Cancel" , "BtnReverse" )

The result of this is shown below. What you see should be identical to what you would have seen had the page been constructed via XML:

Event handling

Using the same page as in the previous section we can see how events are hooked up easily to components without the need to add listeners or import the usual event packages.

Events are added by calling the add SomeEvt Handler of the XPage, where SomeEvt is the event type, for example Item , Mouse , Action and so on. These calls take two parameters, the first being the component which we want to attach the event to and the second being the method to call when the event is triggered.

Code Sample 10-5 - Adding event handlers

private void addEvents()

{

addTextHandler( txtCarCost, "changeAdvance" );

addTextHandler( txtDeposit, "changeAdvance" );

addMouseHandler( btnOK, "proceed" );

}

The called methods must be declared as public void .

Code Sample 10-6 - Simple event handlers

public void changeAdvance()

{

float cost = Float.parseFloat( txtCarCost.getText() );

float deposit = Float.parseFloat( txtDeposit.getText() );

txtAdvance.setText( String.valueOf( cost-deposit) );

}

public void proceed()

{

if ( wasMouseClicked() )

btnOK.setLabel( "Clicked!" );

}

The example illustrates a common error in adding events. In the implementation of the proceed method above you can see that we can use the XPage.wasMouseClicked() method to determine if it was a 'click' which triggered the event. The mouse handler is invoked for multiple events like the mouse press, mouse move and mouse release events and we do not want to respond to all of those events.

The problem is that although we may be responding to a mouse click, the appropriate handler for a button click is an in fact an action handler. Therefore instead of using the addMouseHandler the addActionHandler should have been used. Correcting this error the declaration now looks like:

Code Sample 10-7 - Revised addition of event handlers

private void addEvents()

{

addTextHandler( txtCarCost, "changeAdvance" );

addTextHandler( txtDeposit, "changeAdvance" );

addActionHandler( btnOK, "proceed" );

}

With this revision we can simplify the response method to remove the unnecessary checks.

Code Sample 10-8 - Revised simple event handlers

public void changeAdvance()

{

float cost = Float.parseFloat( txtCarCost.getText() );

float deposit = Float.parseFloat( txtDeposit.getText() );

txtAdvance.setText( String.valueOf( cost-deposit) );

}

public void proceed()

{

btnOK.setLabel( "Clicked!" );

}

If you do indeed need to do more analysis of the event which triggered call you can access the event with the XPage.getCurrentEvent() method and check the event type and properties. The EventHandler returned from the getCurrentEvent() method needs to be cast to the appropriate Handler type depending on how it was declared.

Data binding

Continuing with the example, we next add data bindings to put some content into the page. In the most basic setup, input controls can be bound to data stored in an XML file. Static data is data contained in flat files bundled with the application. Such data is often used for test purposes or during initial development of an application.

To work with data bindings a little configuration is needed and the startup file now requires the entry ModelData=simpledatasets.xml . The referenced file contains the static data. The data in the file is then bound to the input controls using XTextBinding objects.

Code Sample 10-9 - Inserting data bindings

private void addBindings()

{

addBinding( new XTextBinding(txtFirstname, "customer/firstname" ) );

addBinding( new XTextBinding(txtSurname, "customer/surname" ) );

addBinding( new XListBinding(cmbAge, "customer/ageRanges" ) );

addBinding( new XListBinding(txtCarCost, "financial/carcost" ) );

addBinding( new XTextBinding(txtDeposit, "financial/deposit" ) );

}

Validations

Validations are rules that can be used to check that user input is correct. Reusable validation rules are specified in an XML file (named validations.xml by default). For example:

Code Sample 10-10 - Validation rules

mandatory="true"/>

msg="The [age] ({value} [years]) must be between {min} [years] and {max} [years]"

mandatory="true"/>

Here three validation rules are specified for the example shown below. The first two rules merely check that some input has been provided while the third rule checks that an age value is within a minimum and maximum range.

Older versions of the XUI platform required an explicit call to setup the validation handling with a call to the ' setExceptionHandler ' method of the XPage , this is no longer the case .

To use the validations we need to bind the validation to the components with a call to addValidation .

Code Sample 10-11 - Binding the validatin rules to input fields

addValidation( txtFirstname, "firstname" );

addValidation( txtSurname, "surname" );

addValidation( txtAge, "age" );

Putting the complete example together we get:

Code Sample 10-12 - The complete example

package net.xoetrope.samples.simple;

import net.xoetrope.xui.*;

import net.xoetrope.xui.data.*;

public class DataBinding extends XPage

{

XEdit txtFirstname, txtSurname, txtCarCost, txtDeposit, txtAdvance;

XComboBox cmbAge;

XPanel pnlClientInfo, pnlFinancialInfo, pnlButtons;

XButton btnOK, btnCancel;

public DataBinding()

{

pnlClientInfo = (XPanel)componentFactory.addComponent( PANEL, 10 , 10 , 210 , 80 );

pnlFinancialInfo = (XPanel)componentFactory.addComponent( PANEL, 10 , 100 , 210 , 80 );

pnlButtons = (XPanel)componentFactory.addComponent( PANEL, 10 , 200 , 210 , 40 );

pnlClientInfo.setDrawFrame( XPanel.BORDER_BEVEL );

pnlFinancialInfo.setDrawFrame( XPanel.BORDER_BEVEL );

pnlButtons.setDrawFrame( XPanel.BORDER_BEVEL );

componentFactory.setParentComponent( pnlClientInfo );

componentFactory.addComponent( LABEL, 5 , 10 , 90 , 20 , "Firstname:" , "prompt" );

txtFirstname = (XEdit)componentFactory.addComponent( XEDIT, 100 , 10 , 100 , 20 );

componentFactory.addComponent( LABEL, 5 , 30 , 90 , 20 , "Surname:" , "prompt" );

txtSurname = (XEdit)componentFactory.addComponent( XEDIT, 100 , 30 , 100 , 20 );

componentFactory.addComponent( LABEL, 5 , 50 , 90 , 20 , "Age:" , "prompt" );

cmbAge = (XComboBox)componentFactory.addComponent( COMBO, 100 , 50 , 100 , 20 , null , "XEdit" );

componentFactory.setParentComponent( pnlFinancialInfo );

componentFactory.addComponent( LABEL, 5 , 10 , 90 , 20 , "Car cost:" , "prompt" );

txtCarCost = (XEdit)componentFactory.addComponent( EDIT, 100 , 10 , 100 , 20 );

componentFactory.addComponent( LABEL, 5 , 30 , 90 , 20 , "Deposit:" , "prompt" );

txtDeposit = (XEdit)componentFactory.addComponent( EDIT, 100 , 30 , 100 , 20 );

componentFactory.addComponent( LABEL, 5 , 50 , 90 , 20 , "Advance:" , "prompt" );

txtAdvance = (XEdit)componentFactory.addComponent( EDIT, 100 , 50 , 100 , 20 );

txtAdvance.setEnabled( false );

componentFactory.setParentComponent( pnlButtons );

btnOK = (XButton)componentFactory.addComponent( BUTTON, 40 , 10 , 60 , 20 , "Proceed" );

btnCancel = (XButton)componentFactory.addComponent( BUTTON, 110 , 10 , 60 , 20 , "Cancel" ,

"BtnReverse" );

addEvents();

addBindings();

}

public void pageActivated()

{

changeAdvance();

}

private void addEvents()

{

addTextHandler( txtCarCost, "changeAdvance" );

addTextHandler( txtDeposit, "changeAdvance" );

addActionHandler( btnOK, "proceed" );

}

private void addBindings()

{

addBinding( new XTextBinding(txtFirstname, "customer/firstname" ) );

addBinding( new XTextBinding(txtSurname, "customer/surname" ) );

addBinding( new XListBinding(cmbAge, "customer/ageRanges" ) );

addBinding( new XTextBinding(txtCarCost, "financial/carcost" ) );

addBinding( new XTextBinding(txtDeposit, "financial/deposit" ) );

}

public void changeAdvance()

{

float cost = Float.valueOf( txtCarCost.getText() ).floatValue();

float deposit = Float.valueOf( txtDeposit.getText() ).floatValue();

txtAdvance.setText( String.valueOf( cost - deposit) );

}

public void proceed()

{

btnOK.setLabel( "Clicked!" );

}

}

The example makes use of the page's lifecycle method, pageActivated to call the changeAdvance method and update the page once all the components have been setup and the data loaded.

Buddy helpers

In some ways Java coding is more complex than the equivalent XML however once we get over that initial hurdle Java coding can be considerably simpler. One common example of this is the BuddyHelper class that is used to setup labeled components.

Using the BuddyHelper, one call can setup two (or even three) components. The helper is designed to add a label (and sometimes a suffix for say a dimension). The helper not only saves a call to the component factory for adding the label but it also makes it a little easier to get alignments correct. (Remember that layout managers are normally preferable to the null layout).

In the above example the name edit fields could be added with this code:

Code Sample 10-13 - A buddy in use

BuddyHelper buddy = new BuddyHelper( (XStyleFactory)componentFactory );

imgSingle = ( XEdit )buddy.addComponent( EDIT, 5 , 100, 10 , 20 0 , 20 ,

panelWidth, 28, "First Name", "", "prompt" );

imgDouble = ( XEdit )buddy.addComponent( EDIT, 5 , 100, 3 0 , 20 0 , 20,

panelWidth, 28, "Second Name", "", "prompt" );

Carousel has many other helpers like this that can help in building Java application. These helpers are not restricted to UI component creating and they cover all areas of Carousel including the data model, events and so on and are available throughout the lifecycle of the application.

Other helpers

Carousel provides numerous helper classes aimed to simplify Java coding and to remove those verbose typecasting requirements.

Table 10-1 - Some helper classes

NavigationHelper

NavigationHelper extends XPage by adding a few simple methods to assist in navigating from page to page.

DebugLogger

Keep track of errors and warnings and give some statistics when the application shuts down as a debugging aid.

MessageHelper

Formats messages (for 1.1.x JDKs)

NumberFormatter

A utility to help format numbers in accordance with the current Locale

DoubleAdapter

A helper for an double model field

IntegerAdapter

A helper for an integer model field

XTableModelHelper

A utility class to help construct a HTML like table structure

XModelNodeHelper

A helper to eliminate some typecasting with the XModel

Logging

For most applications it is useful to use logging during the develop stage of a project.

Carousel provides the DebugLogger class to provide integrated logging features. This log class keeps track of the number of errors and warnings generated. The amount of logging output can also be configured by setting a log level in this class. Ultimately almost all logging can be suppressed by setting the log level to SILENT . This log level is application wide and can be set or reset at any point in the application lifecycle.

At startup the ' LogLevel ' property is used to set the initial value.

Carousel itself uses logging extensively and this can lead to verbose console output. To further help cut down on the logging Carousel can be built in two forms - with debug logging on or off. The BuildProperties.DEBUG flag controls this logging.

The flag is defined statically so that the compiler will eliminate any code that is excluded by the flag (when it is set to false). This same mechanism can be used to conditionally include logging code in your pages:

Code Sample 10-14 - Adding debug logging

if ( BuildProperties.DEBUG )

DebugLogger.logWarning( "Some log message" );

Compilation and building

Java applications need to be compiled before they can be run. Carousel provides facilities to do this building but it is also possible to build an application from the command line or from a third party tool.

Compiling an application is fairly straightforward as all the classes needed for a build are contained in the XuiALL.jar file. Individual files can be compiled with the Javac command on the command-line, but we recommend using the ANT build tool.

However, as the extent and complexity of a project increases it will be worth considering using the tools that Carousel provides by way of NetBeans or tools such as Eclipse or their commercial equivalents such as JBuilder. These tools provide much more than just compilation support and can be of great benefit when testing and debugging a project.

Switching toolkits

When building an Carousel application with Java it is necessary to derive the page from the XPage class and add components to that page. As part of this process it is necessary to import the definitions of the various objects used in the page, including the Carousel components. At this point it is therefore necessary to choose between the AWT and Swing toolkits as one or the other must be imported.

This import implies a dependency on one of the toolkits. However given judicious programming it should not be a big task to move from one toolkit to the other if you have only used Carousel components and have avoided toolkit specific featured.

In fact all you need do to convert from one toolkit to the other is to change the imports, recompile and test. Of course there will be some differences in the look and feel of the application but by in large the behavior should not change.

Switching toolkits is probably a rare occurrence yet it still remains a good idea to try and reduce dependencies with an application. If possible you should try and isolate dependence of one toolkit or another if only for the purpose of keeping your code clean and clear.

Beyond the basics

Sometimes what is built into a platform may not cover all your needs and it is necessary to add extensions and third party components. Carousel is based on an open design and with Java at the core there are many ways to add and extend the platform.

For example if components outside of the basic framework are employed then they can be registered with Carousel, "Choosing how to install components" (see page 253) and accessed with the techniques described above. Since third party components are not built-in Carousel can only have a limited view or understanding of those components and therefore you may need to manipulate the components directly. Programming in Java allows you do this and once you obtain a reference to a component you can access all its features either directly through the public API or through reflection.

comments


If you were logged in you could rate this article or add a comment.