posts - 50, comments - 5, trackbacks - 0, articles - 1
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

2007年4月17日

ZUML是基于XML的。每一个XML元素描述了需要创建的组件。一个XML属性描述了一个要被创建的组件的初始值。一个XML处理指示描述了如何处理整个页面,如页的标题。

 

不同的组件集合通过XML命名空间来区分。例如,XUL的是http://www.zkoss.org/2005/zul,XHTMLhttp://www.w3.org/1999/xhtml.

XML

这一章节提供了和ZK一起工作的XML的最基本的原则。如果你熟悉XML,你可以跳过这个章节。如果你想学到更多的,网络上有很多相关的资源,如http://www.w3schools.com/xml/xml_whatis.asp http://www.xml.com/pub/a/98/10/guide0.html

 

XML是一种标记语言,很象HTML,但是有更加严格的语法。有几点需要特别注意。

元素必须是结构良好的

首先,每个元素必须关闭。有两种方法来关闭一个元素。如下:

<window></window>

<window />

第二,元素要被正确的嵌套。

特殊的字符必须被替换

XML使用<element-name>来表示一个元素,所以你必须替换掉特殊的字符。例如,你必须使用&lt来替换<字符。

<     &lt

>     &gt

&    &amp

      &quot

      &apos

你也可以使用CDATAXML解析器不要对字符串进行解析。

<zscript>

<![CDATA[

       Void myfunc(int a,int b)

       {

              If(a<0&&b>0)

{

       //do something

}

       }

]]>

</zscript>

 

有意思的是反斜杠(\)不是特殊字符,所以你不需要担心。

 

属性值必须被指定且用引号包围

注释<!—and-->

字符编码

这虽然是可选的,但是在你的XML中指定编码,让XML解析器能正确解析是一个好的主意。注意:它必须在文件的第一行。

<?xml version=”1.0” encoding=”UTF-8”?>

同时你需要确认你的XML编辑器是否支持这种编码。

 

命名空间

命名空间是区分在XML文档中用到名字的简单易懂的方法。ZK使用XML命名空间来区分组件的名字,这样只要在不同的命名空间中,使用相同的名字是可以的。换句话说,ZK使用XML命名空间来表现一个组件集合,这样开发者可以在一个页面中混合两个或多个组件,如下描述。

<html xmlns:="http://www.w3.org/1999/xhtml"

       xmlns:x="http://www.zkoss.org/2005/zul"

       xmlns:zk="http://www.zkoss.org/2005/zk">

 

<head>

<title>zhtml demo</title>

</head>

<body>

<h1>zhtml demo</h1>

<table>

<tr>

<td><x:textbox/></td>

<td><x:button label="now" zk:onclick="addItem()"/></td>

</tr>

</table>

<zk:zscript>

void addItem()

{

}

</zk:zscript>

</body>

</html>

Schema自动完成

许多IDE,如Eclipse,支持自动完成,如果该xml schema被如下指定了的话。

<window xmlns="http://www.zkoss.org/2005/zul"

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">

 

posted @ 2007-04-17 14:40 daniel-shen 阅读(320) 评论(0) 编辑

事件的监听和处理
    本章将描述事件是如何处理的
    通过标记语言添加事件监听器
    增加监听器最简单的方法是在zuml页面中声明一个属性。监听事件的属性的值是能够被beanshell解释的java代码。
    <window title="hello" border="normal">
        <button label="say hello" onClick="alert(&quot;hello world!&quot)"/>
    </window>
    通过程序添加和移除事件监听器
    通过程序有两种方法添加事件监听器
   
    声明一个成员
    当通过自定义的类overriding一个组件的时候,你可以声明一个方法来作为一个事件监听器。
    在一张zuml页面中,use属性用来指定代替默认的自定义类。像下面表示的一样,这里需要zk使用myclass类来代替org.zkoss.zul.window.
    <window use="myclass">
    ...
    </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.ui.Component接口的addEventListener 和 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
}
public boolean isAsap() {
return true; //Refer the following section for description
}
}
ASAP是什么
在接口enentlistener中的isAsap方法定义了监听器的紧急事件。如果返回的是true,那么事件一旦发生就会被发送到服务器。
如果返回的是false,事件将不会被发送到服务器直到另一个ASAP事件发生。这样服务器的性能得到了提升,因为服务器和客户机的通信频率降低了。
注意这样做不会影响程序的正确性,因为应用保持空闲直到接受到一个事件,事件到达的顺序却是一致的(和发生的顺序一致)
动态的给页面添加和移除监听器
开发人员可以动态的给页面(org.zkoss.zk.ui.page)添加监听器,一旦添加了,all events of the specified name the are sent to any components of the specified page will be sent to the listener.
所有页面级的事件监听器均是非ASAP的.换句话说,isArap方法是被忽视的.一个典型的例子是使用一个页面级的事件监听器来保持修改是否发生的修饰符.
public class ModificationListener implements EventListener {
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 = owner.getPage();
_page.addEventListener("onChange", this);
_page.addEventListener("onSelect", this);
_page.addEventListener("onCheck", this);
}
/** Called to unregister the event listener.
*/
public void unregister() {
_page.removeEventListener("onChange", this);
_page.removeEventListener("onSelect", this);
_page.removeEventListener("onCheck", this);
}
/** Returns whether the modified flag is set.
*/
public boolean isModified() {
return _modified;
}
//-- EventListener --//
public void onEvent(Event event) throws UiException {
_modified = true;
}
public boolean isAsap() {
return false;
}
}
调用的步骤
调用事件监听器的顺序如下.我们假设接受到一个onClick事件.
1.调用被加到目标组件上的关于onClick事件的事件监听器,如果监听器实现了org.zkoss.zk.ui.event.express接口.第一个添加的,就第一个调用.
2.如果在目标组件的onClick属性中有指定的脚本,则执行.
3.调用被加到目标组件上 关于onClick事件的监听器,若监听器没有实现org.zkoss.zk.ui.event.express接口.第一个添加的,就第一个调用.
4.如果在目标组件上有onclick的成员方法,则执行.
5.调用组件所属的页面的onClick事件的监听器.第一个添加的,就第一个调用.
org.zkoss.zk.ui.event.Express接口是一个装饰器用来改变事件监听器的优先级别.注意如果监听器被加到页面而不是组件,则是无意义的.
中断invocation sequence
你可以通过org.zkoss.zk.ui.event.Event类的stopPropagation方法来中断invocation sequence.一旦一个监听器调用了这个方法,则之后的所有监听器将被忽略.
 

通过事件监听器发送和提交事件

做为事件接受的补充,应用应当可以通过向事件监听器提交和发送事件在事件监听器之间交流。

      提交事件

通过使用类org.zkoss.zk.ui.event.EventspostEvent方法,一个事件监听器可以提交一个事件到一个事件队列的队尾。将事件放置完毕后立即返回。直到该事件之前的事件均被处理后,该事件才被进行处理。

发送时间

       通过使用类org.zkoss.zk.ui.event.EventssendEvent方法,一个事件监听器可以使ZK立刻处理一个指定的事件。直到所有的指定事件的事件监听器都被处理了才返回。事件是在同一个线程中处理的。

 

线程模型

对于每一个桌面,事件是顺序处理的,所以线程模型是很简单的。类似于开发桌面应用,你不需要去担心多线程。你所需要去做的是登记事件监听器和被调用时候的处理代码。

       小提示:each event listener executes in an independent thread called event processing thread.while the ZUML page is evaluated in the servlet thread.

 

挂起和恢复

对于高级的应用,你可能需要挂气一个执行知道满足继续执行的条件。类org.zkoss.zk.ui.ExecutionsWait,notifynotifyAll方法提供这些支持。

 

当一个事件监听器想挂起自己,它可以调用wait方法。另一个线程在应用指定的条件下可以通过调用notify或者notifyAll来唤醒该进程。下面是一个使用这种机制的例子。

Public void doModal() throws InterruptedException{

       Executions.wait(_mutex);

}

Public void endModal(){

       Executions.notify(_mutex);

}

这样的使用类似于类java.long.objectwait,notifynotifyAll的用法。尽管如此,你还是不能使用java.lang.Object的方法来进行挂起和恢复事件监听器的操作。否则,关联到这个桌面的所有事件处理都将被停止。

 

注意,不同于java objectwaitnotify方法,是否使用synchronized锁来关闭Executionswaitnotify是可选的。在上面的例子中,我们不需要这样做,因为没有没有可能的racing condition。尽管如此,如果存在racing condition,你可以象在java Object中使用waitnotify那样使用synchronized block

//thread 1

Public void request()

{

Synchronized (mutex)

{

              Executions.wait(mutex);

}

}

//thread 2

Public void process()

{

       Synchronized(mutex)

       {

              Executions.notify(mutex);

       }

}

 

长操作

对于同一个桌面事件是被顺序处理的。换个说法,一个事件的处理程序将可以阻塞所有的后续处理程序。一个长时间被阻塞的请求可能是不可接受的(the time blocking user’s requests might not be acceptable),如果一个事件的处理将花费大量的时间。象桌面应用,你需要创建一个专用于工作这种长时间处理的工作线程来减少阻塞时间。

限制于http协议,我们必须符合以下的规则。

1.  在创建了工作线程后,使用wait方法来挂起事件处理进程本身。

2.  因为工作线程不是一个事件监听器,所以它不能进入任何组件(除非组件不属于任何桌面)。因此,在开始工作线程前你可能需要手工通过一些必要的信息。

3.  然后,工作线程可以crush the information和创建组件(若必要的话)。只是不把任何组件关联到任何桌面。

4.  在工作线程结束之后,在工作线程中使用类org.zkoss.zk.ui.Executions notify(Desktop desktop,Object flag)或者notifyAll(Desktop desktop,Object flag)方法来恢复事件处理进程。

5.  直到从客户另一个事件被发送过来,恢复的事件处理进程才会执行。为了强制发送一个事件,你可以使用timer组件(org.zkoss.zul.Timer)来触发一个事件a moment later or periodically.这个timer的时间监听器不做任何事情。

例子:工作线程异步的创建标签

假设我们想异步的创建标签。当然,这有点象用牛刀来杀鸡了,但是我们可以用sophisticated one 来替换这个任务。

//Working Thread

Package test;

Public class WorkingThread extends Thread

{

private static int _cnt;

private Desktop _desktop;

private Label )label;

private final Object _mutex = new Integer(0);

 

public static final Label asyncCreate(Desktop desktop)

        throws InterruptedException{

        final WorkingThread worker = new WorkingThread(desktop);

        synchronized(worker._mutex)

        {

               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)

        {

               Executions.notify(_desktop,_mutex);

        }

}

}

 

然后,我们有一个ZUML页面在一个事件监听器里来调用这个工作线程,如在onClick

<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" runing="false" delay="1000" repeats="true"/>

</window>

 

注意我们需要使用timer来真正恢复被挂起的事件监听器(onclick)。这看起来是多余的,但是归因于http的限制:为了保持web页面在浏览器中的alive,当事件处理进程被挂起的时候我们必须返回回应。然后,工作线程完成了工作,唤醒了事件监听器,http的请求已经gone了。因此,我们需要”piggyback”这个结果,这就是timer被使用的原因。

 

更准确的来说,当工作进程唤醒了事件监听器,ZK只是把它加到一个等待队列中。当另一个http请求到达的时候,监听器才真正的恢复。(在上面的例子中,是onTimer事件)

 

在这个简单里例子中,我们对onTimer事件什么都没做。对于一个sophisticated应用,你可以使用它来返回处理的状态。

 

另一个事例:没有挂起和恢复

没有挂起和恢复来执行一个长时间的操作是可能的。当同步代码对于调试来说太复杂的情况下是有用的。

 

主意很简单。工作进程在一个临时空间里保存结果,然后onTimer事件监听器将结果弹出到桌面。

//WorkingThread2

package test;

public class WorkingThread2 extends Thread

{

private static int _cnt;

private final Desktop _desktop;

private final List _result;

public WorkThread2(Desktop desktop,List result)

{

        _desktop = desktop;

        _result=result;

}

public void run(){

        _result.add(new Label("Execute "+ ++_cnt));

}

}

 

然后,在onTimer事件监听器上面追加labels

 

 

<window id = "main" title="working thread2">

<zscript>

int numpending = 0;

List result=Collections.synchronizedList(new LinkedList());

</zscript>

<button label="start working thread">

        <attribute name="onClick">

               ++numpending;

               timer.start()

               new test.workingthread2(desktop,result).start();

        </attribute>

</button>

<timer id="timer" running="false" delay="1000" repeats="true">

        <attribute name="onTimer">

               while(!result.isEmpty())

               {

                      main.appendChild(result.remove(0));

                      --numpending;

               }

               if(numpending==0)time.stop();

        </attribute>

</timer>

</window>

 

初始和清除事件处理线程

在处理每个事件之前初始化

 

一个事件监听器是在一个事件处理线程中执行的。有时,你不得不在处理所有事件之前初始该线程。

 

一个典型的例子是初始认证所使用的线程。一些j2ee或者web容器在thread local storage中存储着认证信息,因此它们可以在需要时自动进行重复认证。

 

为了进行事件处理线程的初始化,你需要在web-inf/zk.xml文件注册一个继承自org.zkoss.zk.ui.event.EventThreadInit接口的类。

 

一旦进行了注册,在开始一个事件处理线程之前,在主线程中一个指定类的实例就被创建了。然后在处理其他事情之前,该实例的init方法在事件处理线程的上下文中被调用了。

 

注意那个构造体和init方法是在不同的线程中被调用的,因此开发者可以从一个线程获得线程独立的数据发送到另一个线程。

 

下面是jboss的认证机制的例子。在这个例子中,我们在构造体中获得储藏在servlet线程中的信息。然后,我们在init方法调用的时候初始事件处理线程。

 

import java.security.Principal;

import org.jboss.security.SecurityAssociation;

import org.zkoss.zk.ui.Component;

import org.zkoss.zk.ui.event.Event;

import org.zkoss.zk.ui.event.EventThreadInit;

 

public class JBossEventThreadInit implements EventThreadInit

{

       private final Principal _principal;

       private final Object _credential;

 

       public JBossEventThreadInit()

       {

              _principal=SecurityAssociation.getPrincipal();

              _credential=SecurityAssociation.getCredential();

       }

 

       public void init(Component comp,Event evt)

       {

              SecurityAssociation.setPrincipal(_principal);

              SecurityAssociation.setCredential(_credential);

       }

}

 

然后在web-inf/zk,xml中,如下进行注册:

<zk>

       <listener>

              <listener-class>JBossEventThreadInit</listener-class>

       </listener>

</zk>

 

在处理完每个事件后清除

同样的,你可能不得不在处理完一个事件后清除一个事件处理进程。

 

典型的例子是关闭一个transaction,如果它没有被适当的关闭。

 

为了清除一个事件处理线程,你需要注册一个实现org.zkoss.zk.ui.event.EventThreadCleanup接口的监听类,然后在web-inf/zk.xml中注册。

 

<zk>

       <listener>

              <listener-class>my.MyEventThreadCleanup </listener-class>

       </listener>

</zk>

posted @ 2007-04-17 14:39 daniel-shen 阅读(717) 评论(0) 编辑

4.组件的生命周期
本章将讲解页面加载和更新的生命周期
页面加载的生命周期
    zk需要4个步骤来加载和翻译一张zuml页面:
 1.页面的初始化
 2.创建组件
  3.事件的处理
  4.rendering
下面分别详细的介绍上述4个阶段
    页面初始化
在这个阶段,zk启动了init函数,如果没有定义这样的处理指示,则跳过。
对于每一个init处理指示都有一个class属性,一个指定的类被创建,然后它的doInit方法被调用。这个类将会进行什么操作呢,当然,这取决于你应用的要求。
<?init class="myinit"?>
另一种指定处理指示的形式是像下面这样定义zscript文件。然后,这个zscript文件将会在本阶段解释。
<?init zscript="/my/init.zs"?>
注意在这个阶段,页面还没有放到桌面。
组件创建阶段
 在这个阶段,zk加载器解释zuml页面。它进行组件的创建和初始化。分下面几步进行。
 1.对于每一个组件,检查它的if和unless属性来决定组件的有效性。如果是无效的,则它和它的子组件均被忽略。
 2.在foreach属性中指定了items的集合,zk对每一个item重复下面的步骤。
 3.基于元素的名字创建组件,或者使用use属性指定的类
 4.按zuml页面上指定属性次序的初始化成员
 5.解释嵌套的元素,重复整个过程
 6.如果组件继承org.zkoss.zk.ext.AfterCompose接口,调用afterCompose函数。
 7.在所有的子组件都创建后,onCreate事件被发送到这个组件,应用可以在之后初始化一些元素的内容。Notice that the oncreate events are posted for child components first.
 Note: an developer can perform some application-specific initialization by listening to the oncreate event or implementing afterCompose. AfterCompose is called in the component create phase,while the oncreate event is handled by an event listener.
     an event listener is free to suspend and resume the execution(such as creating modal dialogs),while AfterCompose is a bit faster since no need to fork another thread.
    事件处理阶段
 在这个阶段,zk为桌面的每个事件调用每个监听器。
 一个独立的线程开始调用每一个监听器,所以在不影响其他事件处理的情况下可以被挂起。
 在处理的过程中,一个监听器可能会触发其他的事件,参考event listening and processing章节。
 the rendering phase
 在所有的事件处理了之后,zk renders这些组件成为一个规则的html页面,然后将其发送到浏览器。
 为了render组件,redraw方法被调用。在这个方法里面,一个组件的执行将不会改变组件的内容。

 更新页面的生命周期
 zk au engine 处理zk请求需要3个步骤:处理请求,处理事件,rendering
 zk au engine 将zk请求传递到队列(一个桌面一个队列)。因此,对于一个桌面,请求是被顺序处理的。对于不同的桌面,请求是平行处理的。
 请求处理阶段
 根据请求,zk au engine可能更新被影响的组件的内容,尽管在客户端看来内容是一样的。
 然后将相应的事件提交到队列。
 事件处理阶段
 这个过程和“组件创建阶段”相同。在一个独立的线程中顺序的对事件进行处理。
 the rendering phase
 在所有的事件被处理了以后,zk renders 影响的组件,创建相应的zk回应,然后将这些回应发送回客户端。然后client engine更新dom tree.
 
 模型
 组件即使在同一张页面里面也可能有多种不同的表现。这种观念叫做mold。程序员可以通过使用component接口的setMold方法动态的改变mold。所有的组件都有一个名为default的mold。一些组件可能支持多个mold,如tabbox同时支持default和accordion。
<tabbox><!-- if not specified, the default mold is assumed. -->
<tabs>
<tab label="Default"/>
</tabs>
<tabpanels>
<tabpanel>
<tabbox mold="accordion">
<tabs>
<tab label="First Accordion"/>
<tab label="Second Accordion"/>
</tabs>
<tabpanels>
<tabpanel>The first panel.</tabpanel>
<tabpanel>The second panel.</tabpanel>
</tabpanels>
</tabbox>
</tabpanel>
</tabpanels>
</tabbox>
 组件的垃圾回收
 Unlike many component-based GUI, ZK has no destroy or close method for components. Like W3C
DOM, a component is removed from the browser as soon as it is detached from the page. It is
shown as soon as it is attached to the page.
More precisely, once a component is detached from a page, it is no longer managed by ZK. If the
application doesn't have any reference to it. The memory occupied by the component will be
released by JVM's Garbage Collector.

posted @ 2007-04-17 14:38 daniel-shen 阅读(203) 评论(0) 编辑

zk体系结构:
    zk内嵌了体格基于ajax的机制进行自动的交互,一个基于xul的组件丰富可用性,一个标记语言简化开发。
    基于ajax的机制包含了三部分。 zk loader,zk au engine和zk client engine.对于用户的请求,zk loader加载zk page,然后转换成html page,发回客户端。一张zk page 是用zuml标记语言写的。zuml,类似与html,是用来描述创建什么组件,如何表现组件的。这些组件,一旦创建了,在session超时前都保持可用。
    zk au engine 和 zk client engine 的工作方式类似于棒球场上的投手和接球手。他们向服务器上正在运行的应用传递在浏览器中正在发生的事件,基于服务器操纵组件的规则更新dom树。这也被称为事件驱动的编程模式。
    工作流程:
    1.当用户在浏览器中输入了url或者点击了超级链接,一个请求发送到了服务器。如果rul满足条件(需要zk loader),zk loader被调用进行处理请求。
    2.zk loader加载指定的page,翻译page创建指定的组件。
    3.翻译完了整张页面以后,zk loader 将结果转成一张html page。这张page被发送到有zk client engine的浏览器。
    4.zk client engine安静的在浏览器中侦察用户触发的时间,如移动鼠标,修改值什么的,一旦侦察到了,它就通过发送zk 请求唤醒zk au engine。
    5.从client engine那接受到zk请求后,在必要的情况下,au engine 更新相应组件的内容。然后,au engine唤醒应用中相关是事件处理器。
    6.如果应用选择修改,增加,移除组件的内容,au engine通过zk回应发送被改变的组件的新的内容到client engine.
    7.这些zk回应指导client engine如何去更新dom树。
   
组件,页面和桌面
    组件:一个组件就是是一个UI 对象,如label,button,tree.它定义了用户接口的视图和动作。通过操纵它们,程序员控制如何在客户端上展现应用。一个组件必须扩展org.zkoss.zk.ui.Component接口。
    页面:一张页面是组件的集合。页面配置了属于它的组件,定义了组件在浏览器中出现的位置。当zk loader解释zuml page时,页面被自动创建。
    桌面:一张zuml page可能间接或直接的包含其他的 zuml page。当对于一个url 请求创建了多个页面的时候,它们被称为桌面(org.zkoss.zk.ui.Desktop).即桌面就是服务于同一个url的页面集合。
    当zk应用运行的时候,桌面上可能多个页面被加入或删除,就如同页面上的组件被增加或删除类似。
    createComponent方法:
    注意页面和桌面都是在后台创建和删除。但是没有api去创建和删除他们。页面创建是每次zuml加载的时候。页面删除是zk发现它再也不被关联的时候。桌面创建是在第一次zuml page加载的时候,删除是在太多的桌面在指定的session中创建的时候。
    org.zkoss.zk.ui.Executions类中createComponents方法只能创建组件而不是方法,即使是在加载zuml文档的时候。
组件的森林
    一个组件至多有一个父亲,可能有多个孩子。一些组件只接受特定类型的组件作为孩子,而一些组件只能成为特定组件的孩子,而有些却不允许有任何孩子。举例来说,xul的listbox只接受Listcols和Listiterm。
    一个没有父亲的组件被称为根组件。一个页面可能含有多个根组件,可以通过getRoots函数得到。
    组件:一个视图和java对象
    除了作为服务器上的一个java对象,组件也在浏览器扮演了视图角色,当且仅当它属于页面的时候。当组件与页面关联的时候,它的视图部分就被创建了。当组件不和页面关联的时候,其视图部分也被移除了。
    有两个方法可以放组件关联到页面。1.你可以调用setPage方法使一个组件成为指定页面的根组件。2.你可以调用setParent,insertBefore或者 appendChild方法使之成为其他组件的孩子。
    类似的,你可以通过setPage函数设置null把根组件从页面分离。当然,其孩子也和页面分离了。
    标示符:
    每一个组件都含有一个标示符(可以通过getId获得).它是组件被创建的时候自动获得的。程序员可以在任何时候修改它,没有任何限制。可是,一旦一个标示符被指定了,程序员可以在zuml page中通过java 代码或el表达式进入它。
<window title="Vote" 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>
    UUID:
    一个组件有另一个标示符叫做UUID(Unicersal Unique ID),这个才是程序员真正需要的。
    在浏览器组件和client engine通过UUID来操纵dom,和与服务器通信。其实,dom元素的id属性就是UUID.
    UUID是在组件被创建的时候生成的。它是不可变的,except the identifiers of components for representing HTML tags.  
    HTML相关的组件处理UUID和其他的组件不同:UUID和ID是相同的。如果你修改HTML相关的组件de  ID,则UUID也会被相应的修改。所以,旧试的javascript代码和servlet仍旧不加修改的保持工作。
    THE ID SPACE:
    将一个完整的视图分解成多个zuml页面是很普通的做法。举个例子,一个页面来显示订购单,一个对话狂用来输入支付条件。如果所有的组件在同一个桌面上有唯一的标示的话,程序员必须在所有的页面在一个桌面上保持这种唯一性。
    引入ID空间来解决这个问题。ID空间是桌面组件的子集。唯一性只需要在ID空间上面得到保证即可。
    一种简单的ID空间的形式是window(org.zkoss.zul.Window).window的所有子孙组件(包括window自己)形成一个独立的ID空间。因此,你只需要在页面上使用window作为组件的最上级,这样程序员就可以保持页面独立的唯一性。
    更一般的情况,任何组件可以形成一个ID空间,只要实现了org.zkoss.zk.ui.IdSpace接口。页面也实现这个接口,所以它也是空间的所有者。
    ID空间的最顶端组件也称为ID空间的所有者,可以通过component接口的getSpaceOwner方法返回。可以通过getFellow方法得到同个空间的成员。
    值得注意的是,getFellow方法可以由空间中的所有成员使用。getSpaceOwner方法也是的。
    The org.zkoss.zk.ui.Path class provides utilities to simplify the location of a component among ID spaces. Its use is similar to java.io.File.
     Path.getComponent("/A/C/E");
 new Path("A/C", "E").getComponent();
    在zscript中定义变量和函数
<window id="A>
<zscript>
Object myvar = new LinkedList();
void myfunc() {
...
}
</zscript>
...
<button label="add" onClick="myvar.add(some)"/>
<button label="some" onClick="myfunc()"/>
</window>
    定义的变量和函数被存储在包含他们的ID空间中,在上面的情况下,myvar和myfunc都存储在window a中。
    子空间可以看见父空间中定义的变量和函数。
    有意思的是,当assignment发生时,zk会首先定位变量。如果找到了,马上更新。如果没有找到,则新建一个变量。所以,在下面的例子中var2是”def“,而第二个var1和第一个是相同的。
<window id="A">
<zscript>var1 = "abc";</zscript>
<window id="B">
<zscript>var1 = "def";</zscript>
</window>
<zscript>var2 = var1;</zscript>
</window>
To declare a variable local to a namespace no matter its parent ID space defined it or not,use the following format:
MyClass myvar = myvalue,所以,在下面的例子中,var2是"abc"。in other words,the second var1 is created in the id space of window b,while the first var1 is created in the id space of window a.
<window id="A">
<zscript>var1 = "abc";</zscript>
<window id="B">
<zscript>Object var1 = "def";</zscript>
</window>
<zscript>var2 = var1;</zscript>
</window>
    zscript 和 el 表达式
    在zscript中定义的变量是能够被el表达式看见的,只要他们在一个id空间中。
<window>
<zscript>
String var = "abc";
</zscript>
${var}
</window>

<window>
abc
</window>
效果相同
    下面的变量在同一个空间中的是看不见的,它们被{}包围了
<zscript>
{
String var = "abc"; //visible only inside of the curly brace
}
</zscript>
事件:
    事件(org.zkoss.zk.ui.event.Event)是用来通知应用发生了什么。每一个事件被不同的类描述。举个例子,org.zkoss.zk.ui.event.MouseEvent表示了鼠标的动作,像单击。
    为了对事件做出回应,应用必须在事件上注册一个或多个监听。有两中方法。1.指定onXXX在标记语言中。2.给组件调用addEventListener方法。
     作为补充org.zkoss.zk.ui.event.Event类有sendEvent()和postEvent()方法。
    桌面和事件处理
    像上面提到的,桌面是服务于一个url请求的页面的集合。一个桌面也是一个事件监听可以进入的范围。  
    一个事件是和特定的桌面联系在一起的。zk基于关联的桌面隔离事件,将事件压入隔离的队列。因此,一个桌面的事件被顺序的处理。即,不同桌面的事件的执行关系是水平的。
    一个事件的监听器被允许进入关联的桌面的页面的任何一个组件。也被允许从一个组件转移到另一个组件上,只要是在同一个桌面上。换句话说,它不能访问其他桌面的组件。
    桌面和组件的创建
    当在一个监听器里创建了一个组件。默认的,它被指派到执行事件相关的桌面。这个指派甚至在组件没有关联到页面也会发生。这意味着,在事件监听器中产生的组件在监听器所关联的桌面上是可
以被使用的。
    当一个组件不在事件监听器中产生,它不属于任何桌面。在这种情况下,你可以关联到任何桌面只要关联发生在适当的事件监听器内。当然,一旦关联建立了,它就永远属于那个桌面了。
    在大多数应用中,很少有必要在非监听器中创建组件。可是,如果你有一个费时的操作,你可能想在后台线程中行它。然后你可能在后台准备一个组件树,当有适当的时间发生的时候把树添加到桌面上。有关long operations,请参考event listening and processing 。
    zuml和xml命名空间
    zuml是基于xml格式的语言,开发者用来描述视图的。不同的组件集合,像xul,xhtml可以被同时再一个zuml页面中使用。different markup languages could be added transparantly.如果2个或更多的组件集合被应用到同一个page,程序员需要通过xml命名空间区别它们。

posted @ 2007-04-17 14:37 daniel-shen 阅读(697) 评论(0) 编辑