Chapter10
Scrollable Data Table and Tree
1.
<rich:scrollableDataTable>
1)
<rich:scrollableDataTable>
也是一个
dataTable
类的控件。不过,它提供了一些额外的附加功能:
l
当表格滚动时,通过
Ajax
从
Server
取得数据行;
l
可以一次性选中多个行;
l
可以任意调整列的宽度;
l
可以设定冻结列;
l
可以轻易的实现排序;
2)
Ajax
滚动数据表格
l
通过
width
和
height
属性定义表格外观尺寸;
l
通过
rows
属性,定义一次性用
Ajax
取回的行数;
l
<rich:scrollableDataTable>
需要在
form
里,才能实现
Ajax
取回数据行;
l
另外,根据我的实验,最好把
sortMode
、
rowKeyVar
等属性设置齐全一些,否则有时外观刷新不正常,比如调整列宽时。
3)
调整列宽度
不用做额外的操作,只是调整
column
的
header
宽度就好,在每次
Request
之间,系统会自动记住列宽。
4)
设定冻结列
使用
frozenColCount
属性,可以定义表格最左边多少列会被冻结,在横向滚动的时候,不会运动。
5)
选中多行
l
需要用到
selection
属性和
binding
;
l
selection
属性应该指向
managed bean
中的一个实现了
org.richfaces.model.selection.Selection
接口的对象,通常可以直接使用
org.richfaces.model.selection.SimpleSelection
类对象(
SimpleSelection
实现了
Selection
接口)。
l
binding
应该指向
managed bean
中的
UIScrollableDataTable
对象。
l
基本原理:在
browser
端,用户选定多行数据,通过提交(
Ajax
或
Server
),
Server
端更新
Selection
的值,再解析
Selection
的值,查看每一个
rowKey
在
table
中是否可用,从而取得
table
对应行中的数据。
l
具体实现:
<rich:scrollableDataTable
value="#{dataTableScrollerBean.xcvrList}" var="xcvr"
rows="20" height="300px" width="400px" sortMode="single"
rowKeyVar="rkv" frozenColCount="1" binding="#{dataTableScrollerBean.table}" selection="#{dataTableScrollerBean.selection}"
>
<a4j:support
event="onselectionchange
"
reRender="out1" actionListener="#{dataTableScrollerBean.takeSelection}"
></a4j:support>
<rich:column id="itemCode">
<f:facet name="header">
<h:outputText value="Item Code" />
</f:facet>
<h:outputText
value="#{xcvr.itemCode}"></h:outputText>
</rich:column>
……
</rich:scrollableDataTable>
<h:outputText id="out1"
value="#{dataTableScrollerBean.selectedXcvrs}">
private
UIScrollableDataTable table;
private
SimpleSelection selection;
private
List<Xcvr> selectedXcvrs = new ArrayList<Xcvr>();
// Getter
and Setter for above 3 member variables.
……
public void
takeSelection(ActionEvent evt) {
selectedXcvrs.clear();
Iterator<Object> it =
selection.getKeys();
while(it.hasNext())
{
table.setRowKey(it.next());
if(table.isRowAvailable()
) {
selectedXcvrs.add((Xcvr)table.getRowData()
);
}
}
}
在
JSP
页面里通过
<a4j:support>
,在发生
onselectionchange
事件的时候,发起提交,调用
managed
bean
的
actionListener
方法
takeSelection()
。
在
managed
bean
的
takeSelection
方法里,首先使用
Selection
的
getKeys
方法,返回一个
Iterator<Object>
;然后遍历,将这个
Iterator<Object>
中的每一个
Key
,通过
UIScrollableDataTable
的
setRowKey
方法设为当前
Key
;如果
UIScrollableDataTable
的
isRowAvailable()
方法为真,即当前行数据可用,则通过
getRowData()
方法加
Casting
操作,获得对应的数据对象。
6)
实现排序
l
设定
sortMode
属性,两种选择:
single
或
multy
;
l
<rich:column>
的
id
必须与
column
中的数据对象的属性名相对应,即:
<rich:column id="itemCode
">
<f:facet name="header">
<h:outputText value="Item Code" />
</f:facet>
<h:outputText value="#{xcvr.itemCode
}"></h:outputText>
</rich:column>
l
如果无法实现对应(如
column
中包含多个属性值的联合),则必须给
<rich:column>
加上
sortBy
属性,如:
<rich:column id="c1" sortBy=”#{xcvr.itemCode}”
>
<f:facet name="header">
<h:outputText value="Item Code / Tech" />
</f:facet>
<h:outputText value="#{xcvr.itemCode}, #{xcvr.tech}
"></h:outputText>
</rich:column>
2.
关于
dataTable
的
sort
和
filter
我曾在第
7
章,对于数据表的排序、筛选留有疑问。通过上面的排序实现和用户指南,大致有了了解:
1)
在
<rich:dataTable>
中设定好
sortMode
;
2)
在
<rich:column>
中设置好
sortBy
和
filterBy
属性:
<rich:column id="itemCode" sortBy="#{xcvr.itemCode}"
filterBy="#{xcvr.itemCode}"
>
<f:facet name="header">
<h:outputText value="Item
Code"></h:outputText>
</f:facet>
<h:outputText id="out1"
value="#{xcvr.itemCode}"></h:outputText>
</rich:column>
3)
用户指南在
<rich:column>
的章节有详细的介绍。
3.
<rich:tree>
1)
<rich:tree>
控件用来显示具有层级关系的内容。它的
value
属性接受的是
TreeNode
(
org.richfaces.model.TreeNode
)接口的对象,当然也可以直接使用
TreeNode
的实现类
org.richfaces.model.TreeNodeImpl
。
2)
TreeNode
与
TreeNodeImpl
的主要
API
方法:
l
public
void addChild (java.lang.Object identifier, TreeNode
<T
> child)
此方法用于为
Node
节点添加子节点,参数
identifier
用于标识符,区分子节点;
l
public
void setData(T
data)
此方法用于设置
Node
节点自身所包含的数据。可以是任意类型的。
3)
通常可以使用递归的方法,生成节点树,比如文件树等。
public void createTree() {
FacesContext
context = FacesContext.getCurrentInstance();
ExternalContext
externalContext = context.getExternalContext();
File rootDir
= new File(((ServletContext) externalContext.getContext()).getRealPath("/"));
root = new
TreeNodeImpl<File>();
addNodes(rootDir,
root);
}
public void addNodes(File file, TreeNode<File> node)
{
int count =
1;
//
为当前节点设置
Data
,即将当前目录设为当前节点的数据内容
node.setData(file);
//
遍历子文件和子目录
for (File
childFile : file.listFiles()) {
TreeNodeImpl<File>
childNode = new TreeNodeImpl<File>();
if (childFile.isFile()) {
//
如果为单个文件,则作为子节点数据内容
childNode.setData(childFile);
} else {
//
如果为目录,则递归生成子节点树
addNodes(childFile, childNode);
}
//
将子节点或字节点树加入当前节点
node.addChild(count++, childNode);
}
}
4)
将整个节点树的根节点,传入
<rich:tree>
的
value
属性。
<rich:tree
value="#{treeTestBean.root}"
/>
5)
<rich:tree>
应置于
form
中使用,并且有三种切换模式
switchType
:
l
Ajax
(默认):通过
Ajax
提交实现,每次展开闭合都会引起
Ajax Request
;
l
Server
:引起常规提交;
l
Client
:
所有操作只基于
Client
端
,
与
Server
没有交互。
6)
关于处理选择节点事件:
l
ajaxSubmitSelection
属性为
true
的话,选择节点时,提交方式为
Ajax
。
l
managed
bean
中应该定义一个型为
public void
selectionListener(NodeSelectedEvent
event)
的方法。
l
<rich:tree>
的
nodeSelectListener
属性应该指向这个
Listener
方法。
l
例如:
public void
selectionListener(NodeSelectedEvent evt
)
throws IOException {
UITree
tree = (UITree) evt.getComponent();
File
file = (File) tree.getRowData();
nodeTitle =
file.getName();
}
通过
NodeSelectedEvent
的
getComponent
方法获得产生该节点选择事件的
Tree
控件(这与
ActionEvent
的
getComponent
方法类似)。通过
UITree
的
getRowData
方法,返回当前节点自身包含的数据内容。
7)
关于处理展开闭合事件:
l
managed
bean
中应该定义一个型为
public void
expansionListener(NodeExpandedEvent
evt)
。
l
<rich:tree>
的
changeExpandListener
属性应该指向这个
Listener
方法。
l
例如:
<rich:tree
value="#{treeTestBean2.root}" nodeSelectListener="#{treeTestBean2.selectionListener}"
changeExpandListener="#{treeTestBean2.expansionListener}"
ajaxSubmitSelection="true" reRender=”out1” />
8)
可以使用
icon, iconCollapsed, iconExpanded, iconLeaf
属性修改不同节点不同状态下的图标样式。
9)
使用