How to create a StatusBarController with the zk framework ?

A simple statusBarController that works with the new zk5 EventQueues mechanism.

In this article we will create a statusBar that lay in the south area from a borderlayout and access it in a pretty simple way that the zk 5.x version will give us. Exactly the new EventQueues mechanism.

The statusBar should have 5 columns for UserName, OfficeId, selectedRecordObject (That we can see which i.e. customer is selected if we change the tab from listView to detailView).

One way is to create the columns of the statusBar in a zul-template like this:

pieces of the zul-template

            .  .  .
			<south id="south" border="none" margins="1,0,0,0"
				height="20px" splittable="false" flex="true">
				<div id="divSouth">

					<grid id="statusBarGrid" fixedLayout="true"
						height="20px" width="100%">
						<columns sizable="false">

							<column label="User:" width="10%"
								style="background-color: #D6DCDE;" />

							<column id="statusBarColUser" label=""
								width="10%" style="background-color: #D6DCDE;" />

							<column label="Office-No.:" width="10%"
								style="background-color: #D6DCDE;" />

							<column id="statusBarSelectedObject"
								width="30%" style="color: blue; background-color: #D6DCDE;" />

							<column id="statusBarAppVersion"
								style="color: #FF0000; background-color: #D6DCDE;" width="20%" />

							<column id="statusBarTableSchema"
								width="20%" style="color: blue; background-color: #D6DCDE;"
								align="left" />

						</columns>
					</grid>
				</div>

			</south>
		</borderlayout>

It should looks like in this picture:

StatusBarController

StatusBarController

As before zk 5.x we can do actualizing such statusBar columns in the old way by getting the needed objects with a chain of getFellow()’s or a little smaller with autowireing the components with a GenericForwardComposer.

pieces of the old java controller code

            .  .  .
		// show the selected Customers data in the statusBar column 'statusBarSelectedObject'
		if (aCustomer != null) {
			Column aColumn = (Column) event.getPage().getFirstRoot().getFellowIfAny("statusBarSelectedObject");

			if (aColumn != null) {
				aColumn.setLabel("--> " + aCustomer.getName1() + ", " + aCustomer.getName2() + "; " + aCustomer.getZip() + "-" + aCustomer.getCity());
			}
		}

With the EventQueues mechanism ships with zk 5.x it’s easy to do such things in a more elegant way. Jump over namespaces or different controllers away. It works like a global installed listener that if once declared you can reach them from any piece in your application. For that fine way we will spend a little more time for coding the controller. In it we create a grid and the 5 localized columns. In the afterCompose() method we setup the EventQueues ‘Listeners’ for the 5 columns. Like ‘the same procedure as every year, James?’ we create all inside a window container component so we need only one line of code in the zul-template for declaring our statusBarController.

The controller code looks like this:

StatusBarCtrl.java


package de.forsthaus.webui.util;

import java.io.Serializable;

import org.apache.log4j.Logger;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.EventQueues;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Window;

/**
 * =======================================================================<br>
 * StatusBarController. <br>
 * =======================================================================<br>
 * Works with the EventQueues mechanism of zk. ALl needed components are created
 * in this class. In the zul-template declare only this controller with
 * 'apply' to a window component.<br>
 * 
 * Declaration in the zul-file:<br>
 * 
 * <pre>
 * < borderlayout >
 *   . . .
 *    < !-- STATUS BAR AREA -- >
 *    < south id="south" border="none" margins="1,0,0,0"
 * 		height="20px" splittable="false" flex="true" >
 * 	      < div id="divSouth" >
 * 
 *          < !-- The StatusBar. Comps are created in the Controller -- >
 *          < window id="winStatusBar" apply="${statusBarCtrl}"
 *                   border="none" width="100%" height="100%" />
 * 
 *        < /div >
 *    < /south >
 *  < /borderlayout >
 * </pre>
 * 
 * call in java to actualize a columns label:
 * 
 * <pre>
 * EventQueues.lookup(&quot;userNameEventQueue&quot;, EventQueues.DESKTOP, true).publish(new Event(&quot;onChangeSelectedObject&quot;, null, &quot;new Value&quot;));
 * </pre>
 * 
 * Spring bean declaration:
 * 
 * <pre>
 * < !-- StatusBarController -->
 * < bean id="statusBarCtrl" class="de.forsthaus.webui.util.StatusBarCtrl"
 *    scope="prototype">
 * < /bean>
 * </pre>
 * 
 * since: zk 5.0.0
 * 
 * @author sgerth
 * 
 */
public class StatusBarCtrl extends GenericForwardComposer implements Serializable {

	private static final long serialVersionUID = 1L;
	private transient final static Logger logger = Logger.getLogger(StatusBarCtrl.class);

	protected Window winStatusBar; // autowired

	// Used Columns
	private Column statusBarColUser;
	private Column statusBarOfficeId; 
	private Column statusBarSelectedObject;
	private Column statusBarAppVersion;
	private Column statusBarTableSchema;

	// Localized labels for the columns
	private String _labelUser = Labels.getLabel("common.User") + ": ";
	private String _labelOfficeId = Labels.getLabel("common.OfficeId") + ": ";
	private String _labelSelectedObject = Labels.getLabel("common.SelectedSign") + ": ";
	private String _labelAppVersion = Labels.getLabel("common.Version") + ": ";
	private String _labelTableSchema = Labels.getLabel("common.TableSchema") + ": ";

	/**
	 * Default constructor.
	 */
	public StatusBarCtrl() {
		super();

		if (logger.isDebugEnabled()) {
			logger.debug("--> super()");
		}
	}

	@Override
	public void doAfterCompose(Component window) throws Exception {
		super.doAfterCompose(window);

		// Listener for Username
		EventQueues.lookup("userNameEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarColUser.setLabel(_labelUser + msg);
			}
		});

		// Listener for OfficeId
		EventQueues.lookup("officeIdEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarOfficeId.setLabel(_labelOfficeId + msg);
			}
		});

		// Listener for selected Record
		EventQueues.lookup("selectedObjectEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarSelectedObject.setLabel(_labelSelectedObject + msg);
			}
		});

		// Listener for applicationVersion
		EventQueues.lookup("appVersionEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarAppVersion.setLabel(_labelAppVersion + msg);
			}
		});

		// Listener for TableSchemaName
		EventQueues.lookup("tableSchemaEventQueue", EventQueues.DESKTOP, true).subscribe(new EventListener() {
			public void onEvent(Event event) throws Exception {
				String msg = (String) event.getData();
				statusBarTableSchema.setLabel(_labelTableSchema + msg);
			}
		});

	}

	/**
	 * Automatically called method from zk.
	 * 
	 * @param event
	 */
	public void onCreate$winStatusBar(Event event) {

		Grid grid = new Grid();
		grid.setHeight("100%");
		grid.setWidth("100%");
		grid.setParent(winStatusBar);

		Columns columns = new Columns();
		columns.setSizable(false);
		columns.setParent(grid);

		statusBarColUser = new Column();
		statusBarColUser.setLabel(_labelUser);
		statusBarColUser.setWidth("10%");
		statusBarColUser.setStyle("background-color: #D6DCDE;");
		statusBarColUser.setParent(columns);

		statusBarOfficeId = new Column();
		statusBarOfficeId.setLabel(_labelOfficeId);
		statusBarOfficeId.setWidth("10%");
		statusBarOfficeId.setStyle("background-color: #D6DCDE;");
		statusBarOfficeId.setParent(columns);

		statusBarSelectedObject = new Column();
		statusBarSelectedObject.setLabel(_labelSelectedObject);
		statusBarSelectedObject.setWidth("30%");
		statusBarSelectedObject.setStyle("background-color: #D6DCDE; color: blue;");
		statusBarSelectedObject.setParent(columns);

		statusBarAppVersion = new Column();
		statusBarAppVersion.setLabel(_labelAppVersion);
		statusBarAppVersion.setWidth("20%");
		statusBarAppVersion.setStyle("background-color: #D6DCDE; color: #FF0000;");
		statusBarAppVersion.setParent(columns);

		statusBarTableSchema = new Column();
		statusBarTableSchema.setLabel(_labelTableSchema);
		statusBarTableSchema.setWidth("10%");
		statusBarTableSchema.setStyle("background-color: #D6DCDE; color: blue;");
		statusBarTableSchema.setParent(columns);

	}
}

We can now add the statusBar in our zul-template with a single line of code:

As we mentioned we would have it in the south area of our borderlayout we moved it to there. Now the pieces of the zul-file looks like this:

pieces of the zul-template

   .  .  .
		    <!-- STATUS BAR AREA -->
			<south id="south" border="none" margins="1,0,0,0"
				height="20px" splittable="false" flex="true">
				<div id="divSouth">

					<!-- The StatusBar. Comps are created in the Controller -->
					<window id="winStatusBar" apply="${statusBarCtrl}" border="none" width="100%" height="100%" />

				</div>
			</south>
		</borderlayout>
   .  .  .

At last we have a look on how we call such a ‘listener’ . Therefore we imagine we have a listbox with an onSelect() event. By selecting an listItem we call the corresponding method an get the selected Item. In our case we get it from the DataBinder so we must not casting it to the right object. The .publish() method will send the events data to the EventQueues listener and there’s the code running that we have defined in the onEvent() method. The final code looks like here:

calling the EventQueue


	public void onSelect$listBoxCustomer(Event event) {

		Customer aCustomer = getSelectedCustomer();

		if (aCustomer != null) {
	        	
         		// show the objects data in the statusBar
		        EventQueues.lookup("selectedObjectEventQueue", EventQueues.DESKTOP, true).publish(new Event("onChangeSelectedObject", null, aCustomer.getName1()));
		}
	}

Samples are hostet in the Zksample2 project on

Have fun with it.

Stephan Gerth

Dipl.rer.pol.


PS: Help to prevent the global warming by writing cool software

Leave a Reply

You must be logged in to post a comment.