组件: listboxlistitem
,
listcell
,
listhead
和 listheader
。
list box 用于显示列表中的若干项目。用户可以从列表中选取某一项目。最简单的形式如下。这是一个单列单选择的列表框。
<listbox> <listitem label="Butter Pecan"/> <listitem label="Chocolate Chip"/> <listitem label="Raspberry Ripple"/> </listbox>
Listbox有两种模型:default
和select
。若使用了select
,就会产生HTML的SELECT
标签。
<listbox mold="select">...</listbox>
注意: 若为"select
"模型, 则行数为"1", 且并没有项目被标明选中,浏览器就像第一行被选中一样显示listbox
。最坏的情况事,若用户选中了此事例中的首项目,则不会发出onSelect
事件。为了避免这种困惑,开发人员至少要为mold="select"
及 rows="1"
选择一个项目。
除了标签,你可以使用setValue
方法为每个项目指派一个特定应用程序值。
无鼠标输入 listbox
UP
和 DOWN
, 上下移动选中的列表项目。
PgUp
和PgDn
,以一页的步长上下移动选中项。
HOME
,选中首行,END
,选中末行。
Ctrl+UP
和 Ctrl+DOWN
,上下移动列表项目的聚焦但并不改变选中项目。
SPACE
,选中聚焦项目。
List box也支持多列。当用户选中以一个项目时,整行都会被选中。
为了指定一个多列列表,你需要指定listcell组件作为每个listitem(作为一行)的列。
<listbox width="200px"> <listitem> <listcell label="George"/> <listcell label="House Painter"/> </listitem> <listitem> <listcell label="Mary Ellen"/> <listcell label="Candle Maker"/> </listitem> <listitem> <listcell label="Roger"/> <listcell label="Swashbuckler"/> </listitem> </listbox>
通过使用listhead
和listheader
可以指定栏头,如下[40]。除了标签,通过使用image
属性你可以指定一张图像作为栏头。
<listbox width="200px"> <listhead> <listheader label="Name"/> <listheader label="Occupation"/> </listhead> ... </listbox>
通过使用listfoot
和listfooter
,你可以指定栏尾,如下。注意listhead
和listfoot
的顺序是不匹配的。每次listhead
实例被添加到一个listbox
时,它必须为第一个子组件,而listfooter
实例为最后一个子组件。
<listbox width="200px"> <listhead> <listheader label="Population"/> <listheader align="right" label="%"/> </listhead> <listitem id="a" value="A"> <listcell label="A. Graduate"/> <listcell label="20%"/> </listitem> <listitem id="b" value="B"> <listcell label="B. College"/> <listcell label="23%"/> </listitem> <listitem id="c" value="C"> <listcell label="C. High School"/> <listcell label="40%"/> </listitem> <listitem id="d" value="D"> <listcell label="D. Others"/> <listcell label="17%"/> </listitem> <listfoot> <listfooter label="More or less"/> <listfooter label="100%"/> </listfoot> </listbox>
通过指定select模型及单行可以创建一个下拉列表。注意不能为下拉列表指定多列。
<listbox mold="select" rows="1"> <listitem label="Car"/> <listitem label="Taxi"/> <listitem label="Bus" selected="true"/> <listitem label="Train"/> </listbox>
当用户点击一个列表项目时,这个项目会被选中,且onSelect
事件会被送回服务器以通知应用程序。通过将multiple
属性设置为 true,你可以控制一个listbox 是否允许选中多行。默认为false。
若指定了rows
或height
属性且不足以显示所有项目时, listbox 会变为滚动的。
<listbox width="250px" rows="4"> <listhead> <listheader label="Name" sort="auto"/> <listheader label="Gender" sort="auto"/> </listhead> <listitem> <listcell label="Mary"/> <listcell label="FEMALE"/> </listitem> <listitem> <listcell label="John"/> <listcell label="MALE"/> </listitem> <listitem> <listcell label="Jane"/> <listcell label="FEMALE"/> </listitem> <listitem> <listcell label="Henry"/> <listcell label="MALE"/> </listitem> <listitem> <listcell label="Michelle"/> <listcell label="FEMALE"/> </listitem> </listbox>
就像grid,指定paging
模型,你就可以使用多页来呈现listbox的较长内容。类似的,你可以控制每页显示多少项目,是否使用额外的paging组件,以及当选中某一页面时是否定制行为。参考网格一节获取细节。
Listbox直接支持列表项目的排序。有几种方式来启动某一列的排序。最简单的方式是将listheader 的sort
属性设为auto,如下。然后,与listheader 关联的列会基于指定列的每个列表元素的标签排序。
<zk> <listbox width="200px"> <listhead> <listheader label="name" sort="auto"/> <listheader label="gender" sort="auto"/> </listhead> <listitem> <listcell label="Mary"/> <listcell label="FEMALE"/> </listitem> <listitem> <listcell label="John"/> <listcell label="MALE"/> </listitem> <listitem> <listcell label="Jane"/> <listcell label="FEMALE"/> </listitem> <listitem> <listcell label="Henry"/> <listcell label="MALE"/> </listitem> </listbox> </zk>
若你想用不同的方式为列表项目排序,可以为sortAscending
和/
或sortDescending
属性指派一个java.util.Comparator
实例。一旦指定了,列表项目会使用你指派的比较器以升序或降序存储。
调用值为auto的sort属性实际上是自动为sortAsceding
和 sortDescending
指定了两个比较器。你可以重定义它们中的任意一个通过为其指派另一个比较器。
例如,假定你想基于列表项目的值排序,而不是列表元素的标签,可以按如下方式为这些属性指派以一个ListitemComparator
的实例。
<zscript> Comparator asc = new ListitemComarator(-1, true, true); Comparator dsc = new ListitemComarator(-1, false, true); </zscript> <listbox> <listhead> <listheader sortAscending="${asc}" sortDescending="${dsc}"/> ...
sortDirection
属性控制是否在客户端显示一个图标,以指明特定列的排列顺序。若列表项目在添加到listbox前已排好序,你需要明确设置这个属性。
<listheader sortDirection="ascending"/>
然后,只要你为相应的listheader指派了比较器listbox会自动维护。
当你为listheader 至少指派了一个比较器时,若用户点击了它,onSort
事件就会被送至服务器。 listheader 实现了一个监听器来自动处理排序。
若你喜欢受手动处理,可以将你的监听器添加到listheader的onSort
事件。为了阻止默认的监听器调用sort方法,你必须调用stopPropagation
方法来阻止接收事件。另外,你可以重定义sort
方法,见下文。
sort
方法是默认的onSort
事件监听器的最底层实现。若你想使用Java代码为列表项目排序这也是很有用的。例如,你可以在添加项目(假定并未排好序)之后调用此方法。
new Listem("New Stuff").setParent(listbox); if (!"natural".header.getSortDirection()) header.sort("ascending".equals(header.getSortDirection()));
默认的排序算法为快速排序(使用org.zkoss.zk.ui.Components
类的sort
方法)。你可以将其用自己的实现来重定义,或像前一章节描述的那样监听onSort
事件。
提示: 为大量实况数据(live data)排序或许会显著的降低性能。最好是侦听(intercept) onSort事件或sort方法以有效处理排序。参考下面的为实况数据排序一节。
checkmark
属性控制是否在每个listitem前显示一个checkbox 或radio按钮。
在下面的例子中,当你将一个listitem 从左边的listbox 移到右边的listbox时,会自动添加一个checkbox。反过来checkbox会被移去。
<hbox> <listbox id="src" rows="0" multiple="true" width="200px"> <listhead> <listheader label="Population"/> <listheader label="Percentage"/> </listhead> <listitem id="a" value="A"> <listcell label="A. Graduate"/> <listcell label="20%"/> </listitem> <listitem id="b" value="B"> <listcell label="B. College"/> <listcell label="23%"/> </listitem> <listitem id="c" value="C"> <listcell label="C. High School"/> <listcell label="40%"/> </listitem> <listitem id="d" value="D"> <listcell label="D. Others"/> <listcell label="17%"/> </listitem> </listbox> <vbox> <button label="=>" onClick="move(src, dst)"/> <button label="<=" onClick="move(dst, src)"/> </vbox> <listbox id="dst" checkmark="true" rows="0" multiple="true" width="200px"> <listhead> <listheader label="Population"/> <listheader label="Percentage"/> </listhead> <listitem id="e" value="E"> <listcell label="E. Supermen"/> <listcell label="21%"/> </listitem> </listbox> <zscript> void move(Listbox src, Listbox dst) { Listitem s = src.getSelectedItem(); if (s == null) Messagebox.show("Select an item first"); else s.setParent(dst); } </zscript> </hbox>
注意若multiple
属性为 false,则会显示radio 按钮,如右图所示。
vflex
属性控制是否在垂直方向增长或缩小以适合指定空间。即所谓的垂直柔性(vertical flexibility)。例如,如果列表太长以至于不适合浏览器窗口,此属性会缩小列表的高度以控制整个列表在浏览器内可见。
若指定了rows
属性则此属性会被忽略。
就像grid[41],listbox支持live data。使用了实况数据,开发人员可以将数据从视图分离。换句话说,开发人员仅需要实现org.zkoss.zul.ListModel
接口提供数据,而不用直接操作listbox。好处有以下两点,
易于使用不同的视图来显示相同的数据。
listbox仅在其可见时才会将数据送至客户端。在数据量巨大时可以减少大量的网络流量(network traffic)。
使用实况数据需要经过三步,
以ListModel
形式准备好数据。ZK有一个称为org.zkoss.zul.SimpleListModel
的具体实现,用于显示一个数组对象。
实现org.zkoss.zul.ListitemRenderer
接口用于将一个数据项目送至listbox的一个列白哦项目。
这是可选的。若为指定,默认的渲染器(renderer)会启,并将数据送至第一列。
你可以实现不同的渲染器(renderer),这样可以在不同的视图中显示相同的数据。
在model
属性中指定数据,并且可以选择在itemRenderer
属性指定渲染器(renderer)。
在下面的例子中,我们准备了一个strset
列表模型(list model),通过model属性将其指派给一个listbox。然后,listbox会处理余下的工作。
<window title="Livedata Demo" border="normal"> <zscript> String[] data = new String[30]; for(int j=0; j < data.length; ++j) { data[j] = "option "+j; } ListModel strset = new SimpleListModel(data); </zscript> <listbox width="200px" rows="10" model="${strset}"> <listhead> <listheader label="Load on demend"/> </listhead> </listbox> </window>
若你允许用户为一个提供实况数据的listbox排序,你可以实现org.zkoss.zul.ListModel
和org.zkoss.zul.ListModelExt
接口。
class MyListModel implements ListModel, ListModelExt { public void sort(Comparator cmpr, boolean ascending) { //do the real sorting //notify the listbox (or grid) that data is changed by use of ListDataEvent } }
当用户向listbox发出排序请求时,listbox将会调用ListModelExt
的sort
方法为数据排序。换句话说,排序是由列表模型处理的,而不是listbox。
排好序之后,列表模型会调用org.zkoss.zul.event.ListDataListener
实例(通过addListDataListener
方法注册到listbox
)的onChange
方法通知listbox。在大多数情况下,所有的数据通常会改变,所以列表模型通常发出下列事件:
new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1)
注:ListModel
和 ListModelExt
的实现与视觉表现是独立的。换言之,它可以被用于grid ,listbox及其它支持ListModel
的任意组件。
换言之,为了获得最大的灵活性,你应该假定不使用组件,而使用ListDataEvent
通信。
理论上,listcell可以包含任意的其它组件,如下所述。
<listbox width="250px"> <listhead> <listheader label="Population"/> <listheader label="Percentage"/> </listhead> <listitem value="A"> <listcell><textbox value="A. Graduate"/></listcell> <listcell label="20%"/> </listitem> <listitem value="B"> <listcell><checkbox label="B. College"/></listcell> <listcell><button label="23%"/></listcell> </listitem> <listitem value="C"> <listcell label="C. High School"/> <listcell><textbox cols="8" value="40%"/></listcell> </listitem></listbox>
注:
若使用grid更好,则不要使用listbox。它们的外观类似,但listbox应仅用于呈现可选项目的列表。
若listbox包括可编辑的组件,例如textbox
和checkbox
,则会引起用户的困惑。一个普遍的问题使,用户在一个未选中的项目内输入文本(A common question is what the text, that a user entered in a unselected item, means).
由于浏览器的限制,用户不能从文本框(text box)内选择一段文字。