Thursday, March 22, 2012

ZK and Design Patterns
----------------------------------------------------------------------------

The ability of ZK framework to separate data and logic from presentation make it possible to use design patterns to develop complex GUIs with little learning curve and without second thought. In this article I will show you how to develop a complex GUI using design patterns which I derived from zk-sample2 [1].


The following are the list of design patterns:

  • ZK Label
<label id="label_ ${tableClassName}Dialog_${columnVar}"
value="${c:l('label_${tableClassName}Dialog_${columnVar}.value')}" />
  • ZK Textbox
<textbox id="${columnVar}" width="100px " />

  • ZK Textbox - multiline
<textbox id="${columnVar}" width="100px" multiline="true" rows="2" />
  • ZK Datebox
<datebox id="${columnVar}" cols="20" format="yyyy/MM/dd a hh:mm:ss" onCreate="self.value = new Date()" />

  • ZK Combobox
<combobox id="${columnVar}" width="100px">
<comboitem>
:
:
</comboitem>
</combobox>

  • ZK Comboitem
<comboitem id="${comboItemVar}" label="${c:l('label_${ComboItemName}.value')}" />

  • ZK DecimalBox
<decimalbox id="${columnVar}" format="#,##0.00" width="100px" />

  • ZK CheckBox
<checkbox id="${columnVar}" />

  • ZK ListBox
<listbox id="${columnVar}" width="120px" mold="select" multiple="false" rows="1" />
  • ZK ListBox - Search
<listbox id="listBox${tableClassName}Search" width="100%" height="100%" multiple="false">
<listhead sizable=’true”>
<listheader>
:
:
</listheader>
</listhead>
</listbox>

  • ZK ListHead
<listhead sizable="true">
:
:
</listhead>

  • ZK ListHeader
<listheader id="listheader_${columnVar}" sort="auto" width="30%" label="${c:l('listheader_${columnVar}.label')}" />

  • ZK ListBox -Example
<listbox id="listBoxCustomerSearch" width="100%" height="100%" multiple="false">
<listhead sizable="true">
<listheader id="listheader_CustNo_2" sort="auto" width="15%" label="${c:l('label_OrderDialog_kunName1.label')}" />
<listheader id="listheader_CustMatchcode_2" sort="auto" width="25%" label="${c:l('listheader_CustMatchcode_2.label')}" />
<listheader id="listheader_CustName1_2" sort="auto" width="30%" label="${c:l('listheader_CustName1_2.label')}" />
<listheader id="listheader_CustCity_2" sort="auto" width="30%" label="${c:l('listheader_CustCity_2.label')}" />
</listhead>
</listbox>

  • ZK Search Button
<button id="btnSearch${tableClassName}" disabled="true" width="28px" image="/images/icons/btn_search2_16x16.gif" tooltiptext="${c:l('btn${tableClassName}ListBox.tooltiptext')}" />

  • ZK Simple Layout
<panel id="panel_${tableClassName}Dialog" title="${c:l('panel_${tableClassName}Dialog.title')}" style="margin-bottom:10px" border="normal" collapsible="true">
<panelchildren>
<grid fixedLayout="true" style="border:0px">
<columns>
<column width="150px" />
<column width="100%" />
</columns>
<rows>
<row>
:
:
</row>
</rows>
</grid>
</panelchildren>
</panel>

  • ZK Multi Columns Layout
<columnlayout>
<columnchildren width="50%">
<panel id="panel_${tableClassName}Dialog" title="${c:l('panel_${tableClassName}Dialog.title')}" style="margin-bottom:10px" border="normal" collapsible="true">
<panelchildren>
<grid fixedLayout="true" style="border:0px">
<columns>
<column width="120px" />
<column width="100%" />
</columns>
<rows>
<row>
:
:
</row>
</rows>
</grid>
</panelchildren>
</panel>
</columnchildren>
<columnchildren width="50%">
<panel>
<panelchildren>
<grid fixedLayout="true" style="border:0px">
<columns>
<column width="120px" />
<column width="100%" />
</columns>
<rows>
<row>
:
:
</row>
</rows> </grid>
</panelchildren>
</panel>
</columnchildren>
</columnlayout>

  • ZK Tab
<tabbox id="tabBox${tableClassName}" width="100%">
<tabs>
<!—Use the following design patterns to define the tab
<tab id="tab${tableClassName}${columnVar}" label="${c:l('tab${tableClassName}Dialog${columnVar}.label')}" />
-->
</tabs>
<tabpanels>

<! --
<tabpanel id="tabPanel${tableClassName}${columnVar}" height="100%"
style="border: 0px; padding: 0px">

</tabpanel>
-->

</tabpanels>
</tabbox>

  • ZK Master Detail Layout
<panel id="panel_${tableClassName}Dialog" title="${c:l('panel_${tableClassName}Dialog.title')}" style="margin-bottom:10px" border="normal">
<panelchildren>
<grid fixedLayout="true" style="border:0px">
<columns>
<column width="150px" />
<column width="100%" />
</columns>
<rows>
<row>
:
:
</row>
</rows>
</grid>
</panelchildren>
</panel>
<hbox width="100%">
<vbox width="100%">
<div>
<panel id="panel_${tableClassName} Dialog_${childTableClassName}" title="${c:l('panel_${tableClassName}Dialog${childTableClassName}s.title')}" border="none" />
<toolbar>
<button id="button_${tableClassName}Dialog_New${childTableClassName} "
image="/images/icons/btn_new2_16x16.gif"
label="${c:l('button_${tableClassName}Dialog_New${childTableClassName}.label')}"
tooltiptext="${c:l('button${tableClassName}Dialog_New${childTableClassName}.tooltiptext')}" />
</toolbar>
<paging id="paging_ListBox${tableClassName}${childTableClassName}" pageSize="20" />
<listbox id="listBox${tableClassName}${childTableClassName}s" tooltiptext="${c:l('listbox.tooltiptext')}" width="100%" height="100%" multiple="false">
<listhead sizable="true">
<listheader
:
:
</listhead>
</listbox>
</div>
</vbox>
</hbox>

  • ZK Detail of Master Detail Layout
<hbox width="100%">
<vbox width="100%">
<div>
<panel id="panel_${tableClassName} Dialog_${childTableClassName}" title="${c:l('panel_${tableClassName}Dialog${childTableClassName}s.title')}" border="none" />
<toolbar>
<button id="button_${tableClassName}Dialog_New${childTableClassName} "
image="/images/icons/btn_new2_16x16.gif"
label="${c:l('button_${tableClassName}Dialog_New${childTableClassName}.label')}"
tooltiptext="${c:l('button${tableClassName}Dialog_New${childTableClassName}.tooltiptext')}" />
</toolbar>
<paging id="paging_ListBox${tableClassName}${childTableClassName}" pageSize="20" />
<listbox id="listBox${tableClassName}${childTableClassName}s" tooltiptext="${c:l('listbox.tooltiptext')}" width="100%" height="100%" multiple="false">
<listhead sizable="true">
<listheader
:
:
</listhead>
</listbox>
</div>
</vbox>
</hbox>

  • ZK - Zul Dialog Page
<?xml version="1.0" encoding="UTF-8"?>
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>

<zk xmlns="http://www.zkoss.org/2005/zul"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">

<window id="window_${tableClassName}sDialog"
title="${c:l('window_${tableClassName}sDialog.title')}" border="none"
sizable="true" apply="${${tableVariableName}DialogCtrl}" closable="true"
width="500px" height="320px">

<style>
body { padding: 0 0; /* 0 padding on top and bottom and 0
padding on right and left */ }
</style>

<borderlayout id="borderlayout${tableClassName}Dialog">

<north border="none" margins="0,0,0,0">
<grid>
<columns sizable="true" height="20px">
<!-- Help Button -->
<column width="40px" align="left">
<hbox>
<button id="btnHelp"
image="/images/icons/light_16x16.gif"
tooltiptext="${c:l('btnHelp.tooltiptext')}" />
</hbox>
</column>

<!-- Addtionally Buttons -->
<column align="center">
<hbox>

</hbox>
</column>

<!-- CRUD Buttons -->
<column align="right">
<hbox spacing="5px" style="padding:1px"
align="end">
<button id="btnNew" height="20"
tooltiptext="${c:l('btnNew.tooltiptext')}" />
<!-- label="${c:l('btnNew.label')}" -->
<button id="btnEdit" height="20"
tooltiptext="${c:l('btnEdit.tooltiptext')}" />
<button id="btnDelete" height="20"
tooltiptext="${c:l('btnDelete.tooltiptext')}" />
<button id="btnSave" height="20"
tooltiptext="${c:l('btnSave.tooltiptext')}" />
<button id="btnCancel" height="20"
tooltiptext="${c:l('btnCancel.tooltiptext')}" />
<button id="btnClose" height="20"
tooltiptext="${c:l('btnClose.tooltiptext')}" />
</hbox>

</column>
</columns>
</grid>
</north>


<center border="none" margins="0,0,0,0">
<div id="divCenter${tableClassName}">
//TODO add your input components here

</div>
</center>

<east border="none"></east>
<west border="none"></west>
<south border="none"></south>

</borderlayout>

</window>

</zk>

  • ZK - Zul Listing Page
<?xml version="1.0" encoding="UTF-8" ?>
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>

<zk xmlns="http://www.zkoss.org/2005/zul"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd">

<window id="window_${tableClassName}sList" apply="${${tableVariableName}ListCtrl}"
border="none" width="100%">

<style>
body { padding: 0 0; /* 0 padding on top and bottom and 0
padding on right and left */ }
</style>

<panel id="panel${ tableClassName}List"
title="${c:l('panel${ tableClassName}List.title')}" border="none" />

<toolbar>
<button id="btnHelp" image="/images/icons/light_16x16.gif"
tooltiptext="${c:l('btnHelp.tooltiptext')}" />
<button id="btnRefresh"
image="/images/icons/refresh2_yellow_16x16.gif"
tooltiptext="${c:l('btnRefresh.tooltiptext')}" />
<separator orient="vertical" />
<button id="button_${ tableClassName}List_New${ tableClassName}"
image="/images/icons/btn_new2_16x16.gif"
tooltiptext="${c:l('button_${ tableClassName}List_New${ tableClassName}.tooltiptext')}" />
<button id="button_${ tableClassName}List_PrintList"
image="/images/icons/btn_print2_16x16.gif"
tooltiptext="${c:l('button_${ tableClassName}List_PrintList.tooltiptext')}" />
</toolbar>

<hbox style="padding: 3px">
<space />
<checkbox id="checkbox_${ tableClassName}List_ShowAll"
label="${c:l('checkbox_${ tableClassName}List_ShowAll.label')}" />
<separator bar="true" orient="vertical" />

<!-- TODO Use the following design pattern to add Search functions
<label id="label_${ tableClassName}List_${columnVar}
value="${c:l('label_${ tableClassName}List_${columnVar}value')}" />
<textbox id="tb_${ tableClassName}${columnVar}width="120px" />
<button id="button${ tableClassName}List_Search${columnVar}
image="/images/icons/search.gif"
label="${c:l('button${ tableClassName}List_Search${columnVar}label')}"
tooltiptext="${c:l('button${ tableClassName}List_Search${columnVar}tooltiptext')}" />
<separator bar="true" orient="vertical" />

-->
</hbox>

<borderlayout id="borderLayout_${tableVariableName}List">

<north border="none" height="26px">
<paging id="paging_${ tableClassName}List" />
</north>


<center border="normal">

<listbox id="listBox${ tableClassName}vflex="true"
tooltiptext="${c:l('listbox.tooltiptext')}" width="99.9%"
height="100%" multiple="false">
<listhead sizable="true">

<!-- TODO use the following design pattern to define your listing header
<listheader id="listheader_${ tableClassName}List_${columnVar}
image="/images/icons/variable_tab.gif"
label="${c:l('listheader_${ tableClassName}List_${columnVar}label')}" sort="auto"
width="<percentage>" />
-->
</listhead>
</listbox>

</center>
<!—You only use this section if you want to have special display of data at the bottom of page

<south border="none">

<grid fixedLayout="true" style="border:0px">
<columns>
<column width="20%" />
<column width="80%" />
</columns>
<rows>
<row>
//TODO replace with the relevant field name
<label
id="label_${ tableClassName}List_${columnVar}
value="${c:l('label_${ tableClassName}List_${columnVar}value')}" />
<textbox id="longBox${ tableClassName}${ tableClassName}${columnVar}"
width="99%" multiline="true" rows="3" />
</row>
</rows>
</grid>

</south>
-->

</borderlayout>


</window>
</zk>

  • ZK - Zul Listing Page – Master Detail
<?xml version="1.0" encoding="UTF-8" ?>
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>

<zk xmlns="http://www.zkoss.org/2005/zul"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.zkoss.org/2005/zul
http://www.zkoss.org/2005/zul/zul.xsd">


<window id="${ tableVariableName}ListWindow" apply="${${ tableVariableName}ListCtrl}" border="none"
width="100%">

<style>
body { padding: 0 0; /* 0 padding on top and bottom and 0
padding on right and left */ }

div.z-list-footer-cnt { font-weight: bold;}
</style>

<panel id="panel${ tableClassName}List"
title="${c:l('panel${ tableClassName}List.title')}" border="none" />

<toolbar>
<button id="btnHelp" image="/images/icons/light_16x16.gif"
tooltiptext="${c:l('btnHelp.tooltiptext')}" />
<button id="btnRefresh"
image="/images/icons/refresh2_yellow_16x16.gif"
tooltiptext="${c:l('btnRefresh.tooltiptext')}" />
<separator orient="vertical" />
<button id="button_${ tableClassName}List_New${ tableClassName}"
image="/images/icons/btn_new2_16x16.gif"
tooltiptext="${c:l('button_${ tableClassName}List_New${ tableClassName}.tooltiptext')}" />
</toolbar>
<!--
label="${c:l('button_${ tableClassName}List_New${ tableClassName}.label')}"
-->

<hbox style="padding: 3px">
<!-- Use this section to add search functions -->
<hbox id="hBox${linkedTableClassName}Search">
<label id="label_${tableClassName}List_${linkedTableClassName}"
value="${c:l('label_${tableClassName}List_${linkedTableClassName}.value')}" />


<bandbox id="bandbox_${tableClassName}List_${linkedTableClassName}Search"
width="250px"
tooltiptext="${c:l('bandbox_${tableClassName}List_${linkedTtableClassName}Search.tooltiptext')}">
<bandpopup id="bpop_${tableClassName}s_${linkedTableClassName}Search"
width="540px" height="455px">
<panel id="panel_bbox${linkedTableClassName }Search"
title="${c:l('panel_bbox${linkedTableClassName}Search.title')}" />

<vbox>
<hbox width="100%">

<grid fixedLayout="true"
style="border:0px" width="100%">
<columns>
<column width="150px" />
<column width="250px" />
<column width="100px" />
<column width="40px" />
</columns>
<rows>

<!-- TODO Use the following design pattern to add the field you want to search on linked table <row>
<label
id="label_bbox${linkedTableClassName}Search_${linkedColumnClass}"
value="${c:l('label_bbox${linkedTableClassName}Search_${linkedColumnClass}.value')}" />
<textbox
id="tb_Orders_SearchCustNo" width="99%" />
<button
id="button_bbox_${linkedTableClassName}Search_Search"
image="/images/icons/search.gif"
label="${c:l('button_bbox_${linkedTableClassName}Search_Search.label')}"
tooltiptext="${c:l('button_bbox_${linkedTableClassName}Search_Search.tooltiptext')}" />
<button
id="button_bbox_${linkedTableClassName}Search_Close"
image="/images/icons/stop.gif"
tooltiptext="${c:l('button_bbox_${linkedTableClassName}Search_Close.tooltiptext')}" />
</row>
-->

<row spans="4">
<vbox width="100%">
<paging
id="paging_${tableClassName}List_${linkedTableClassName}SearchList" pageSize="20" />
<listbox
id="listBox${linkedTableClassName}Search" width="99.9%" height="100%"
multiple="false">
<listhead
sizable="true">

<!-- TODO Use the following design pattern to add list header
<listheader
id="listheader_${linkedColumnClass} " image="/images/icons/builder.gif"
sort="auto" width="15%"
label="${c:l('listheader_${linkedColumnClass}.label')}" />
-->
</listbox>
</vbox>
</row>

</rows>
</grid>

</hbox>
</vbox>
</bandpopup>
</bandbox>

<separator bar="true" orient="vertical" />
</hbox>

<!- - TODO Use the following design pattern to add the field you want to search on the main table
<label id="label_${tableClassName}List_Search${columnVar}"
value="${c:l('label_${tableClassName}List_Search${columnVar}.value')}" />
<textbox id="tb_${tableClassName}s_${tableClassName}" width="120px" />
<button id="button_${tableClassName}List_${columnVar}Search"
image="/images/icons/search.gif"
label="${c:l('button_${tableClassName}List_${columnVar}Search.label')}"
tooltiptext="${c:l('button_${tableClassName}List_${columnVar}Search.tooltiptext')}" />
<separator bar="true" orient="vertical" />
-->
</hbox>

<paging id="paging_${tableClassName}List" />
<listbox id="listBox${tableClassName}"
tooltiptext="${c:l('listbox.tooltiptext')}" width="99.9%"
multiple="false">
<listhead sizable="true">
<!- - Use the following design pattern to add list header for the search data to be displayed
<listheader id="listheader_${tableClassName}"List_${columnVar}"
image="/images/icons/builder.gif" sort="auto" width="40%"
label="${c:l('listheader_${tableClassName}"List_${columnVar}".label')}" />

</listbox>

<separator />
-- >
<panel id="panel_${tableClassName}List_${childTableClassName}s"
title="${c:l('panel_${tableClassName}List_${childTableClassName}s.title')}"
border="none">
<panelchildren>

<borderlayout id="borderLayout_ListBox${tableClassName}Article"
height="250px">

<north border="none" height="26px">
<paging id="paging_${tableClassName}ArticleList" />
</north>

<center border="normal">

<listbox id="listBox${tableClassName}Article" vflex="true"
height="100%" width="100%" multiple="false">
<listhead sizable="true">

<!-- TODO Use the following design pattern to add list header for child table
<listheader
id="listheader_${childTableClassName}List_ ${childColumnClass}"
image="/images/icons/builder.gif" sort="auto" width="10%"
label="${c:l('listheader_${childTableClassName}List_${childColumnClass}".label')}" />
-->
</listhead>

<listfoot>
<!-- TODO Use the following design pattern to add list footer for child table

<listfooter
id="listfooter_${childTableClassName}List__${childColumnClass}" width="10%"
label="${c:l('message_Sum')}" style="font-weight:bold" />
-->
</listfoot>
</listbox>

</center>

<south border="none">
<separator />
</south>

</borderlayout>

</panelchildren>
</panel>



</window>
</zk>


<!--
<style dynamic="true">
.mybandbox .z-bandbox-img { background: transparent
url(${c:encodeURL('~./zul/img/button/bandbtn.gif')})
no-repeat 0 0; border: 1px solid #C0C0C0 ;
vertical-align: top: cursor: pointer: width: 19px;
height: 19px ;}
</style>
-->

The Challenge
Now I want to convert a complex GUI of a Drug Entry Screen as shown in Fig.1 to a new RIA based web page as shown in Fig. 2.
Fig1. Drug Entry Screen

Fig 2. Drug Entry Screen based on zk-sample2 layout.

The steps involved in creating the Drug Entry Screen is as follows:
1) Create a zul page.
2) Copy and paste the design pattern of ZK- Zul Dialog Page
3) Copy and paste the design pattern of ZK Multi Column Layout into
<center border="none" margins="0,0,0,0">
<div id="divCenter${tableClassName}">
<!--
paste the design pattern of ZK Multi Column Layout here
-->
</div>
</center>
4) Add the following code to the ZK Multi Column Layout design pattern to make it a 3 columns layout

<columnchildren width="50%">
<panel>
<panelchildren>
<grid fixedLayout="true" style="border:0px">
<columns>
<column width="120px" />
<column width="100%" />
</columns>
<rows>
<row>
:
:
</row>
</rows> </grid>
</panelchildren>
</panel>
</columnchildren>

5) Repeat step 3 and 4
6) Repeat step 3 and 4
7) Copy and paste the design pattern of ZK Tab after the last </columnlayout>
8) Copy and paste the design pattern of Detail of Master Detail Layout into the first <tabpanel>

From the above steps you can see the layout of a web page only involved copy and paste of the relevant patterns until you get the final product, no drag and drop or trivial and tedious html programming. For a complex GUI that took 2 to 4 weeks, now I can do it in less than a day, a tremendous improvement in productivity.
If you use Velocity Template Language to name the variable in your design patterns, you can further increase your productivity, by converting the final product into a template for a velocity based code generator.

ZK framework is a framework that worth the investment, the ROI is beyond your imagination which you will only realize when you explore further.
Now I can turn the company I worked for into a highly efficient and reliable software production factory ;-)



References:
1. Zk-sample2 is a ZK based sample application with all the best features to kick starts your ZK based application. The demo is available at http://zk-web.de/zksample2/

1 comment:

  1. thanks for the nice words about Zksample2.

    For more ideas have a look here:
    http://www.zk-web.de/opentruuls/

    Most of the sources will be available soon.

    best
    Stephan (TerryTornado)

    ReplyDelete