窗口

window , 就像HTML的 DIV 标签, 用于为组件分组。不同于其它的组件, window 有如下的特点。

  1. window是一个ID空间的所有者。window可以包含任意组件, 包括其自身。如果通过标识指定,可以使用getFellow方法来找到它。

  2. window 可以被重叠,弹出和嵌入(overlapped, popup, and embedded)。

  3. window 可以是对话框(modal dialog)。

标题

window可以有一个title,一个caption 和 一个 border。标题(title) 是 title 属性指定的。 标题 (caption)是 caption 组件声明的。 caption 组件的所有子组件都会出现在 title 的右边。

<window title="Demo" border="normal" width="350px">
   <caption>
      <toolbarbutton label="More"/>
      <toolbarbutton label="Help"/>
   </caption>
   <toolbar>
      <toolbarbutton label="Save"/>
      <toolbarbutton label="Cancel"/>
   </toolbar>
   What is your favorite framework?
   <radiogroup>
      <radio label="ZK"/>
      <radio label="JSF"/>
   </radiogroup>
</window>

你可以为caption 指定标签和图像,其外观如下。

<window id="win" title="Main" border="normal" width="200px">
   <caption image="/img/coffee.gif" label="Hi there!"/>
   <checkbox label="Hello, World!"/>
</window>

closables属性

若将closable属性值设为true,close 按钮会显示在window 组件中,这样可以关闭此window 。一旦用户点击了close按钮,onClose事件会被送到window。这样此事件会被window的onClose方法处理。那么,onClose在默认情况下会把 window 自身移除。

你也可以重定义此方法,使其做你想做的事情。或者,注册一个监听器来改变默认的行为。例如,你可以选择隐藏而不是关闭。

<window closable="true" title="Detach on Close" border="normal" width="200px"
onClose="self.visible = false; event.stopPropagation();">
   In this example, this window hides itself when the close button is clicked.
</window>

注意,必须调用event.stopPropagation()阻止Window.onClose()被调用。

提示: 若为一弹出window,当由于用户点击window的外围或按下ESC键关闭此弹出window时, onOpen事件(open=false) 会被送至 window 。

这会有些困惑,但是onClose被送至服务器来询问移除还是隐藏window。默认情况下,window会被移除。当然,应用程序可以重定义此方法并且让其做任何事情,就像上面描述的一样。

另外,onOpen是一个通知(notification)。此事件被送出以通知应用程序客户端已经隐藏了window 。应用程序并不能阻止window被隐藏,或改变被移除的行为。

sizable属性

如果你允许用户重定义window的大小,可以将sizable属性设为true 。这样用户可以拖曳边框来改变

window的尺寸。

<window id="win" title="Sizable Window" border="normal" width="200px" sizable="true">
   This is a sizable window.
   <button label="Change Sizable" onClick="win.sizable = !win.sizable"/>
</window>

onSize事件

一旦用户改变了window 的尺寸,onSize事件及的org.zkoss.zul.event.SizeEvent一个实例会被送出。注意改变window的大小是在onSize事件被送出前发生的。换言之,事件就像一个通知那样服务。当然,你可以在事件监听器中做任何事情。

注: 如果用户拖曳上边框或左边框,onMove事件也会被送出,因为位置也改变了。

样式类

Zk的window支持四种样式类:embedded overlapped popupwndcyan。当然,你可以添加更多。

默认情况下,sclass属性与 window 模式是一样的,所以不同模式window 的外观是不同的。要想改变外观,可以按下例描述的那样简单的为 sclass 属性指定一个值。

<hbox>
   <window title="Embedded Style" border="normal" width="200px">
      Hello, Embedded!
   </window>
   <window title="Cyan Style" sclass="wndcyan" border="normal" width="200px">
      Hello, Cyan!
   </window>
   <window title="Popup Style" sclass="popup" border="normal" width="200px">
      Hello, Popup!
   </window>
   <window title="Modal Style" sclass="modal" border="normal" width="200px">
      Hello, Modal!
   </window>
</hbox>

contentStyle属性

通过指定contentStyle属性可以改变window中内容块的亲自体会(look and feel)。

<window title="My Window" border="normal" width="200px" contentStyle="background:yellow">
   Hello, World!
</window>

滚动窗口

contentType的一个典型应用是使一个 window变得可滚动。

<window id="win" title="Hi" width="150px" height="100px" contentStyle="overflow:auto" border="normal">
This is a long line to spead over several lines, and more content to display.
Finally, the scrollbar becomes visible.
This is another line.
</window>

边框

border属性是否显示window 的边框。默认的样式仅支持normalnone。默认为none

当然,你可以提供额外的样式类(style class)。例如,

<zk>
   <style>
   div.wc-embedded-dash {
   padding: 2px; border: 3px dashed #aab;
   }
   </style>
   <window title="My Window" border="dash" width="200px">
   Hello, World!
   </window>
</zk>

wc-embedded-dash定义了window 内框(inner box)的样式。样式类通过连锁(concatenating)wc [37]命名,sclass属性和border属性是一起的,并且以横线(-)分开它们。在此例中,由于此窗口是嵌入式的(embedded),所以为sclassembedded ,而且没有明确的sclass被指定(所以使用了默认的sclass)。

重叠,弹出,Modal,标示和嵌入

window有四种模式:重叠,弹出,Modal,标示和嵌入。嵌入为默认模式。可以使用doOverlapped doPopup doModal doHighlighteddoEmbedded方法来改变模式。如下,

<zk>
   <window id="win" title="Hi!" border="normal" width="200px">
      <caption>
         <toolbarbutton label="Close" onClick="win.setVisible(false)"/>
      </caption>
      <checkbox label="Hello, Wolrd!"/>
   </window>

   <button label="Overlap" onClick="win.doOverlapped();"/>
   <button label="Popup" onClick="win.doPopup();"/>
   <button label="Modal" onClick="win.doModal();"/>
   <button label="Embed" onClick="win.doEmbedded();"/>
   <button label="Highlighted" onClick="win.doHighlighed();"/>
</zk>

嵌入

嵌入window 和其它组件一起被插入在文字之间。在这种模式中,你不能改变window的位置,因为其位置是由浏览器决定的。

重叠

重叠window 和其它组件是重叠的,这样用户可以到处拖曳此window,并且开发人员可以使用setLeftsetTop方法来设置其位置。

除了doOverlapped,你也可以按如下方式使用mode属性,

<window title="My Overlapped" width="300px" mode="overlapped">
</window>

弹出

弹出window 与重叠window类似,除了弹出window 在用户点击任一组件(不包括弹出window本身及其所有子组件)时会自动关闭。就像其名字一样,它被设计成实现弹出window。

Modal

modal window (亦称对话框,modal dialog)与重叠window 类似,除了modal window可以挂起执行,直到endModal, doEmbedded, doOverlapped, doHighlighted, 和 doPopup方法中的一个被调用。

除了挂起执行,modal window还可以使不属于其的组件失效。

modal window会自动位于浏览器的中央,你可以控制它的位置。

标示

标示window 与重叠window 类似,除了标示window 的视觉效果与modal window相同。换言之,标示window 位于浏览器的中央,并且使不属于其的组件失效。

但是,标示window 不会挂起执行。就像重叠window,一旦模式改变,执行会继续。例如,仅当win1被关闭后f1()才会被调用,而在win2变为标示后g()被立即调用。

win1.doModal(); //the execution is suspended until win1 is closed
f1();

win2.doHighlighted(); //the execution won't be suspended
g1()

如果你不喜欢挂起事件处理线程,可以使用标示window 代替modal window。参考特性提示一章中使用Servlet线程处理事件的一节。

Modal窗口和事件监听器

不同于其它的模式,你仅能在事件监听器中将window 放置在modal模式中。换言之,你可以在事件监听器中调用doModal()或 setMode("modal")。

<zk>
   <window id="wnd" title="My Modal" visible="false" width="300px">
      <button label="close" onClick="wnd.visible = false"/>
   </window>
   <button label="do it" onClick="wnd.doModal()"/>
</zk>

另外,如果在组件创建阶段(Component Creation Phase)[38] 执行,下面的例子是错误的。

//t1.zul
<window title="My Modal" width="300px" closable="true" mode="modal">
</window>

如果在浏览器中直接打开,将会导致如下结果[39]

下面的代码会导致相同的结果。

//t2.zul
<window title="My Modal" width="300px" closable="true">
   <zscript>
      self.doModal();
   </zscript>
</window>

如果你需要在页面加载时创建一个modal window,可以按如下方式提交onModal事件。

//t3.zul
<window title="My Modal" width="300px" closable="true">
   <zscript>
   Events.postEvent("onModal", self, null);
   </zscript>
</window>

注: 下面的代码会正确执行,甚至t1.zul将window直接设置为modal模式(就像上面一样)。为什么呢?它在一个事件监听器中执行(onClick)。

<button label="do it">
   <attribute name="onClick">
   Executions.createComponents("t1.zul", null, null);
      //it loads t1.zul in this event listener for onClick
   </attribute>
</button>

position属性

除了lefttop属性,你可以使用position属性来控制重叠/弹出/modal window 的位置。例如,下面的代码片断将window置于右下角。

<window width="300px" mode="overlapped" position="right,bottom">
...

position属性可以是下列常量的集合,各常量之间以逗号 (,)隔开。

常量

描述

center

将winow组件放置在中间。若制定了leftright属性,则为垂直中心。若指定了topbuttom属性,则为水平中心。若均未指定,则以为着在两个方向均居中。

lefttop 属性被忽略。

left

将winow组件在左边。

left属性被忽略。

right

将winow组件在右边。

left属性被忽略。

top

将winow组件在顶部。

top属性被忽略。

bottom

将winow组件在底部。

top属性被忽略。

默认情况下,其值为null。也就是,重叠和弹出window 的位置由lefttop决定,而modal window居中。

通用对话框

XUL组件集支持下列通用对话框来简化一些通用任务。

消息框

org.zkoss.zul.Messagebox类提供了一套功能来显示消息框。典型应用是当发生错误时警告用户,或促使用户作出决定。

if (Messagebox.show("Remove this file?", "Remove?", Messagebox.YES | Messagebox.NO, Messagebox.QUESTION) == Messagebox.YES) {
   ...//remove the file
}

由于警告用户有误是很平常的,所以一个称为alert的全局函数被加进了zscript。alert函数是Messagebox类中show方法的一个捷径。换言之,下列两条语句是等价的。

alert("Wrong");
Messagebox.show("Wrong");

注意Messagebox为一个modal window,所以它也受相同的约束:仅在事件监听器中是可执行的。因此,下列代码将会失败。参考上面的Modal窗口和事件监听器一节获取更多的描述。

<window title="Messagebox not allowed in paging loading">
   <zscript>
   //failed since show cannot be called in paging loading
   if (Messagebox.show("Redirect?", "Redirect?",
   Messagebox.YES | Messagebox.NO, Messagebox.QUESTION) == Messagebox.YES)
      Executions.sendRedirect("another.zul");
   </zscript>
</window>

文件上传对话框

org.zkoss.zul.Fileupload类提供了一套功能用以帮助用户向服务器上传文件。一旦调用了get方法,浏览器端会显示一个文件上传对话框来促使用户指定要上传的文件。直到用户已经上传了文件或点击了放弃按钮其才会返回。

<window title="Fileupload Demo" border="normal">
   <image id="image"/>
   <button label="Upload">
      <attribute name="onClick">{
         Object media = Fileupload.get();
         if (media instanceof org.zkoss.image.Image)
            image.setContent(media);
         else if (media != null)
            Messagebox.show("Not an image: "+media, "Error",
               Messagebox.OK, Messagebox.ERROR);
      }</attribute>
   </button>
</window>

一次上传多个文件

如果你允许一次上传多个文件,可以按如下方式指定允许数字的最大值。

<window title="fileupload demo" border="normal">
   <button label="Upload">
      <attribute name="onClick"><![CDATA[{
   Object media = Fileupload.get(5);
   if (media != null)
      for (int j = 0; j < media.length; ++j) {
         if (media[j] instanceof org.zkoss.image.Image) {
            Image image = new Image();
            image.setContent(media[j]);
            image.setParent(pics);
         } else if (media[j] != null) {
            Messagebox.show("Not an image: "+media[j], "Error",
               Messagebox.OK, Messagebox.ERROR);
         }
      }
      }]]></attribute>
   </button>
   <vbox id="pics"/>
</window>

fileupload组件

fileupload不是一个modal对话框。它是一个组件,所以fileupload可以和其它组件一起插入文字之间。

注:除了静态的get方法用于打开文件上传对话框,org.zkoss.zul.Fileupload本身即为一个组件。 即所谓的fileuplod 组件。

例如,

<image id="img"/>
Upload your hot shot:
<fileupload onUpload="img.setContent(event.media)"/>
onUpload事件

当按下上传按钮后,onUpload事件及org.zkoss.zk.ui.event.UploadEvent事件的一个实例被送出。你可以使用getMediagetMedias方法获取上传文件的内容。

注意getMediagetMedias方法返回null即表示没有文件被指定但上传按钮被按下了。

OnClose事件

除了onUploadonClose事件也被送出以通知上传按钮还是放弃按钮被按下。默认情况下,如果监听了此事件来实现定制行为(have the custom behavior),fileupload组件会失效,也就是说,所有的域(field)会被清空或重设(redraw)。

文件下载对话框

org.zkoss.zul.Filedownload类提供了一套功能用以帮助用户从服务器下载文件。不同于iframe组件在浏览器窗口显示文件,如果其中的一个save方法被调用,则文件下载对话框会显示在浏览器端。然后,用户可以指定在本地文件系统中的存储路径。

<button label="Download download.html">
   <attribute name="onClick">{
   java.io.InputStream is = desktop.getWebApp().getResourceAsStream("/test/download.html");
   if (is != null)
      Filedownload.save(is, "text/html", "download.html");
   else
      alert("/test/download.html not found");
   }</attribute></button>



[37] wc 为 window 内容, 而 wt 为 window title.

[38] 参考组件活动周期(Component Lifecycle) 一章.

[39] 假定使用Tomcat.