目录
本章描述了XUL组件集 。不同于其他的实现,ZK的XUL组件,经过了跨越网络合作的优化(co-operating across Internet)。有些组件可能不会完全兼容XUL技术标准。为方便起见,我们有时指它们为XUL组件。
Label组件用来呈现一段文字。
<window border="normal"> Hello World </window>
如果你想为Label指定一个属性,并且如下方式明确指定<label
>。
<window border="normal"> <label style="color: red" value="Hello World"/> </window>
[提示]:ZUML为XML而不是HTML,所以并不接受
。但是可以用 
代替。
你可以使用 pre
,
hyphen
,
maxlength
和multiline
属性来控制如何展示一个label。例如,如果指定pre
为true,所有的空格(white spaces),例如换行,空白,制表符(new line, space和tab)都会被保留。
|
|
|
描述 |
---|---|---|---|
|
|
|
切去超过指定最大长度的字符 |
|
|
|
如果一个单词超过了最大长度,此单词会被截断(hypernated) |
|
|
|
|
|
|
|
|
<window border="normal" width="100px"> <vbox id="result"> </vbox> <zscript><![CDATA[ String[] s = {"this is 9", "this is ten more to show", "this framework", "performance is everything"}; for (int j = 0; j < s.length; ++j) { Label l = new Label(s[j]); l.maxlength = 9; l.hyphen = true; l.parent = result; } ]]></zscript> </window>
multiline
属性与pre
类似,除了multiline
在每行的开始保留了换行和空格。
有两种类型的按钮:button
和toolbarbutton
。除了外观,它们的功能使相似的。button
组件使用HTML BUTTON标记,而toolbarbutton
组件使用HTML A标记。
你可以使用label
和image
属性来为一个按钮指定标签和图像。如果这两个属性都被指定,dir
控制`哪个组件显示在前方,orient
控制布局为横向或纵向。
<button label="Left" image="/img/folder.gif" width="125px"/> <button label="Right" image="/img/folder.gif" dir="reverse" width="125px"/> <button label="Above" image="/img/folder.gif" orient="vertical" width="125px"/> <button label="Below" image="/img/folder.gif" orient="vertical" dir="reverse" width="125px"/>
除了通过URL来指定图片,你可以使用setImageContent
方法为按钮指定一个动态生成图像。参考下面的章节获取细节。
提示:所有包含image
属性的组件都提供了setImageContent
方法。简单来说,setImageContent
方法用于动态生成图像,而image用于通过URL指定图像。
有两种方式为button
和 toolbarbutton
添加行为。首先需要为onClick
指定一个监听器。然后为href
属性指定一个URL。如果都被指定,href属性拥有更高的优先级,也就是说 onClick
事件不会被发送。
<button onClick="do_something_in_Java()"/> <button href="/another_page.zul"/>
当处理一个事件时, 你可以决定停止处理当前桌面,并且通过sendRedirect
方法来转到另一个页面。换句话说,下面的例子中两个按钮是等价的(从用户的观点来看)。
<button onClick="Executions.sendRedirect("another.zul")"/> <button href="another.zul"/>
既然 onClick
事件被送到了服务器去处理,你可以在调用sendRedirect
前添加更多的逻辑,例如,当特定的条件被满足时转到另一个页面。
另外,href
属性在客户端方面被完全处理。当用户点击按钮时,你的应用程序并不会被察觉
一个单选按钮是可以被打开或关闭的组件。单选按钮可以被分组,称为radiogroup
。在相同的组内,同一时间仅可以有一个按钮被选中。
<radiogroup onCheck="alert(self.selectedItem.label)"> <radio label="Apple"/> <radio label="Orange"/> <radio label="Banana"/> </radiogroup>
你可以混合使用radiogroup
和radio
来组成你想要的布局,如下所示。
<radiogroup> <grid> <rows> <row><radio label="Apple" selected="true"/> Fruit, music or computer</row> <row><radio label="Orange"/><textbox/></row> <row><radio label="Banana"/><datebox/></row> </rows> </grid> </radiogroup>
单选按钮属于离其最近的radiogroup
。你甚至你可按如下方式嵌套使用radiogroup
。每个
radiogroup
是独立的,虽然可能有某种视觉重叠(visual overlap)。
<radiogroup> <grid> <rows> <row><radio label="Apple" selected="true"/> Fruit, music or computer</row> <row><radio label="Orange"/> <radiogroup> <radio label="Small"/> <radio label="Large" selected="true"/> </radiogroup> </row> <row><radio label="Banana"/><datebox/></row> </rows> </grid> </radiogroup>
image
用于在浏览器端展示图像。有两种方式来为image
组件指定一个图像。一种方法是使用src
属性指定图像的URI,这种方法与HTML支持的相似。如果你想展示一张景台图像,或任何可以通过URL定位的图像,这种方法很有用。
<image src="/some/my.jpg"/>
就像使用其他可以接受URI的属性一样,你可以指定"*"来定位一张本地图像。例如,如果对不同的地区对应不同的图像,你可以按如下方式使用。
<image src="/my*.png"
然后假定你的用户以de_DE作为首选地区访问你的页面。ZK会设法定位名称为/my_de_DE.png的图像。如果没有找到,则会尝试/my_de.png ,最后是/my.png。
参考国际化一章中浏览器和本地化URI一节来获取细节。
第二种方法是使用setContent
方法来直接为image组件指定图像的内容。一旦被指定,图像会展示在浏览器端并会被动态更新。这种方法指定适用于动态生成的图像。
例如,你可以按如下方式为用户指定的位置生成一个映射。
Location: <textbox onChange="updateMap(self.value)"/> Map: <image id="image"/> <zscript> void updateMap(String location) { if (location.length() > 0) image.setContent(new MapImage(location)); } </zscript>
在上面的例子中,我们假定有一个MapImage
类用于产生指定位置的映射,即所谓的商业逻辑(business logic)。
注意,image组件仅接受org.zkoss.image.Image
中的内容。如果有工具生成的图像不是这个格式,可以使用org.zkoss.image.AImage
类来将一个二进制阵列数据,文件或输入流包装成Image
接口
在传统的Web应用程序中,缓存一个动态生成的图像是很复杂的。有了image组件,你就不需要担心这些了。一旦指定了一个图像的内容,它就属于image
组件,而且当image组件不再被使用时,它所占用的内存会被自动释放。
提示:如果你想指定非图像音频文件的内容,例如PDF,可以使用iframe
组件。参考相关章节获取细节。
imagemap
是一个特殊的image
组件。它接受image
组件的所有属性。但是不同于image
,当用户点击一张图像时,onClick 事件及鼠标坐标的位置会一起被送回服务器。相比之下,image
发送的onClick
事件不包含坐标。
鼠标位置的坐标是屏幕像素,从图像的左上角开始计数,始于(0,0)。这将会作为
org.zkoss.zk.ui.event.MouseEvent
的实例存储。一旦应用程序接收了onClick
事件,就可以通过getX
和getY
方法来检查鼠标位置的坐标。
例如,如果用户点击了下列语句展示图像的(137,167)像素(从左上角开始) ,那么用户就会得到如下所示的结果:
<imagemap src="/img/sun.jpg" onClick="alert(event.x + ", " +event.y)"/>
应用程序通常使用坐标来决定用户点击了那个部分,然后作出相应的相应。
通过为imagemap
然后,组件添加area
子组件,开发人员可以代替使用应用程序本身处理坐标的方法。
<imagemap src="/img/sun.jpg" onClick="alert(event.area)"> <area id="First" coords="0, 0, 100, 100"/> <area id="Second" shape="circle" coords="200, 200, 100"/> </imagemap>
然后,imagemap
组件将鼠标的位置坐标翻译成一个逻辑名字:用户点击的区域标识。
例如,如果用户点击(150,150),将会得到如下描绘的结果:
area 组件支持三种形状:圆,多边形和矩形(circle, polygon and rectangle)。鼠标位置的坐标是屏幕像素,从图像的左上角开始计数,始于(0,0)。
形状 |
坐标/描述 |
---|---|
|
|
|
一对x,y定义多边形的一个定点。定义三角形至少需要三对坐标。多边形会自动关闭,所以不需要为了关闭区域而在列表的末尾重复第一个坐标。 |
|
第一对坐标为矩形的一个角,另一对为斜对角。矩形只是为多边性指定四个顶点的简单方式。 |
如果一个area
组件内的坐标覆盖了另外一个,第一个拥有更高的优先权。
audio
组件用来在浏览器端播放音频。就像image
,你可以使用src属性来指定音频资源的URL,或使用setContent
方法来指定一段动态生成的音频。
依靠浏览器和音频插件,开发人员可以使用play
,
stop
和pause
方法来控制播放一段音频。目前,包含多媒体的Internet浏览器都有这种控制机制。
XUL组件支持一套输入控制组件:textbox
,
intbox
,
decimalbox
,
doublebox
,
datebox
, combobox
和bandbox
,用于输入各种类型的数据 。
<zk> <textbox/> <datebox/> </zk>
提示:combobox
和bandbox
是特殊的输入框。他们共享这里描述的公用属性。关于它们各自独特的特点,将会在之后的 combobox
和bandbox
章节中讨论。
你可以为textbox
组件指定值为password
的type
属性。这样将不会显示用户输入的内容。
Username: <textbox/> Password: <textbox type="password"/>
通过使用format
域,可以控制输入控件的格式。默认为null
。对于datebox
,意味着 yyyy/MM/dd
。而对与intbox
和decimalbox
,则以为着根本没有格式。
<datebox format="MM/dd/yyyy"/> <decimalbox format="#,##0.##"/>
就像其他的任何属性,你可以动态的改变格式,如下所示:
<datebox id="db"/><button label="set MM-dd-yyyy" onClick="db.setFormat("MM-dd-yyyy")"/>
无鼠标输入datebox
Alt+DOWN
弹出日历 .
LEFT
,
RIGHT
,
UP
和 DOWN
改变日历中选中的日期.
ENTER
将选中的日期复制到 date
.
Alt+UP
或 ESC
放弃选择并关闭日历. .
使用constraint
属性可以控制输入控件接受什么值。它可以使no positive
,
no negative
,
no zero
,
no empty
,
no future
,
no past
,
no today
和一个正则表达式的集合。前三个约束金使用于intbox
和decimalbox
。no future
,
no past
,和no today
约束仅适用于datebox
。 no empty
适用于任何组件。正则表达式约束仅适用于字符串类型组件,例如textbox
,
combobox
和bandbox
。
使用两个或更多的约束时,用逗号翻开约束,如下:
<intbox constraint="no negative,no zero"/>
为了指定一个正则表达式,你可以使用/
来包围表达式。如下:
<textbox constraint="/.+@.+\.[a-z]+/"/>
注:
上面的语句为XML,所以不必使用\\
来表示反斜杠。另一方面,如果写在Java代码中,则是需要的。
new Textbox().setContraint("/.+@.+\\.[a-z]+/");
允许混合使用正则表达式与其他约束,但要用逗号分隔。
`如果你想为应用程序展示定制的信息,而不是默认的,可以添加约束及验证失败后的信息,用
冒号隔开。
如果你想为应用程序展示定制的信息,而不是默认的,可以添加约束及验证失败后的信息,用
冒号隔开。
<textbox constraint="/.+@.+\.[a-z]+/: e-mail address only"/> <datebox constraint="no empty, no future: now or never"/>
注:
如果指定了错误信息,那么它必须为末尾元素,且以冒号开始。
为了支持多语言,你可以使用l函数,就像在国际化(Internationalization)一章中描述的那样。
<textbox constraint="/.+@.+\.[a-z]+/: ${c:l('err.email.required')}"/>
除了在上述章节中描述的约束(例如no future
和正则表达式),datebox
支持一个日期范围。例如,
<datebox constraint="between 20071225 and 20071203"/> <datebox constraint="before 20071225"/> <datebox constraint="after 20071225"/>
注意
日期的格式被约束为yyyMMdd
,独立于区域。
约束内指定的日期为包含。例如,"before 20071225"包括December 25, 2007 及之前的每一天。
约束实际上表示org.zkoss.zul.SimpleDateConstraint
类的一个实例。你可以使用getBeginDate
和getEndDate
方法分别获取开始和结束日期。
((SimpleDateConstraint)datebox.getConstraint()).getBeginDate();
如果你想使用更复杂的约束,可以指定一个实现了org.zkoss.zul.Constraint
接口的对象。
<window title="Custom Constraint"> <zscript><![CDATA[ Constraint ctt = new Constraint() { public void validate(Component comp, Object value) throws WrongValueException { if (value =e= null || ((Integer)value).intValue() < 100) throw new WrongValueException(comp, "At least 100 must be specified"); } } ]]></zscript> <intbox constraint="${ctt}"/> </window>
你可以在一个Java类中实现你的约束,例如my.EmailValidator
,那么
<?taglib uri="/WEB-INF/tld/web/core" prefix="c"?> <textbox constraint="${c:new('my.EmailValidator')}"/>
在上面的例子中,我们使用了org.zkoss.zk.ui.WrongValueException
来表述一个错误。
就像描绘的那样,你需要指定两个参数,第一个为引起错误的组件,第二个为错误信息。你可以随时丢出这个异常,如下面,当onChange
事件被接收时:
<textbox> <attribute name="onChange"> if (!self.value.equals("good")) { self.value = "try again"; throw new WrongValueException(self, "Not a good answer!"); } </attribute> </textbox>
通过实现org.zkoss.zul.CustomConstraint
及Constraint
接口,你可以提供定制的外观,以代替前面例子中的默认错误框。CustomConstraint
有一个showCustomError
方法,当抛出异常或验证失败时,此方法会被调用。下面是一个例子:
<window title="Custom Constraint" border="normal"> <zscript><![CDATA[ class MyConst implements Constraint, CustomConstraint { //Constraint// public void validate(Component comp, Object value) { if (value == null || ((Integer)value).intValue() < 100) throw new WrongValueException(comp, "At least 100 must be specified"); } //CustomConstraint// public void showCustomError(Component comp, WrongValueException ex) { errmsg.setValue(ex != null ? ex.getMessage(): ""); } } Constraint ctt = new MyConst(); ]]></zscript> <hbox> Enter a number at least 100: <intbox constraint="${ctt}"/> <label id="errmsg"/> </hbox> </window>
在客户端验证更多的约束可以提高能力。你得实现org.zkoss.zul.ClientConstraint
及Constraint
接口来实现此功能。如果完成了客户端的所有验证,可以通
isClientComplete
方法返回true,那么将不会有回调服务(server callback)。
你也可以使用纯JavaScript代码来定制一个错误信息的显示,需要提供一个叫作Validate_errorbox
的函数。如下:
<script type="text/javascript"><![CDATA[ //Running at the browser window.Validate_errorbox = function (id, boxid, msg) { var html = '<div style="display:none;position:absolute" id="' +boxid+'">'+zk.encodeXML(msg, true)+'</div>'; document.body.insertAdjacentHTML("afterbegin", html); return $e(boxid); } ]]></script>
[注]: script
指定了在浏览器端运行的脚本代码类型, 而script
在服务器端运行的脚本代码类型.
[注]:如果也实现了CustomConstraint
,那么由于在服务端完成了所有的验证,所以 ClientConstraint 会被忽略。换言之, 如果你想使用ClientConstraint
提高响应能力,重写Validate_errorbox
是定制错误信息显示的唯一方式。
当用户已经改变了输入控件的内容,输入控件会使用onChange
事件来通知应用程序。
注意,当onChange
的事件监听器被调用时,其值已经被设定。因此,如果当你想为onChange
的事件监听器注入一个非法值时已经晚了,除非你适当地还原其值。建议使用在定制约束(Custom Constraints)章节描述的约束。
当用户正在改变了输入控件的内容时, 输入控件会使用onChanging
事件来通知应用程序
注意,当onChanging
的事件监听器被调用时,其值并没有被设定。换言之,value
属性原来的值。为了获取用户输入的内容,你得按如下方式访问事件的value
属性。
<grid> <rows> <row>The onChanging textbox: <textbox onChanging="copy.value = event.value"/></row> <row>Instant copy: <textbox id="copy" readonly="true"/></row> </rows> </grid>
由于用户还没有更改,所以onChanging
的事件监听器非法值就太早了。建议使用在定制约束(Custom Constraints)章节描述的约束。
calendar 展示了一个日历并允许用户从中选择一个日期。
<hbox> <calendar id="cal" onChange="in.value = cal.value"/> <datebox id="in" onChange="cal.value = in.value"/> </hbox>
Slider以滚动(scrolling) 方式来指定值。
<slider id="slider" onScroll="Audio.setVolume(slider.curpos)"/>
slider接收在0至100范围内的值。你可以使用maxpos
属性来改变允许的最大值 。
timer是一个不可见的组件,用于在指定的时刻或一段时间内将onTimer
事件发送到服务器。你可以使用 start
和stop
方法来控制 timer
。
<window title="Timer demo" border="normal"> <label id="now"/> <timer id="timer" delay="1000" repeats="true" onTimer="now.setValue(new Date().toString())"/> <separator bar="true"/> <button label="Stops timer" onClick="timer.stop()"/> <button label="Starts timer" onClick="timer.start()"/> </window>
paging组件用于将一段很长的内容分成多个页面。例如, 假定有100个项目,每次显示20个项目,那么可以按如下方式使用 paging 组件。
<paging totalSize="100" pageSize="20"/>
然后,当用户点击一个链接时,onPaging
事件会和org.zkoss.zul.event.PagingEvent
的一个实例被送到paging组件。可以为paging组件添加一个监听器以决定100个项目的哪部分是可见的。
<paging id="paging"/> <zscript> List result = new SearchEngine().find("ZK"); //assume SearchEngine.find() will return a list of items. paging.setTotalSize(result.size()); paging.addEventListener("onPaging", new EventListener() { public void onEvent(Event event) { int pgno = event.getPaginal().getActivePage(); int ofs = pgno * event.getPaginal().getPageSize(); new Viewer().redraw(result, ofs, ofs + event.getPaginal().getPageSize() - 1); //assume redraw(List result, int b, int e) will display //from the b-th item to the e-th item } }); </zscript>