ZK/操作指南/常见问题
1. 假设您有另一个名为 app2 的应用程序。然后,您可以通过使用 “~app2/your/resource/path” 来访问资源。
例如:
<include src="~app2/main/foo.zul"/>
请注意,Web 容器可能会阻止您访问其他 Web 应用程序。在这种情况下,将抛出 org.zkoss.lang.SystemException(("Context not found or not visible to....")。要启用它,您必须正确配置 Web 容器。
2. 在 context.xml 中,为 Context 元素指定 crossContext="true"
<Context crossContext="true">
使用 toolbarbutton 或 button 组件并指定 href 属性。例如,以下代码将生成 ZK - 简单而丰富 超链接。
<toolbarbutton label="ZK - Simple and Rich" href="http://tw.yahoo.com"/> <button label="Rich Internet Application" href="http://www.zkoss.org/zkdemo/userguide"/>
您也可以将 xhtml 和 xul 混合在一起,以便您可以创建普通的超链接,例如:
<window title="mix HTML demo" xmlns:h="http://www.w3.org/1999/xhtml"> <button label="zul hyperlink button" href="http://www.google.com/"/> <h:a href="http://www.google.com">xhtml hyperlink</h:a> </window>
查看演示和开发者指南以获取更多示例。
import java.io.ByteArrayOutputStream; import java.awt.image.RenderedImage; import javax.imageio.ImageIO; import org.zkoss.image.Image; import org.zkoss.image.AImage; Image encode(RenderedImage image) { ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(image, "png", os); return new AImage("my-image.png", os.toByteArray()); }
从 3.0.7 和 3.5.0 开始,有一个名为 org.zkoss.image.Images 的实用程序类来简化编码工作。
使用 include 组件,您可以像下面这样将任何页面包含多次。
<include src="/mypage.zul"/> <include src="/mypage.zul"/>
但是,如果您想访问它们内部的组件,您必须为被包含的页面分配一个唯一的标识符。您可以这样做。
<include src="/mypage.zul?pageId=first"/> <include src="/mypage.zul?pageId=second"/>
此外,在被包含的页面中,即此示例中的 mypage.zul,您必须编写
<?page id="${param.pageId}"?>
然后,您可以访问它们的组件。
Path.getComponent('//first/asdf/'); Path.getComponent('//second/asdf/');
请注意,组件的创建是在渲染阶段的最后,所以您只能在以下事件的事件监听器中访问它们
<window> <zscript><![CDATA[ /** * in a real application we would use something like * List iterateOverMe = sessionScope.get("listToRender"); */ String[][] iterateOverMe = { {"99", "Fred Flintstone"} ,{"8", "Wilma Flintstone"} ,{"65", "Barney Rubble"} ,{"32", "Betty Rubble"} }; ]]></zscript> <tabbox mold="accordion"> <tabs> <!-- more realisticly my iterateOverMe would be a List of pojos so that I can write ${each.label} --> <tab forEach="${iterateOverMe}" label="${each[1]}"/> </tabs> <tabpanels> <!-- more realisticly my iterateOverMe would be a List of pojos so that I can write ${each.id} --> <tabpanel forEach="${iterateOverMe}" > <include src="/render-item.zul?pageId=${each[0]}"/> </tabpanel> </tabpanels> </tabbox> </window>
在该页面中,我们为搜索结果列表中的每个对象拉入 search-item.zul 一次,并将包含的页面提供一个页面 ID,该 ID 是要渲染的项目的标识符,即 99、8、65、32。在 render-item.zul 中
<?page id="${param.pageId}"?> <zscript> // Here we have to use param.pageId to locate the object that we will render Object itemToRender = ... // use param.pageId as the identifier to locate specific object to render at this time </zscript> <vbox> <button label="${itemToRender.label}"/> </vbox>
该文件被包含了四次,param.pageId 每次都不同,即 99、8、65、32。每次调用页面时,我们使用 param.pageId 来查找要渲染的业务项目。
假设我们用 MyTabbox 扩展 Tabbox,如下所示。
public class MyTabbox extends Tabbox { ...
然后,您可以使用两种方法对其进行初始化:构造函数和 onCreate 事件。
public class MyTabbox extends Tabbox { public MyTabbox() { ...//some init } public void onCreate() { ...//other init } }
构造函数是在成员被分配初始值之前调用的,而 onCreate 事件是在整个页面加载后处理的。
但是,如果您以编程方式创建组件,而不是在 ZUML 页面中声明,则不会发送 onCreate 事件。
使用 Execution 接口的 sendRedirect 方法来要求浏览器重定向到另一个页面。对当前页面/桌面的所有更新都将被丢弃。
void onClick() { if (some_condition) Executions.sendRedirect("another_page"); }
首先,使用 include 组件并指定 src 属性来包含您想要的任何页面(ZK、JSP、JSF 或其他)在 ZK 页面中。其次,您可以通过更改 src 属性来动态地更改它。例如,以下代码将在最终用户按下 Bye! 按钮时将内部页面从 hello.zul 更改为 byebye.zul。
<include id="inner" src="hello.zul"/> <button label="Bye!" onClick="inner.src = "byebye.zul""/>
如果您只想重新加载同一个页面(而不是更改到另一个页面),您必须先将 src 属性设置为 null;然后将 src 属性设置回它以前的值。因为 ZK 优化了操作,所以将相同的值设置为同一个属性将被视为什么都不做。例如,以下代码将在最终用户按下 Reload 按钮时刷新 hello.zul 页面。
<include id="inner" src="hello.zul"/> <button id="reload" label="Reload" onClick="String tmp=inner.src; inner.src=null; inner.src=tmp;"/>
如果您想在完成其他一些工作后以编程方式从另一个按钮的事件处理程序中调用 Reload 按钮,您可以通过使用以下方法将当前事件分派到该按钮,只需按 ID 引用它
Events.sendEvent(reload,event)
如下所示
<button label="Do Lots Of Stuff Then Pass The Click To The Reload Button"> <attribute name="onClick"> { doLotsOfStuff(); Events.sendEvent(reload, event); } </attribute> </button>
创建以下页面,以及另外两个页面 "tab1.zul" 和 "tab2.zul" 在同一个文件夹中。在 tab1.zul 和 tab2.zul 中放一个 <window>,包含您想要的任何 zul(提示,访问演示页面,点击 "Try Me" 按钮,剪切粘贴一些大型源代码)。
<?page id="main-page"?> <window id="main-window"> <tabbox width="400px"> <attribute name="onSelect">{ //alert("selected index:"+self.selectedIndex); if(self.selectedIndex > 0 ) { Include inc = (Include)Path.getComponent("//main-page/main-window/tab"+self.selectedIndex); inc.setSrc("tab"+self.selectedIndex+".zul"); } }</attribute> <tabs> <tab label="Tab 0"/> <tab label="Tab 1"/> <tab label="Tab 2"/> </tabs> <tabpanels> <tabpanel>This is panel 0 and it does not have an include</tabpanel> <tabpanel> <include id="tab1" src=""/> </tabpanel> <tabpanel> <include id="tab2" src=""/> </tabpanel> </tabpanels> </tabbox> </window>
只有当您点击 "Tab 1" 和 "Tab 2" 时,tab1.zul 和 tab2.zul 的内容才会被加载,并且它们的组件会被创建。为了验证这一点,请注释掉以以下行开头的代码
inc.setSrc("tab"+self.selectedIndex+".zul");
然后刷新页面,点击选项卡,您将看不到 tab1.zul 或 tab2.zul 中的任何 xul,因为在注释掉加载它们的事件处理程序代码之后,这些文件不会被加载。
XML解析器将换行符视为普通的空格,因此使用换行符将不起作用。
<label value="line 1 line 2"/>
请改为使用属性元素,如下所示:
<label multiline="true"> <attribute name="value">line 1 line 2</attribute> </label>
<window title="Countries" border="normal" width="100%"> <zscript><![CDATA[ // Here we have an array of countries // We will generate a bunch of buttons per this array // When the button is click, an alert window will show the country name. String[] countries = {"China", "France", "Germany", "United Kingdom", "United States"}; ]]></zscript> <hbox> <!-- WARNING THIS IS INCORRECT USE "Example 3" --> <button label="${each}" forEach="${countries}" onClick="alert(${each})"/> </hbox> </window>
示例 1 是错误的。EL 表达式不能在 onXxx() 事件处理程序中使用。当按钮被点击时,它会抛出一个异常 "Attempt to access property on undefined variable or class name",因为 onClick 中的 alert(${each}) 被直接解释为 Java 代码。
<window title="Countries" border="normal" width="100%"> <zscript><![CDATA[ // Here we have an array of countries // We will generate a bunch of buttons per this array // When the button is click, an alert window will show the country name. String[] countries = {"China", "France", "Germany", "United Kindom", "United States"}; ]]></zscript> <hbox> <!-- WARNING THIS IS INCORRECT USE "Example 3" --> <button label="${each}" forEach="${countries}" onClick="alert(each)"/> </hbox> </window>
示例 2 将 alert(${each}) 重写为 alert(each)。因为 each 是一个隐式对象,所以它应该可以直接在 onClick 中使用,就像其他隐式对象一样。然而,点击按钮仍然会抛出一个异常 "Undefined argument: each"。原因很简单。虽然 each 是一个隐式对象,但它是一个 临时 隐式对象。它只在 zuml 页面被评估时存在。当按钮被点击时,那个最初的 each 已经不存在了。
那么如何在 onXxx() 事件处理程序中引用 forEach 属性的 each 变量呢?关键是在 zuml 页面被评估时存储临时 each 变量,并在 onXxx 事件被触发时使用该存储的变量。
<window title="Countries" border="normal" width="100%"> <zscript><![CDATA[ // Here we have an array of countries // We will generate a bunch of buttons per this array // When the button is click, an alert window will show the country name. String[] countries = {"China", "France", "Germany", "United Kindom", "United States"}; ]]></zscript> <hbox> <button label="${each}" forEach="${countries}" onClick="alert(componentScope.get("country"))"> <custom-attributes country="${each}"/> </button> </hbox> </window>
示例 3 使用按钮的自定义属性映射(componentScope)在 zuml 页面被评估时存储临时 each 对象,并在按钮被点击时使用该存储的对象。
由 Bakoma 提供
Grid 由列和行组成,每个列的子元素都是列。类似地,行的子元素是行。
这是一个带有标题列和三行的简单 Grid:
Name Age Grade Mike 29 C Todd 21 B Tony 37 A
以下代码将以上内容放入一个 Grid 中,行和列可拖放和放置。以下是步骤:
- 创建 Grid
- 添加列,并指定每列都是可拖放和放置的,前提是它们是相同类型的列。
<columns> <column label="Name" draggable="col" droppable="col" onDrop="move(event.dragged)"/>gunawan <column label="Age" draggable="col" droppable="col" onDrop="move(event.dragged)"/> <column label="Grade" draggable="col" droppable="col" onDrop="move(event.dragged)"/> </columns>
- 添加行,并指定每行都是可拖放和放置的。
<rows> <row draggable="row" droppable="row" onDrop="move(event.dragged)"> <label value="Mike" /> <label value="29" /> <label value="C" /> </row> <row draggable="row" droppable="row" onDrop="move(event.dragged)"> <label value="Todd" /> <label value="21" /> <label value="B" /> </row> <row draggable="row" droppable="row" onDrop="move(event.dragged)"> <label value="Tony" /> <label value="31" /> <label value="A" /> </row> </rows>
- 实现事件处理函数。确保在移动列时也移动相应的单元格。
void move(Component dragged) { if(dragged.getClass().getName().endsWith("Column")) { int maxRows=dragged.getGrid().getRows().getChildren().size(); int i= dragged.getParent().getChildren().indexOf(dragged); int j= self.getParent().getChildren().indexOf(self); //move celles for each row for(int k=0; k < maxRows; k++) self.getGrid().getCell(k,j).parent.insertBefore(self.getGrid() .getCell(k,i),self.getGrid().getCell(k,j)); } self.parent.insertBefore(dragged, self); }
- 将它们组合在一起以获得完整的代码。
<zk> <grid> <columns> <column label="Name" draggable="col" droppable="col" onDrop="move(event.dragged)"/> <column label="Age" draggable="col" droppable="col" onDrop="move(event.dragged)"/> <column label="Grade" draggable="col" droppable="col" onDrop="move(event.dragged)"/> </columns> <rows> <row draggable="row" droppable="row" onDrop="move(event.dragged)"> <label value="Mike" /> <label value="29" /> <label value="C" /> </row> <row draggable="row" droppable="row" onDrop="move(event.dragged)"> <label value="Todd" /> <label value="21" /> <label value="B" /> </row> <row draggable="row" droppable="row" onDrop="move(event.dragged)"> <label value="Tony" /> <label value="31" /> <label value="A" /> </row> </rows> </grid> <zscript><![CDATA[ void move(Component dragged) { if(dragged.getClass().getName().endsWith("Column")) { int maxRows=dragged.getGrid().getRows().getChildren().size(); int i= dragged.getParent().getChildren().indexOf(dragged); int j= self.getParent().getChildren().indexOf(self); //move celles for each row for(int k=0; k < maxRows; k++) self.getGrid().getCell(k,j).parent.insertBefore(self.getGrid() .getCell(k,i),self.getGrid().getCell(k,j)); } self.parent.insertBefore(dragged, self); } ]]></zscript> </zk>
<html>版权所有 &copy; Super Co.</html>
解释:& 是一种将 & 传递给 html 组件的 content 属性的方法。并且,html 组件直接将 content 属性输出到浏览器。
另一方面,如果使用 label 组件,它将不起作用,因为 label 会对其内容进行编码。
<label>版权所有 &copy; Super Co.</label>
org.zkoss.zk.ui.sys.ComponentsCtrl.applyForward(comp, "onClick");
1. 首先,在您的应用程序的 zk.xml
文件中设置日志配置。我使用了空字符串。
<zk> <log> <log-base></log-base> </log> </zk>
2. 创建一个 i3-log.conf
配置文件,并将它放在 Tomcat 的 /conf 文件夹中。它应该包含以下内容。
org.zkoss.testlog=DEBUG org.zkoss=ERROR
3. 记住修改 Tomcat 的 /conf 文件夹中的 logging.properties
文件。默认的 ConsoleHandler
的级别是 INFO,因此您不会看到任何 DEBUG 消息,否则。将 java.util.logging.ConsoleHandler.level = INFO 修改为 java.util.logging.ConsoleHandler.level = FINEST 4. 如果您想输出来自程序的特定消息
private static final Log log = Log.lookup(org.zkoss.testlog.Foo.class); if(log.debugable()){ log.debug("a log for debug message"); } if(log.infoable()){ log.info("a log for info message"); }
来自 http://www.javaworld.com.tw/roller/atticcat/entry/2007_10_10_Using_log_in_zk