读书人

ZK 学习小结

发布时间: 2012-12-24 10:43:13 作者: rapoo

ZK 学习总结

?

ZK 学习总结

?

目? 录

1 了解ZK?1
1.1 理解ZK?1
1.2 ZK特点?1
2 ZK环境搭建?3
2.1安装环境前,需要下载的东西:?3
2.2安装过程?3
2.3 第一个用Eclipse创建的ZK项目:Hello World?7
2.4例子中的配置分析?12
3 组件基础属性及事件?15
3.1 ID属性?15
3.2 IF和unless属性?16
3.3 use和apply属性?16
3.4 forEach属性?20
3.5 事件处理?20
4 组件属性及重要函数?28
4.1 标签组件?28
4.2 按钮组件?30
4.3 日历组件?31
4.4 图像组件?32
4.5 窗口?34
4.6 布局组件?39
4.7 标签页?44
4.8 网格?48
4.9 菜单?56
4.10 列表框?59
4.11 树形组件?64
5 应用示例?71
5.1 功能简介?71
5.2 建立项目环境?71
5.3 登陆功能?72
5.4 权限判断?73
5.5 页面布局实现?74
5.6 权限管理实现?75
5.7 信息中心模块?77
5.8 示例配置代码?79
?
1 了解ZK
1.1 理解ZK
ZK官方网站及<<ZK开发手册>>中有关于ZK的定义:“ZK是一个事件驱动(event-driven)的,基于组件(component-based)的,用以丰富网络程序中用户界面的框架。ZK包括一个基于AJAX事件驱动的引擎(engine),一套丰富的XUL和XHTML,以及一种被称为ZUML(ZK User Interface Markup Language,ZK用户界面标记语言)的标记语言”。
通过这么一段时间的接触,体验到ZK是C/S构架在WEB应用中的实现。写过C/S程序的同学应该能够理解C/S构架特点,如C++,.NET等语言的应用程序构架,以上语言在编写C/S构架程序的时候都是基于各个组件的应用,如窗口、按钮、列表等,用面向对象的语言来说,C/S程序是由各个可视化的对象组成的。
最简单的程序需要有以下几个步骤,第一,编写前台数据输入页面,然后编写后台处理数据的代码,最后编写数据处理的结果的页面。以上的3个步骤在B/S框架中通常是独立分开的,而目前ZK框架则将三者能够绑定在一起,在一个ZK得页面中完成。像桌面程序一样,每个显示页面关联一个后台程序,页面中元素值及属性在后台程序中均能够随时得到,后台程序也能够控制页面元素。
?ZK是基于组件的,每个组件都有对应的HTML页面显示,又会对应一个JAVA 对象。于是用户可以通过后台程序中对组件JAVA对象的处理来更新页面的HTML显示,而页面中元素的从属关系则体现在Java中的List类,每个组件都能够获得属于其中的元素列表(List)。
1.2 ZK特点
通过这么一小段时间的ZK学习与应用,总结一点我认为特点与体会。
1.组件多样,能够轻松完成普通web程序很难完成的树、图表、页面局部动态变换、标签页、分页网格等功能,是实现富客户端应用的良好工具。
2.开发模式简单,只需要掌握各个组件应用变可以轻松完成应用开发。
但利用ZK开发还有些缺点的地方
1.学习资料较少,只有官方网站中的例子,且例子均是局部功能,没有完整的WEB项目参考。这样就不能了解类包及页面如何分配等相关知识,如目前比较缺少在ZK中通用的对数据库进行增删改查的例子,打开2个window间数据传递等功能。
2.感觉网格不是很好用,网格中的一行可以显示一条数据,但如何通过一行直接获得绑定的数据?还是事件处理部分,事件处理是一个组件的特定函数,即一个类的函数,而函数中处理数据经常需要其他组件的数据,如何获得其他组件数据?唯一的方法似乎是事件监听类为组件的内部类。
3.版本问题,目前ZK最新式5.0,其中官网中的DEMO均是此版本的,而其他的DEMO及Eclipse的插件均是3.6版本的ZK,导致从例子中学习的一些程序代码在其他环境中运行出错。
4.编译源码问题,由于功能需要,需要对项目源代码进行重新编译,但ZK的编译需要在Linux或模拟Linux环境下运行,不是很方便,目前还没掌握。
?
2 ZK环境搭建
2.1安装环境前,需要下载的东西:
作为一个基于 java 的 web framework,再使用 ZK 之前,需要成功安装 JDK 和 tomcat5.5 或者更高的版本,所以要提前下载的东西为:
①下载JDK(Java SE)安装包;
②下载Tomcat安装包;
③下载Eclipse IDE 软件开发工具安装包,我们项目组目前Eclipse环境为3.4;
④下载ZK Library;
⑤下载ZK Studio
对于ZK Library可以再http://www.zkoss.org/download/zk.dsp下载,ZK Studio插件可以在http://www.zkoss.org/product/zkstudio.dsp下载。
2.2安装过程
2.2.1安装Java运行环境
Java运行环境(Jre)是运行ZK的基础,也是运行servelet容器必需的。Jre可以登录SUN的官方网站(http:// java.sun.com)中下载到本地机器。安装之后需要配置环境变量。
2.2.2 安装Servlet容器
Apache Tomcat是当前广为流行的Servlet容器之一,安装简单,使用方便,可以使用官方网站提供的两种安装方法。第一种使用Installer包安装,第二种是快速安装方法,是Tomcat提供的一个.ZIP文件。第二种具体操作过程是:首先,可已访问官方网站下载.zip文件;其次,将文件解压到本地机器;然后装tomcat,装完后启动tomcat测试是否可以正常运行,以便查看环境变量测试的是否正确(默认端口是8080)。在地址栏直接键入http:/localhost:8080/或者输入http://127.0.0.1:8080。
2.2.3安装Eclipse
可以到www.eclipse.org下载eclipse,可以选择: Download now 下载完成后,只需要将下载的压缩文件eclipse-SDK-3.4-in32.zip解压到指定位置,例如D:\Eclipse即可完成安装。记下来就可以。安装后,会弹出一个画面选择工作空间,自己指定一个就可以。
2.2.4安装插件
通过自己在Eclipse下安装ZK插件的学习体会,总结了在Eclipse下安装插件主要有三种方式,我认为第三种方式比较好(推荐),具体的安装过程如下:
第一种方法:主要借助于Eclipse的向导来安装插件。通过Help/Software Updates/Find and Install,在弹出的菜单中选择“Search for new features to install”,点“Next”,在下一菜单中选择“New Local Site”或“New Archived Site”,找到你下载的插件所在目录,选中安装即可。
第二种方法:在Eclipse的主目录(%ECLIPSE_HOME%)下有一个plugins目录和features目录。将插件解压缩后,在解压缩后的文件夹里一般可以看到plugins文件夹,有的插件解压缩后还可以看到一个features文件夹。一般将plugins文件夹下的内容直接拷贝到%ECLIPSE_HOME%\plugins目录下,如果解压缩后的插件目录下还有features文件夹,则把该文件夹下的内容也拷贝到%ECLIPSE_HOME%\features下。重新启动Eclipse之后就可以使用刚刚安装的插件了。
第三种方式:就是在Eclipse主目录下创建一个links目录,然后将你自己的插件放在你想放的任何地方,这个时候你放插件的目录就是插件目录(%PLUGIN_HOME%),然后在你的%ECLIPSE_HOME%\links\目录下创建一个link文件,比如要安装一个 Lomboz插件,可以在links目录下创建一个Lomboz.eclipse.link文件,link文件的名称随便取。这个Lomboz.eclipse.link文件指向的存放Lomboz插件的目录(%PLUGIN_HOME%)。假如你的Lomboz插件的zip/rar文件解压缩后放在C:\eclipse_plugins\Lomboz.eclipse下(如果是插件是jar文件则可以不用解压缩),则Lomboz.eclipse.link文件的内容就应该是:path=C:\\eclipse_plugins\\Lomboz.eclipse。注意:path所指的文件路径一定要增加一个“\”转义符来分开。
其余插件的安装也是如此,比如安装Eclipse多国语言包,通过安装Eclipse多国语言包,Eclipse可以自动实现开发环境的本地化,即自动根据操作系统的语言环境选择语言包进行本地化,先到http://download.eclipse.org/eclipse/downloads/下载Eclipse3.2版本的多国语言包,其名称为Language pack。按照前面的第三种方式安装即可。
2.2.5 配置ZK环境(ZK库)
1.打开Eclipse(前提条件是已经安装好了ZK studio插件),如果没有安装,请先按照前面的介绍安装插件;
?2.点击菜单Window->Preferences(From menu goto Windows > Preferences );
3.在打开的这个窗口上选择ZK->ZK Packages(On the Preferences Window, select ZK > ZK Packages);
4.点击Add Diretory 选择到你下载的ZK Library包,不用解压,直接是ZIP文件,如下图:
??????
5.会跳出一个窗口来,点击OK
?
6.给这个包命名,一般就用默认的,点击OK;
?
7.再选择上那个ZK Library就行了,如果你不选择,会自动选择最后你引入的版本的。到此,ZK的环境就配置完了。
2.3 第一个用Eclipse创建的ZK项目:Hello World
2.3.1 创建项目过程
1.启动Eclipse,我倾向于在Java EE 下创建项目
2.如果没有建立Server的话,需要先打开Window-》show view -> other…->servers ?右击选择New ->Server,然后选择tomcat即可;
?
3.选择File->New->Dynamic Web Project,输入项目名称,例如我给项目其名字为MyZK;?
4.点Next,再点Finish就完成了一个ZK项目的创建;
?
5.右击项目名称,选择properties----》Java BuidPath给项目导入ZK的Jar包,将%ZK_HOME%\dist\lib目录下的所有jar文件(如果需要更多ZK附加功能,加入ext与zkforge目录下的jar文件)到WebContent\WEB-INF\lib目录下。
?
6.创建一个新的ZUL文件(Creating a new ZUL file):helloworld;
?
7.创建完.zul文件后,写入ZK代码;
8.启动Tomcat服务器,选择MyZK,运行;
?
9.在浏览器里输入:http://localhost:8080/MyZK/first.zul,就可以看到下面的内容。
?

2.4例子中的配置分析
2.4.1项目目录结构
在Eclipse下搭建的ZK环境上开发的程序,比如对于上面的例子项目MyZK,其目录结构如下所示:
?
下面对于上面的目录中的文件,我通过查找资料,进行了总结,对于Zk的配置文件大体的意思是:
①WEB-INF/web.xml 定义了必须的servlet,及运行ZK应用程序所需要的监听器;
②WEB-INF/zk.xml为ZK的配置描述文件;
③WEB-INF/lib 包括了ZK的必须库文件;
④该应用程序所需的重要jar包文件说明:
. bsh.jar: BeanShell Java 代码解释器
. commons-el.jar: Apache的EL表达式解释器
. zcommon.jar : ZK的通用库
. zhtml.jar: XHTML 相关组件
. zk.jar : ZK核心代码
. zkplus.jar :与Acegi Security, Spring, Hibernate,和data binding集成的代码
. zul.jar :XML相关组件
. zweb.jar:web相关功能代码
2.4.2关于web.xml的配置
在web.xml中为ZK定义必须的servlet ,及listener,我把在该项目MyZK下的web.xml文件中的代码拷贝如下:
?<display-name>MyZK</display-name>
?<listener>
??? <description>
???????????? Used to cleanup when a session is destroyed
</description>
??? <display-name>
??????????? ZK Session cleaner
</display-name>
??<listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
?</listener>
?<servlet>
??? <description>
??????????? The ZK loader for ZUML pages
</description>
?? <servlet-name>zkLoader</servlet-name>
?? <servlet-class>
??????????? org.zkoss.zk.ui.http.DHtmlLayoutServlet
</servlet-class>
?? <init-param>
????? <param-name>update-uri</param-name>
????? <param-value>/zkau</param-value>
??</init-param>
?????? <load-on-startup>1</load-on-startup>
?</servlet>
?<servlet>
??? <description>
???????? The asynchronous update engine for ZK
</description>
???? <servlet-name>auEngine
</servlet-name>
???? <servlet-class>
???????? org.zkoss.zk.au.http.DHtmlUpdateServlet
</servlet-class>
?</servlet>
?<servlet>
???? <description>
???? </description>
???? <display-name>
??????????????? LoginServlet
</display-name>
???? <servlet-name>
LoginServlet
</servlet-name>
???? <servlet-class>
????????????? servlet.LoginServlet
</servlet-class>
?</servlet>
?<servlet-mapping>
???? <servlet-name>zkLoader</servlet-name>
???? <url-pattern>*.zul</url-pattern>
?</servlet-mapping>
?<servlet-mapping>
???? <servlet-name>zkLoader</servlet-name>
???? <url-pattern>*.zhtml</url-pattern>
?</servlet-mapping>
?<servlet-mapping>
???? <servlet-name>auEngine</servlet-name>
????? <url-pattern>/zkau/*</url-pattern>
?</servlet-mapping>
?<servlet-mapping>
???? <servlet-name>LoginServlet</servlet-name>
???? <url-pattern>/userlogin</url-pattern>
?</servlet-mapping>
?<welcome-file-list>
???? <welcome-file>index.html</welcome-file>
???? <welcome-file>index.htm</welcome-file>
???? <welcome-file>index.jsp</welcome-file>
???? <welcome-file>default.html</welcome-file>
???? <welcome-file>default.htm</welcome-file>
???? <welcome-file>default.jsp</welcome-file>
???? <welcome-file>index.zul</welcome-file>
?</welcome-file-list>
2.4.3关于zk.xml的配置
.xml文件是对ZK配置的描述性文件,我把在该项目MyZK下的zk.xml文件中的代码拷贝如下:
<?xml version="1.0" encoding="UTF-8"?>
<!--
?????????? Created by ZK Studio
-->
<zk>
?<device-config>
??<device-type>ajax</device-type>
??<timeout-uri>/timeout.zul</timeout-uri>
<!-- An empty URL can cause the browser to reload the same URL -->
?</device-config>
</zk>
3 组件基础属性及事件
3.1 ID属性
为了读取 Java 代码或EL 表达式中的组件,我们可以使用id 属性来标识它。在下面的例子中,我们为label 设置了一个标识,这样当一个按钮被按下时,我们就可以操纵label 的值了。如下面两个例子可以让你领会id的作用
<?page title="test use id" contentType="text/html;charset=UTF-8"?>
<window title="Press the below Button!" border="normal">
??? Do you like ZK?
??? <label id="label" />
??? <separator />
??? <button label="Yes" onClick="label.value = self.label" />
??? <button label="No" onClick="label.value = self.label" />
</window>
当按下“Yes”按钮的时候,可以看到如下效果。
?

id属性在EL表达式中的应用,如下代码:
?<textbox id="source" value="ABC" />
?<label value="${source.value}" />
这段代码实现的是将文本框中的值赋给标签,“source”就代表着文本框,我们只需对其进行操作就相当于对文本框操作了。

3.2 IF和unless属性
if 和unless 属性被用于控制是否创建一个组件,在下面的例子中,两个label只有在请求中含有一个为vote 的属性时才被创建:
<label value="Vote 1" if="${param.vote}"/>
<label value="Vote 2" unless="${!param.vote}"/>
如果两个属性都被指定,将不会创建组件除非它们的值都被赋值为true。
3.3 use和apply属性
在页面中嵌入代码不当会增加维护的难度,有两种途径可以从视图中分离出代码。
一种途径是你可以监听所关心的事件,然后调用合适的方法进行处理。例如,可以调用
onCreate, onOK, onCancel事件来完成初始化(initialize),处理(process)和取消(cancel)等工作。
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<window id="main" onCreate="MyManager.init(main)"
?onOK="MyManager.process(main)" onCancel="MyManager.cancel(main)">
<button label="OK" onClick="MyManager.save(main)"/>
<button label="Cancel" onClick="MyManager.cancel(main)"/>
</window>
另外,必须有一个名称为MyManager 的Java 类,内容像下面一样:
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

public class MyManager {
?public static void init(Window main) {
??main.setTitle("关注我的请求!");
?}

?public static void save(Window main) throws InterruptedException {
??main.setTitle("save......");
??Messagebox.show("您的信息已经保存!");
?}

?public static void cancel(Window main) throws InterruptedException {
??main.setTitle("cancel......");
??Messagebox.show("你取消的请求已经完成!");
?}
}
按下“save”按钮的时候,程序运行的效果如下:
?
但是,上面的方法需要你在ZUML页面内嵌入一些代码。在用户界面(UI)内嵌入代码的优点是可以很容易的动态改变行为(特别是在原型阶段),但是这仍然会展现一些维护代码且性能会有一些降低。于是引出了use和apply属性的使用。
3.3.1 use 属性
若不想在 ZUML 页面内使用Java 代码,你可以继承一个组件的实现来处理事件,如下。
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Window;

public class MyWindow extends Window {

?public void onCreate() {
??this.setTitle("关注我的变化!");
?}

?public void onSave() {
??this.setTitle("save......");??
?}

?public void onCancel() {
??this.setTitle("cancel......");
?}
}
然后,使用use 属性指定类,如下。
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<window use="MyWindow" onClick='alert(" MyWindow is used!")' >
</window>
执行效果如下:
?
3.3.2 apply 属性
若你喜欢使用MVC(模型-试图-控制者)方法,例如,你不想在window(视图)内嵌入处理代码,可以实现一个类来初始化window。这个类必须实现org.zkoss.zk.ui.util.Composer 接口。
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.util.Composer;
import org.zkoss.zul.Window;

public class MyComposer implements Composer {

?public void doAfterCompose(Component comp) throws Exception {
??((Window) comp).setTitle("Apply can be used as this!");
????????? // do whatever initialization you want
?}
}
在这里我们假设你有三个监听器, MyCreate,MyOK,和 MyCancel。参考下面的事件章节获取事件监听器的解释。然后,使用 apply 属性指定类,如下。
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<zk>
?<window apply="MyComposer">
??<button label="apply" onClick='alert("Are you clear?")' />
?</window>
</zk>
按下apply按钮,程序执行效果如下:
?
window 仍然作为org.zkoss.zul.Window 的一个实例被创建,且作为comp 参数被传递给doAfterCompose 方法。然后,你可以处理你所希望的初始化。若你想apply 多个composer,使用逗号隔开。另外,你可以使用EL 表达式来返回类,它的名称,Composer 实例,或Composer 实例的集合。示意的代码如下:
<window apply="MyComposer, AnotherComposer">
<textbox apply="${c:mycomposer()}"/>
</window>
3.3.3 与 forward 属性一起使用
window 通常由一些按钮,菜单项目和其他组件组成。例如,
<window use="MyWindow">
<button label="OK"/>
<button label="Cancel"/>
</window>
当用户点击按钮时,onClick 事件会被送至按钮本身。但是这些事件最好在window内处理而不是散落这些按钮。为了这样,你可以按如下方式使用forward 属性。
<window use="MyWindow">
...
<button label="OK" forward="onOK"/>
<button label="Cancel" forward="onCancel"/>
</window>
在这里OK 按钮的forward 属性指定接收onClick 事件后将其作为onOK 事件转向空间所有者(例如,window)。同样,针对Cancel 按钮的onClick 事件会转向onCancel 事件。因此你可以在MyWindow 命名空间内处理onOK 和onCancel事件,如下。
public class MyWindow extends Window {
public void onOK() {
//called when the OK button is clicked (or the ENTER buttonis pressed)
}
public void onCancel() {
//called when the Cancel button is clicked (or the ESC button
is pressed)
}
}
除了将onClick 事件forward 至空间所有者,你可以使用forward 属性将任何事件forward 至任何组件。
3.4 forEach属性
forEach 属性用来控制要创建多少个组件,如果你为这个对象指定一个对象集合,ZK 装载机(ZK loader)将为每个被指定的集合项目创建一个组件。在下面的ZUML 页面中,listitem 元素将被赋值三次(分别为"Monday", "Tuesday" 和"Wednesday"),然后产生三个list 项目。
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<window id="win" title="a example foreach" border="normal">
?<zscript>
?contacts = new String[] { "Monday", "Tuesday", "Wednesday", "Thursday",
???"Friday", "Saturday", "Sunday" };
</zscript>
?<listbox width="100px" height="50px">
??<listitem label="${each}" forEach="${contacts}"
???draggable="true" />
?</listbox>
</window>
代码运行的效果如下:
?
除了使用foreach,还可以通过forEachBegin 和forEachEnd 来控制迭代(iteration)。
3.5 事件处理
事件(org.zkoss.zk.ui.event.Event)用来通知服务器发生了什么。每种类型的事件都由一种不同的类来表示。例如,org.zkoss.zk.ui.event.MouseEvent 来代表鼠标活动,如点击。为了响应事件,服务器需要为其注册一个或多个事件监听器。由两种方法来注册一个事件监听器。一种是通过在标记语言中指定onXxx 属性。另一种方法是为你要监听的组件或页面调用addEventListener 方法。
除了在浏览器端由客户活动触发的事件,一个应用程序可以使用org.zkoss.zk.ui.event.Events 类中的sendEvent 和postEvent 方法来触发事件。
3.5.1桌面和事件处理
如上所述,桌面是页面的集合,这些页面服务于同样的URL 请求。一个桌面当然是事件监听器能读取的范围。
当一个事件被触发时,它就和桌面联系在一起。ZK 分离基于关联桌面及流水事件(pipelines events)分成单独的队列。因此,同一桌面的事件可以被顺序处理。另一方面,不同桌面的事件可以被并行处理。
一个事件监听器是被允许读取事件关联桌面内任何页面的任何组件的。它也被允许将一个组件从一个页面移到另一个页面,只要这些页面在同一桌面内。另一方面,它不能读取到其它桌面的组件。
[注]: 开发人员可以在一个事件监听器中将一个组件从一个桌面卸载,然后在另外的事件监听器中将其添加到另外一个桌面。
3.5.1.1 桌面及创建组件
当一个组件在一个事件监听器中被创建时,它就自动被分配到被处理的事件相关联的桌面。即使组件不属于一个页面这种分配也会发生。这就意味着你在事件监听器中创建的任何组件可以用于监听正在处理的同一桌面。如果一个组件是在一个线程(thread)而不是任何事件监听器中创建的话,它就不属于任何桌面。在这种情况下,可以将它添加到任何一个桌面,只要添加发生在一个合适的监听程序中。当然,一旦组件被添加到一个桌面,它就一直属于这个桌面。对于大多数应用程序而言,很少在线程(thread)而不是事件监听器中创建组件。然而,如果有一个长操作(long operation),你或许会在后台线程(background thread)中执行它。那么,你可以在后台准备一些组件树,然后在合适的事件被接收时将它们添加到桌面。关于此的详细信息,参看事件监听与处理一节的详细介绍。
3.5.2 事件监听与处理
3.5.2.1通过标记语言添加事件监听器
添加一个事件监听器最简单的方法就是在一个ZUML 页面内声明一个属性。用来监听的属性的值是可以被BeanShell 解释的任何Java 代码。
<window title="Welcome you!" border="normal">
??<button label="say welcome"
???onClick=" alert(" Welcome your study!")">
??</button>
</window>
点击“say welcome”按钮,效果如下图所示:
?

3.5.2.2通过程序添加或移除事件监听器
有两种方法通过程序添加或移除事件监听器。
第一种 声明一个成员
当用你自己的类重定义(overriding)一个组件后,你可以声明一个成员函数成为事件监听器。在一个ZUML页面中,你可以使用use属性来指定你想使用的类,即用它去替换默认类。如下所示,它使用了MyWindow来替换默认的org.zkoss.zul.Window。
<window use="MyWindow">
</window>
然后你实现MyWindow.java 同过继承默认的类,就像下面一样:
public class MyWindow extends org.zkoss.zul.Window {
public void onOK() { //add an event listener
...//handles the onOK event (sent when ENTER is pressed)
}
}
如果你想获得关于事件的更多信息,你可以按如下方式声明:
public void onOK(org.zkoss.zk.ui.event.KeyEvent event) {
...
}
不同的事件或许与不同的事件对象相关联。
第二种 动态地添加与移除事件监听器
开发人员可以使用org.zkoss.zk.ui.Component 接口中的addEventListene 和removeEventListener 方法来动态地添加或移除事件监听器。如下所示,动态添加的事件监听器必须实现org.zkoss.zk.ui.event.EventListener 接口。
void init(Component comp) {
...
comp.addEventListener("onClick", new MyListener());
...
}
class MyListener implements org.zkoss.zk.ui.event.EventListener
{
public void onEvent(Event event) throws UiException {
...//processing the event
}
}
(1) 延期事件监听器
默认情况下,当客户端的事件被触发时就会被送到服务器。但是,许多事件仅用于维持服务器端的现状,而不是向客户端提供视觉响应(visual response)。换句话说,这些监听器的事件并不需要马上被送出。相反,它们应该仅被提交一次,以降低客户端和服务器端的来往,以提高服务器的性能。为求描述方便,我们称它们为延期事件监听器(Deferrable Event Listeners)。为了使一个事件监听延期,必须实现org.zkoss.zk.ui.event.Deferrable接口(和 EventListener)并且使用isDeferrable 方法返回true,就像下面一样。
public class DeferrableListener implements EventListener,
Deferrable {
private boolean _modified;
public void onEvent(Event event) {
_modified = true;
}
public boolean isDeferrable() {
return true;
}
}
当客户端的一个事件(例如,选择一个列表项目(list item))被触发时,如果没有为其注册事件监听器或仅有延期(deferrable)的监听器被注册,ZK 不会将事件送出。一方面,如果至少有一个非延期(non-deferrable)监听器,事件会被马上送到服务器端,和所有的队列事件(queued events)一起。没有事件会丢失,到达顺序是保存好的。
[提示]:当有非延期监听器为用户提供视觉响应,可以使用使用延期的(deferrable)事件监听器维持(maintaining)服务器状态。
(2) 为页面动态地添加和移除事件监听器
开发人员可以为页面(org.zkoss.zk.ui.Page)动态地添加和移除事件监听器。一旦被添加,所有被指定名字的事件会被送到指定页面的任何组件,这些页面将会被送到监听器。
所有的页面级(page-level)事件监听器都是非即时。换言之,isArap 方法被忽略了。
一个典型的例子是使用页面级事件监听器来维护修改标志(modification flag),如下:
import org.zkoss.web.servlet.dsp.action.Page;
import org.zkoss.zk.ui.event.Deferrable;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zul.Window;
import org.zkoss.zk.ui.*;

public class ModificationListener implements EventListener, Deferrable {

?private final Window _owner;
?private final Page _page;
?private boolean _modified;

?public ModificationListener(Window owner) {
??// Note: we have to remember the page because unregister might
??// be called after the owner is detached
??_owner = owner;
??_page = (Page) owner.getPage();
??((org.zkoss.zk.ui.Page) _page).addEventListener("onChange", this);
??((org.zkoss.zk.ui.Page) _page).addEventListener("onSelect", this);
??((org.zkoss.zk.ui.Page) _page).addEventListener("onCheck", this);
?}

?/**
? * Called to unregister the event listener.
? */
?public void unregister() {
??((org.zkoss.zk.ui.Page) _page).removeEventListener("onChange", this);
??((org.zkoss.zk.ui.Page) _page).removeEventListener("onSelect", this);
??((org.zkoss.zk.ui.Page) _page).removeEventListener("onCheck", this);
?}

?/**
? * Returns whether the modified flag is set.
? */
?public boolean isModified() {
??return _modified;
?}

?public void onEvent(Event event) throws Exception {
?}

?public boolean isDeferrable() {
??return false;
?}

}
3.5.2.3调用顺序
调用事件监听器的顺序如下。假定接收的是onClick 事件。
1. 如果监听器实现了org.zkoss.zk.ui.event.Express 接口,依次为添加到目标组件(targeting component)的onClick 事件调用事件监听器。按照添加的顺序调用。
2. 调用目标组件的onClick 属性指定的脚本语言。
3. 如果监听器没有实现org.zkoss.zk.ui.event.Express 接口,依次为添加到目标组件的onClick 事件调用事件监听器。按照添加的顺序调用。
4. 调用目标组件的onClick 成员方法。
5. 依次为添加到目标组件所属页面的的onClick 事件调用事件监听器。按照添加的顺序调用。org.zkoss.zk.ui.event.Express 接口是一个装饰器(decorative interface),用来改变调用事件监听器的优先级。注意,如果事件监听器被添加到页面,而不是组件,这个接口是没有意义的。
3.5.2.4事例:一个异步产生标签的工作线程
package Test;

import org.zkoss.lang.Threads;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zul.Label;

public class WorkingThread extends Thread {
?private static int _cnt;
?private Desktop _desktop;
?private Label _label;
?private final Object _mutex = new Integer(0);

?/**
? * Called by thread.zul to create a label asynchronously. To create a label,
? * it start a thread, and wait for its completion.
? */
?public static final Label asyncCreate(Desktop desktop)
???throws InterruptedException {
??final WorkingThread worker = new WorkingThread(desktop);
??synchronized (worker._mutex) { // to avoid racing
???worker.start();
???Executions.wait(worker._mutex);
???return worker._label;
??}
?}

?public WorkingThread(Desktop desktop) {
??_desktop = desktop;
?}

?public void run() {
??_label = new Label("Execute " + ++_cnt);
??synchronized (_mutex) { // to avoid racing
???Executions.notify(_desktop, _mutex);
??}
?}
}

然后,在一个事件监听器中,我们使用ZUML 页面来调用这个工作线程,如在onClick事件中。使用的代码如下所示:
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<window id="main" title="Working Thread">
?<button label="Start Working Thread">
??<attribute name="onClick">
?timer.start();
?Label label = Test.WorkingThread.asyncCreate(desktop);
?main.appendChild(label);
?timer.stop();
</attribute>
?</button>
?<timer id="timer" running="false" delay="1000" repeats="true" />
</window>
按下“Start Working Thread”按钮的效果如下:
?
此代码运行有错误,还没有运行出结果,官方的demo也是有错的。
?
4 组件属性及重要函数
4.1 标签组件
Label组件主要是用来呈现一段文字,最简单的应用方式如下所示:
?<window? width="50%" title="标签应用" border="normal">
??? ?? hello? world!
</window>
也可通过如下方式明确指定一个label
<window title="标签应用" width="50%" border="normal">
<label value="hello world!" style="color:green"/>
</window>
?
当然,你也可以为它设置各种属性来控制其显示方式。Label有pre、hyphen、maxlength和multiline属性。例如当pre属性为true时,所有的空格、换行符、制表符等都会被保留,不同属性配合使用将会产生不同的结果;hyphen属性控制单词在超过长度限制时的行为,hyphen为ture时,超过长度的单词会被截断到下一行继续显示,为false时直接切去不显示;maxlenth属性用来定义单词的最大长度;multiline属性与pre类似,只是multiline在每行的开始保留了空格和换行。如下表所示:
?
具体应用效果如下:
1)最大长度为9,hyphen为true
?<window? width="50%" title="标签属性应用" border="normal">
?<vbox id="a">
?</vbox>
?<zscript>
?<![CDATA[
????????? String[] s={"welcome!","Nice to meet you!","Hello every!"};
????????? for(int i=0;i<s.length;++i)
????????? { Label l=new Label(s[i]);
??????????? l.maxlength=9;
??????????? l.hyphen=true;
??????????? l.parent=a;
????????? }
?]]>
?</zscript>
</window>
?
2)最大长度为9,hyphen为false
<window? width="50%" title="标签属性应用" border="normal">
?<vbox id="a">
?</vbox>
?<zscript>
?<![CDATA[
????????? String[] s={"welcome!","Nice to meet you!","Hello every!"};
????????? for(int i=0;i<s.length;++i)
????????? { Label l=new Label(s[i]);
??????????? l.maxlength=9;
??????????? l.hyphen=false;
??????????? l.parent=a;
????????? }
?]]>
?</zscript>
</window>
?
3)pre属性为true
<window width="50%" title="pre属性" border="normal">
<label? value="hello????? world!" pre="true" style="color:blue"/>
</window>
?
4)pre属性为false
<window width="50%" title="pre属性" border="normal">
<label? value="hello????? world!" pre="false" style="color:blue"/>
</window>
?
4.2 按钮组件
?按钮组件有两种类型Button和toolbarbutton,他们的主要功能是类似的,只是其外观显示不同。Button组件使用HTML BUTTON标记,而toolbarbutton组件使用HTML A标记。可用label和image属性来为按钮指定标签和图像,用dir属性控制哪个组件显示在前方,Orient控制布局是横向还是纵向。
为按钮添加行为可有两种方式,通过onClick和href属性。onClick属性定义了点击按钮后进行的响应,href属性定义了点击按钮后转向的页面。
具体应用如下所示:
1)显示不同的位置情况,点击不同的按钮,显示相应的值(onClick属性)
<window title="按钮应用" border="normal" width="60%">
<button? label="left" image="/img/1.gif"? onClick="view.value=self.label"
width="100px" height="70px"/>
<button? label="right" image="/img/2.gif"? dir="reverse" onClick="view.value=self.label"
width="100px" height="70px"/>
<button? label="above" image="/img/3.gif" orient="vertical" onClick="view.value=self.label"
width="100px" height="70px"/>
<button label="below" image="/img/4.gif" orient="vertical"? dir="reverse"
onClick="view.value=self.label" width="100px" height="70px"/>
<separator/>
<label id="view"/>
</window>
?
?
2)应用href属性
<window title="按钮应用" border="normal" width="60%">
<button? label="left" image="/img/1.gif"? href="/left.zul"
width="100px" height="70px"/>
<button? label="right" image="/img/2.gif"? dir="reverse" href="right.zul"
width="100px" height="70px"/>
<button? label="above" image="/img/3.gif" orient="vertical" href="/above.zul"
width="100px" height="70px"/>
<button label="below" image="/img/4.gif" orient="vertical"? dir="reverse"
href="below.zul" width="100px" height="70px"/>
<separator/>
<label id="view"/>
</window>
?
点击left后:
?
4.3 日历组件
Calendar属性展示了日历功能,并允许用户选择日期。它支持两种不同的布局,可通过compact属性进行设置。Calendar设置了value属性来让开发人员设置和获取选中的日期,开发人员还可以通过监听Onchang事件来进行必要的处理。
1)默认情况下compact属性为true
<window title="日历" border="normal" width="50%">
<vbox>
<calendar id="a" onChange="b.value = a.value"/>
<datebox id="b" onChange="a.value = b.value"/>
</vbox>
</window>
?
2)当compact属性为false时,上面显示的为月份,下面为日期,用户可直接进行选择
<window title="日历" border="normal" width="50%">
<vbox>
<calendar id="cal" compact="false" onChange="in.value = cal.value"/>
<datebox id="in" onChange="cal.value = in.value"/>
</vbox>
</window>

?
4.4 图像组件
Image组件用于在浏览器端展示图像,支持多种图像文件格式,一般有两种方式来为image组件指定一个图像。一种方式是使用src属性指定图像的URI,这种方法与HTML支持的相似;另一种方法是通过setContent方法来直接为image组件指定图像的内容,一旦被指定,图像会展示在浏览器端并会被动态更新。这种方法指定使用于动态生成的图像。
1)src方法
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<window title="new page title" border="normal" width="50%" height="50%">
<image AutoSize="true"? src="/img/hu.jpg"/>
这是使用src方法显示图片
</window>
?
2)setContent方法
<window>
<image id="img"/>
Upload your hot shot:
<fileupload onUpload="img.setContent(event.media)"/>
</window>
?
?
4.5 窗口
window 组件, 就像HTML的 DIV 标签, 用于为组件分组,应用很广泛。不同于其它的组件, window 有如下的特点。
1)、window是一个ID空间的所有者。window可以包含任意组件, 包括其自身。如果通过标识指定,可以使用getFellow方法来找到它。
2)、window 可以被重叠,弹出和嵌入(overlapped, popup, and embedded)。
3)、window 可以是对话框(modal dialog)。
Window有如下属性:
??title属性:用来设置window的标题
??caption属性:设置标题,caption 组件的所有子组件都会出现在 title 的右边,你可以为caption 指定标签和图像。
??border属性:border属性是否显示window 的边框。默认的样式仅支持normal 和 none。默认为none。但也可以提供额外的样式类(style class)。
??closable属性:若将closable属性值设为true,close 按钮会显示在window 组件中,这样可以关闭此window 。一旦用户点击了close按钮,onClose事件会被送到window。这样此事件会被window的onClose方法处理。那么,onClose在默认情况下会把 window 自身移除。也可以重定义此方法,或者注册一个监听器来改变默认的行为,例如,你可以选择隐藏而不是关闭。
??sizable属性:将sizable属性设为true,则允许用户重定义window的大小,这样用户可以拖曳边框来改变window的尺寸。
??contentStyle属性:通过指定contentStyle属性可以改变window中内容。contentStyle的一个典型应用是使一个 window变得可滚动。
Zk的window支持四种样式类:embedded , overlapped , popup 和 wndcyan,不同模式window 的外观是不同的,可以通过为 sclass 属性指定一个值来改变外观。
window有四种模式:重叠,弹出,标示和嵌入。嵌入为默认模式。可以使用doOverlapped , doPopup , doHighlighted和 doEmbedded方法来改变模式。
具体应用实例如下:
1)实例一
<zk>
<window id="win" border="normal" width="350px"? minheight="350">
?<caption image="/img/2.gif" label="Complex Window"/>
?<borderlayout height="300px">
??<north border="none">
???<menubar id="menubar" width="100%">
????<menu label="Project" />
????<menu label="Help" />
???</menubar>
??</north>
??<center>
???<div>Auto-position (applicable if not embedded)
???<image src="/img/jiqimao.jpg"/>
???</div>
??</center>
??<south border="0">
???<toolbar mold="panel" align="center">
????<button label="left,center" onClick="win.position = "left,center";"/>
????<button label="right,bottom" onClick="win.position = "right,bottom";"/>
????<button label="center" onClick="win.position = "center";"/>
???</toolbar>
??</south>
?</borderlayout>
</window>
<button label="Overlap" onClick="win.setSizable(true);win.doOverlapped();"/>
<button label="Popup" onClick="win.setSizable(true);win.doPopup();"/>
<button label="Embed" onClick="win.setSizable(false);win.doEmbedded();"/>
</zk>
Embed:
?
Overlap:
?
Popup:
?

2)实例二
<?page title="new page title" contentType="text/html;charset=UTF-8"?>
<window id="win" title="window实例"? border="normal" closable="true"
onClose="event.stopPropagation();" sizable="true" contentStyle="background:yellow">
<caption image="/img/3.gif" label="welcome"/>
Hello everyone!这是窗口演示界面,点击按钮查看相应变化。
<separator/>
<vbox>
<hbox>
<button id="b" label="Overlap" onClick="win.doOverlapped();a.value=b.label;" />
<button id="c" label="Popup" onClick="win.doPopup();a.value=c.label;" />
<button id="d" label="Modal" onClick="win.doModal();a.value=d.label;" />
<button id="e" label="Embed" onClick="win.doEmbedded();a.value=e.label;" />
<button id="f" label="Highlighted" onClick="win.doHighlighted();a.value=f.label;" />
</hbox>
<separator/>
<label id="a"/>
</vbox>
</window>
默认模式即为嵌入模式:
?
重叠模式:
?
弹出模式:
?
Modal模式:
?
??????? 标识模式:
?

4.6 布局组件
布局组件包括:borderlayout, north,south,center,west,east 。
布局组件是嵌套组件。 父组件为 borderlayout,子组件包括 north,south,center,west,和east。borderlayout 子组件的组合是任意的。
布局组件可以将某一区域分成三个竖直的区域,实现代码如下:
<borderlayout height="300px" width="500px">
<east width="150px">
The East
??? </east>
??? <center>
The Center
??? </center>
??? <west width="150px">
The West
??? </west>
</borderlayout>
?
也可以将某一区域分成三个水平的区域,实现代码如下:
<borderlayout height="300px" width="500px">
<north height="100px">
The North
??? </north>
??? <center>
??????? The Center
??? </center>
??? <south height="100px">
??????? The South
??? </south>
</borderlayout>
?
4.6.1 嵌套的 borderlayout 组件
为了将某一区域划分更多的小区域,你可将布局组件嵌入到另一个布局组件中,即嵌套的borderlayout 。
<borderlayout height="300px" width="500px">
??? <north size="30%">
??????? <borderlayout >
??????????? <west border="normal">
??????????????? The First Area
??????????? </west>
??????????? <center>
??????????????? The Second Area
??????????? </center>
??????????? <east size="50%" border="normal">
??????????????? The Third Area
??????????? </east>
???????? </borderlayout>
???? </north>
???? <center border="normal">
???????? <borderlayout>
???????????? <west border="normal">
???????????????? The Forth Area
???????????? </west>
???????????? <center border="normal">
???????????????? The Fifth Area
???????????? </center>
???????????? <east size="30%" border="normal">
???????????????? The Sixth Area
???????????? </east>
???????? </borderlayout>
???? </center>
</borderlayout>
?
4.6.2 布局组建的size和border属性
north,south,east,west等子组件可以通过指定size属性改变其大小,size属性的功能依赖于子组件的类型,对于水平组件(north和south)size属性决定他们的高度,而对于竖直组件(east和west)size属性决定他们的高度。
border属性决定是否为布局组件设置边框,包括borderlayout的所有子组件。当border值为“none”或“default”时,布局组件没有边框;当border值为“normal”时,布局组件显示边框。
<borderlayout height="300px" width="500px">
??? <north size="30%" >
??????? The North
??? </north>
??? <east size="30%" border="normal">
??????? The East
??? </east>
??? <center border="normal">
??????? The Center
??? </center>
??? <west border="default">
??????? The West
??? </west>
??? <south size="30%" border="normal">
??????? The South
??? </south>
</borderlayout>
?
4.6.3 布局组件的splittable和collapsible属性
将splittable属性设置为“true”,布局组件可以拆分;将collapsible属性设置为“true”,布局组件可以折叠。
<borderlayout height="300px" width="500px">
?<north title="North" maxsize="300" size="50%" splittable="true" collapsible="true">
<borderlayout>??
<west title="West" size="25%" flex="true" maxsize="250"
???????????? splittable="true" collapsible="true">
?????? <div style="background:#B8D335">
??????? <label value="25%" style="color:white;font-size:50px" />
????</div>
???</west>
???<center border="none" flex="true">
????<div style="background:#E6D92C">
?????<label value="25%" style="color:white;font-size:50px" />
????</div>
???</center>
???<east size="50%" border="none" flex="true">
????<label value="Here is a non-border" style="color:gray;font-size:30px" />
???</east>
??</borderlayout>
?</north>
?<center border="0">
??<borderlayout>
???<west maxsize="350" size="30%" flex="true" border="0" splittable="true">
????<div style="background:#E6D92C">
?????<label value="30%" style="color:white;font-size:50px" />
????</div>
???</west>
???<center>
????<label value="Here is a border" style="color:gray;font-size:30px" />
???</center>
???<east title="East" size="30%" flex="true" collapsible="true">
????<div style="background:#B8D335">
?????<label value="30%" style="color:white;font-size:50px" />
????</div>
???</east>
??</borderlayout>
?</center>
</borderlayout>
?
??? 当布局组件被设置为可拆分时,maxsize和minisize属性决定此组件的变动范围,如:<north splittalbe=”true” maxsize=”500px” minisize=”200px”/>,则north组件的变动范围为200?px—500px。
4.6.4 布局组件的其他属性
将布局组件的flex属性设置为true时,布局组件会随着浏览器大小的改变自动调整自身的尺寸来适合浏览器的尺寸。
为了获知一个布局组件是否已被折叠,则可以检查其属性的值(也就是 isOpen 方法)。
若想在程序中打开或折叠布局组件,则可以设置 open 属性的值(也就是,setOpen方法)。
4.7 标签页
组件:tabbox , tabs , tab , tabpanel , tabpanels。
tabbox是外层的box,包括一系列tab和tabpanel,tabs是tab的容器,也就是tab组件的集合,点击tab可以将其tabpanel显示出来,tabpanels是tabpanel的容器,也就是tabpanel组件的集合,tabpanel是面板的主体,可以将一组组件放置于一个tabpanels中,第一个tabpanel对应于第一个tab,第二个tabpanel对应于第二个tab,以此类推。
tabbox允许开发人员将大量组件分别置于几个组内,且每次只显示一个组,这样用户界面不会太难于阅读。 在同一时间内仅会显示一组。一旦一个隐藏组的 tab被点击后,此组的组件变得可见而前一个可见组变得不可见。
<tabbox width="200px">
??? <tabs>
??????? <tab label="First"/>
??????? <tab label="Second"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel>The first panel.</tabpanel>
??????? <tabpanel>The second panel</tabpanel>
??? </tabpanels>
</tabbox>
??
4.7.1 嵌套的tabbox
<tabbox width="500px">
??? <tabs>
??????? <tab label="First"/>
??????? <tab label="Second"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel>
??????????? The first panel.
??????? <tabbox>
??????????? <tabs>
??????????????? <tab label="Nested 1"/>
??????????????? <tab label="Nested 2"/>
??????????????? <tab label="Nested 3"/>
??????????? </tabs>
??????????? <tabpanels>
??????????????? <tabpanel>The first nested panel</tabpanel>
??????????????? <tabpanel>The second nested panel</tabpanel>
??????????????? <tabpanel>The third nested panel</tabpanel>
??????????? </tabpanels>
??????? </tabbox>
??????? </tabpanel>
??????? <tabpanel>The second panel</tabpanel>
</tabpanels>
</tabbox>
?
?
4.7.2 the accordion tabbox
tabbox支持两种模式(mold):default和accordion模式。
<tabbox mold="accordion" width="500px">
??? <tabs>
??????? <tab label="First"/>
??????? <tab label="Second"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel>The first panel.</tabpanel>
??????? <tabpanel>The second panel</tabpanel>
??? </tabpanels>
</tabbox>
?
?
4.7.3 tabbox的orient 属性
tabbox有两种布局方位,水平布局和垂直布局,默认为水平布局,也可以通过设置orient=”vertical”垂直布局。
<tabbox width="500px" orient="vertical">
??? <tabs>
??????? <tab label="A"/>
??????? <tab label="B"/>
??????? <tab label="C"/>
??????? <tab label="D"/>
??????? <tab label="E"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel>This is panel A</tabpanel>
??????? <tabpanel>This is panel B</tabpanel>
??????? <tabpanel>This is panel C</tabpanel>
??????? <tabpanel>This is panel D</tabpanel>
??????? <tabpanel>This is panel E</tabpanel>
??? </tabpanels>
</tabbox>
?
4.7.4 tab的closable 属性
可以通过设置tab的closable属性为true来显示tab的关闭按钮,这样用户可以通过点击关闭按钮来关闭tab和相应的tab面板。当用户点击了colse按钮,onClose时间会被送至tab,此事件会由tab的onClose方法来处理。
<tabbox width="250px">
??? <tabs>
??????? <tab label="Tab 1" closable="true"/>
??????? <tab label="Tab 2" closable="true"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel>This is panel 1</tabpanel>
??????? <tabpanel>This is panel 2</tabpanel>
??? </tabpanels>
</tabbox>
?
4.7.5 tab的disabled属性
通过将 disabled 属性设置为 true,用户通过点击 tab 或 close 按钮不能选择或关闭相应的 tab。但是,开发人员仍然可以编程控制 tab 的选择或关闭。
<tabbox width="300px" id="tbx">
??? <tabs>
??????? <tab label="Step 1" id="tb1" disabled="true"/>
??????? <tab label="Step 2" id="tb2" disabled="true"/>
??????? <tab label="Step 3" id="tb3" disabled="true"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel><button label="to Step2" onClick="tbx.selectedTab=tb2"/>
</tabpanel>
??????? <tabpanel><button label="to Step3" onClick="tbx.selectedTab=tb3"/>
</tabpanel>
??????? <tabpanel>This is panel 3</tabpanel>
??? </tabpanels>
</tabbox>
程序说明:运行程序后显示如下界面:
?
点击按钮“to Step2”后打开第二个面板如下:
?
点击按钮“to Step3”后可以打开第三个面板:
?
4.7.6 tab 面板的随机存取
使用fulfill属性来推迟tab面板子组件的创建,这样仅当tab面板变为可见时才加载其内容。
<tabbox width="500px">
??? <tabs>
??????? <tab label="Preload" selected="true"/>
??????? <tab id="tab2" label="OnDemand"/>
??? </tabs>
??? <tabpanels>
??????? <tabpanel>
??????? ?This panel is pre-loaded since no fulfill specified
??????? </tabpanel>
??????? <tabpanel fulfill="tab2.onSelect">
??????? ?This panel is loaded only tab2 receives the onSelect event
??????? </tabpanel>
??? </tabpanels>
</tabbox>
程序说明:当运行程序后第一个面板首先被加载,而此时第二个面板的内容还没有被加载。
?
仅当用户点击“OnDemand”时第二个面板才被加载。
?

4.8 网格
网格组件包括:grid,columns,column,rows 和 row。
使用网格grid可以使组件排列的就像表格一样整齐,在grid内,可以声明columns和rows,rows组件可以声明一套row,即为grid元素的子组件,在rows内可以为每一行添加row组件,以便在row元素内田间想要的内容。同样columns可以声明column组件,column声明每列的通用属性,如宽度和对齐方式等。
<grid width="500px">
??? <columns>
??????? <column label="Type"/>
??????? <column label="Content"/>
??? </columns>
??? <rows>
??????? <row>
??????????? <label value="File:"/>
??????????? <textbox width="99%"/>
??????? </row>
??????? <row>
??????????? <label value="Type:"/>
??????????? <hbox>
??????????????? <listbox rows="1" mold="select">
??????????????? ?<listitem label="Java Files,(*.java)"/>
??????????????? ?<listitem label="All Files,(*.*)"/>
??????????????? </listbox>
??????????????? <button label="Browse..."/>
??????????? </hbox>
??????? </row>
??? </rows>
</grid>
?
4.8.1 滚动网格
当指定了height 属性且没有足够的空间来显示数据时,grid 会变为滚动的。
<grid width="500px" height="130px">
??? <columns>
??????? <column label="Head 1"/>
??????? <column label="Head 2" align="center"/>
??????? <column label="Head 3" align="right"/>
??? </columns>
??? <rows>
??????? <row>
??????????? <listbox mold="select">
??????????? ?<listitem label="Faster"/>
??????????? ?<listitem label="Fast"/>
??????????? ?<listitem label="Average"/>
??????????? </listbox>
??????????? <datebox/>
??????????? <textbox rows="2"/>
</row>
??????? <row>
??????????? <checkbox checked="true" label="Option 1"/>
??????????? <checkbox label="Option 2"/>
??????????? <radiogroup>
??????????? ?<radio label="Apple"/>
??????????? ?<radio label="Orange" checked="true"/>
??????????? ?<radio label="Lemon"/>???????
?</radiogroup>
??????? </row>
??????? <row>
??????????? <checkbox checked="true" label="Option 1"/>
??????????? <checkbox label="Option 2"/>
??????????? <radiogroup orient="vertical">
??????????? ?<radio label="Apple"/>
??????????????? <radio label="Orange" checked="true"/>
??????????? ?<radio label="Lemon"/>
??????????? </radiogroup>
??????? </row>
</rows>
</grid>
?
4.8.2 可变列宽
如果你允许用户改变每列的宽度,可以将 columns 的 sizable 属性的设为 true。一旦允许用户进行此操作,用户可以通过拖动相邻列的边框来改变列宽。
<window width="500px">
<grid>
??????? <columns id="cs" sizable="true">
??????? ?<column label="AA"/>
??????? ?<column label="BB"/>
??????? ?<column label="CC"/>
??????? </columns>
<rows>
??????? ?<row>
??????? ??<label value="AA01"/>
??????? ??<label value="BB01"/>
??????? ??<label value="CC01"/>
??????? ?</row>
?????? ? ?<row>
??????? ??<label value="AA02"/>
??????? ??<label value="BB02"/>
??????? ??<label value="CC02"/>
?????? ??</row>
??????? ?<row>
??????? ??<label value="AA03"/>
?????? ? ??<label value="BB03"/>
??????? ??<label value="CC03"/>
??????? ?</row>
??? ?</rows>
</grid>
??? <checkbox label="sizable" checked="true" onCheck="cs.sizable=self.checked"/>
</window>
?
??? 通过拖动边框改变各列宽后如下:
?
4.8.3 分页网格
有两种方式在 grid 中处理较长的内容:滚动及分页。滚动可以由指定 height 属性来实现,就像在前面讨论的一样。分页可以通过将 mold 属性设为 paging 来实现的。一旦分页可用,grid 会将内容分为几页并且在同一时间内只显示一页。
<grid width="300px" mold="paging" pageSize="4">
??? <columns>
??????? <column label="Left"/>
??????? <column label="Right"/>
??? </columns>
??? <rows>
??????? <row>
??????????? <label value="Item 1.1"/><label value="Item 1.2"/>
??????? </row>
??????? <row>
??????????? <label value="Item 2.1"/><label value="Item 2.2"/>
??????? </row>
??????? <row>
??????????? <label value="Item 3.1"/><label value="Item 3.2"/>
??????? </row>
??????? <row>
??????????? <label value="Item 4.1"/><label value="Item 4.2"/>
??????? </row>
??????? <row>
??????????? <label value="Item 5.1"/><label value="Item 5.2"/>
??????? </row>
??????? <row>
??????????? <label value="Item 6.1"/><label value="Item 6.2"/>
??????? </row>
??????? <row>
??????????? <label value="Item 7.1"/><label value="Item 7.2"/>
??????? </row>
??? </rows>
</grid>
?
设置分页模式后可以通过 pageSize 属性指定每次的可见行数(也就是页面大小)。默认显示20行。
通过指明paginal属性可以控制两个或者更多的grid 。
<vbox>
<paging id="pg" pageSize="4"/>
<hbox>
? ???? <grid width="300px" mold="paging" paginal="${pg}">
????? ??<columns>
???????? ??<column label="Left"/><column label="Right"/>
????? ??</columns>
????? ??<rows>
???????? ??<row>
??????????? ??<label value="Item 1.1"/><label value="Item 1.2"/>
???????? ??</row>
???????? ??<row>
??????????? ??<label value="Item 2.1"/><label value="Item 2.2"/>
???????? ??</row>
???????? ??<row>
?????????? ? ??<label value="Item 3.1"/><label value="Item 3.2"/&gt

读书人网 >编程

热点推荐