Introduction

jZeno comes with a fair set of ready-to-use GUI components. These built-in component are all dynamic components. These components facilitate repetitive aspects of the user interface that all applications need to implement. Specifically these components make the folowing tasks easier :

We will cover these functions below.

Before we get started a few words on how to instantiate dynamic components. Every dynamic component has a 3 argument constructor with the folowing arguments :



Databinding

jZeno dynamic components are created using a 'property path', that binds them to an arbitrary java object. Such a property path consists of a sequence of property names (as in the JavaBean specification, this property is specified without the get/set/is prefix). It is important to know that the first property specified is a property on the aggregate (a Screen, Dialog or CustomComponent) you are working on. So lets say you want to create a input box that edits an integer value, an example of this would be :



package get.started;

import net.sf.jzeno.echo.components.Screen;
import net.sf.jzeno.echo.editor.IntegerEditor;

public class MyScreen extends Screen {
	private static final long serialVersionUID = 1L;
    
	private IntegerEditor integerEditor;
	
	private int value = 10;
	
	public MyScreen() {
		integerEditor = new IntegerEditor(getClass(), "value", "");
	}
	
	public void setValue(int value) {
		this.value = value;
	}
	
	public int getValue() {
		return value;
	}
}
	


TIP: In order to get this example working, you should read our getting started section first. Notice that the property 'path' specified on the IntegerEditor only has 1 property, 'value'. Using only a single property on your property path is typically used if you want to have some temporary place to store information, before committing to database, or further processing.

In a lot of applications though, you may want to bind directly to a domain model bean (typically a java bean that is mapped with Hibernate to be persisted in your database), that can be saved by the business layer to a database, or some other javabean in general, that is seperate from the screen you're working on. An example of this would be :



package get.started;

import net.sf.jzeno.echo.components.Screen;
import net.sf.jzeno.echo.editor.IntegerEditor;

public class MyScreen extends Screen {
	private static final long serialVersionUID = 1L;
    
	private IntegerEditor integerEditor;
	
	private ModelBean modelBean;
	
	public MyScreen() {
		integerEditor = new IntegerEditor(getClass(), "modelBean.integer", "");
		modelBean = someBusinessFacade.callThatReturnsAModelBean();
	}
	
	public void setModelBean(ModelBean bean) {
		modelBean = bean;
	}
	
	public ModelBean getModelBean() {
		return modelBean;
	}
}
	


package get.started;

public class ModelBean {
	private static final long serialVersionUID = 1L;

	private int integer = 12;

	public void setInteger(int value) {
		integer = value;
	}
	
	public int getInteger() {
		return integer;
	}
}
	


Some more tips on databinding.

Event handling

To save you from having to implement something like the ActionListener interface very frequently (and/or inner anonymous classes, etc..), jZeno dynamic components allow you to specify a public method on the aggregate you are working on (Screen, Dialog or CustomComponent) to function as event handler. (In fact the real rule is that it is the closest parent of the EventSource that implements the EventSink interface - guess which 3 classes implements this interface :-)). You can specify the method name of the event handler in the actionCommand property. (Either through setting it on the component, or specifying it in the construction hints). An example :



package get.started;

import net.sf.jzeno.echo.components.Screen;
import net.sf.jzeno.echo.databinding.DynaButton;

public class MyScreen extends Screen {
	private static final long serialVersionUID = 1L;
    
	private DynaButton dynaButton;
	
	public MyScreen() {
		dynaButton = new DynaButton(getClass(), "", 
		                            "text=press me,actionCommand=eventHandler");
	}
	
	public void eventHandler() {
		System.out.println("Button pressed.");
	}
}
	


This is the easiest way to use the dynamic event handling. Instead of specifying a method with zero arguments, you can also specify a method with 1 argument which may be either a PropertyComponent or an ActionEvent argument. In the first case the source component that generated the event will get passed into the event handler, and in the second the original echo ActionEvent is passed in. This ActionEvent is identical in use as Swing's ActionEvent. Having this event object can be handy to determine for example what the clicked button was bound to (call getValue() on the source PropertyComponent). This type of combining of dynamic event handling and dynamic databinding is very handy when used inside repeating groups, like a DynaTable (this is jZeno's 'data grid') component.

Do note that the method you specify must be public, and the class where this method occurs must also be public. This is necessary since the framework does not by default have more access to your classes than other java code.



Data Validation

When the user enters information in one of the dynamic components this component is responsible for validating the entry. Typically the components will check things like whether or not the user entered data of the right type (integer, float, etc..). It will typically also check that when a component is marked required that the used entered information. Other requirements can be specified on the individual components (e.g. is zero allowed for the IntegerEditor ?, etc...).

When the information entered by the user is considered valid by the component, it will update the property it is bound to. When the information entered by the user is not considered valid, the incorrect information is retained by the component, but it is not written to the bound property. This behaviour is automatic for all the dynamic components.

The application code can also query a specific dynamic component to know whether or not the currently entered information is valid or not. This can be done by calling isValid() on the component in question. At certain points in the code (say the event handler of a save button) your application may decide to check whether or not all fields on the screen have been correctly entered. It can do this by calling :



EchoSupport.isValidRecursively(this);
	


This basically recurses the component tree, and queries all of the components that implement the PropertyComponent (all jZeno dynamic component do) to check that they are valid. If one of them is not, the method returns false. You may also specify a part of the component tree by passing in the root where querying should start.



Error Marking

A lot of cases an application may want to query all of the components on the screen for validity, it may also want to mark all invalid components on the screen, for the users to clearly see where invalid data is entered, (and at the same time add error messages to tell the user what is wrong). This can be done in jZeno by calling the method :



EchoSupport.doValidationRecursively(this);
	


This operation recurses all components in the component tree (starting at the indicated root) and mark all invalid components as such, and clear any previous markings on now valid components.



Some More Tips

The built-in dynamic components in jZeno have been created to try and remove as much cumbersome coding as possible from your application. If you feel that these are not sufficient/appropriate in a specific situation consider bypassing this abstraction layer.

To find out which components are available and the details on how to use them you can also look at the javadoc