JBoss Seam (POJO without EJB) 后台 + ExtJS 前台完整例子(七)
1.引言
网格(Grid)(也有人叫“表格”)是ExtJS的核心器件之一。企业级应用大多数以数据库为中心,网格器件的
使用最为频繁,它的功能强弱直接影响到应用程序的可用性。
本文首先提出对网格器件的功能需求,然后分析ExtJS是如何满足这些需求的,最后介绍本项目中酒店预订界面 对网格器件的应用。
2.用户对网格器件的基本要求
在浏览器界面上使用全功能网格器件,其基本要求如下:
(1)可以在任意位置的某个区域显示。
(2)具备纵向和横向滚动条。横向滚动时,网格列标题行应该同步滚动。
(3)点击列标题,网格内容自动按该列进行排序,排序分为正序和倒序两种,通过点击切换。
(4)可调整列宽度。
(5)可调整列的排列顺序。
(6)可隐藏或显示指定列。
(7)可单选行,也可多选行
(8)能显示行号。
(9)支持Checkbox选择某行或全选。
(10)能实时编辑网格单元中的内容,单元值可以用文本框、下拉列表等多种器件展现。
3.用户对网格器件的高级要求
随着技术的发展,在传统桌面应用软件中,网格器件已经能提供更高级的功能,包括:
(1)锁定指定列。横向滚动时,锁定列内容不滚动。
(2)按指定列对网格内容进行分组显示。
(3)分组后,显示计数、求和等运算的结果。
(4)按指定字段,输入任意值,对网格内容进行筛选。
4.网格视图保存和恢复技术
现代应用软件面对多种屏幕分辨率和不同的布局,在某些场合下,软件规定好某种网格外观后,需要让用户在现场能自由调整。也就是说,用户通过对网格进行列宽度调整、列排列顺序调整、隐藏或显示指定列等操作后,获得自己想要的网格视图格式。应用程序应该对网格视图的状态提供保存和恢复功能。
通过网格视图保存和恢复技术,利用同一个网格可以显示同一个数据源的不同视图。用户只要通过工具条上的下拉菜单,就能切换不同的视图。
5.分页还是不分页
传统桌面应用软件中,由于前后台传输速度快,胖客户端的容纳能力强,往往不需要考虑网格的分页显示。
浏览器应用则要使用分页来显示网格数据。
分页后的网格在某些应用场景下,可能会给用户带来操作上的不便。如果数据量较大,而且又要求不分页,
那么, Live Grid可能是一种比较好的解决方案。
6.ExtJS的网格器件已经可以实现的功能
Ext 2.0 对网格器件进行了很大的改进。它已经完全能满足用户对网格器件的基本要求。它还提供了更高级
的功能:
(1)指定任意列进行分组,并可以在程序中定制分组后显示的信息,包括求和等统计信息, 参见ExtJS发行包中的例子。
(2)ExtJS社区贡献了 网格筛选器,可以实现按指定字段,输入任意值,对网格内容进行筛选。
(3)ExtJS社区贡献了 列锁定功能。
分组后的求和、计数操作,如何让用户自己灵活定义,目前还没有看到这方面的实现。
网格视图保存和恢复,涉及到网格元数据的动态获取和网格状态持久化等方面的技术,这方面的实现也已经很成熟:
(1)ExtJS社区贡献了动态网格( Autogrid ),网格的元数据完全由服务器 端提供,最新版本已经实现了网格状态的持久化保存。
(2)ExtJS社区贡献了 GridStateManager, 它首先实现了网格视图状态的持久化.
7.网格器件的数据源
网格器件的数据源有多种选择, 常用的有下列几种:
(1)JSON
(2)XML
(3)DWR
(4)数组
JSON是最常用的数据源, 在《ext tutorial》的“ 2. 震撼吧!让你知道ext表格控件的厉害。” 中,对这种数据源的具体格式有非常清晰的描述. 本项目就是采用这种数据源方式. 在后续的本系列文章中, 将专门有一篇介绍如何用Servlet实现JSON数据的服务器端实现.
XML也可以作为网格的数据源, 这方面的例子很多, 你可以在ExtJS发行包中找到有关的例子。
如果你使用Java后端, 并且使用DWR, 可以用远程方法返回值直接作为网格的数据源. Ext社区贡献了 DWRProxy , 它实现了DWR返回数据作为数据源的功能.
数组也能方便地作为网格的数据源使用, 程序例子请参见ExtJS发行包。
8.酒店预订界面中的网格器件
在 hotel-list.js 和 booking-list.js 中实现了两个网格. 网格的数据源是JSON格式, 由服务器端Servlet提供. 两个网格 的设计方法类似, 其主要设计手法是:
(1)网格的创建(Create)和展现(Render),分为两个方法分别实现. 先把网格加入布局, 再展现网格, 例如 main.js 中:
oBookingList = Divo.app.BookingList;
oBookingList.init();
bookingGrid = oBookingList.getGrid();
createLayout();
oBookingList.showGrid();
如果在加入布局前就展现网格, 有时无法得到想要的效果.
(2)展现网格后, 订阅下列两个事件, 实现行选择相关的功能:
selModel.on('rowselect', onRowSelect);
ds.on("load", onLoad);
用户点击某个网格行, 或者网格数据重新加载后, 会触发onRowSelect事件处理方法, 它记录当前行的id值到私有属性cId(c表示当前,current), 并且刷新工具条按钮的状态.
数据加载后, 会触发onLoad事件处理方法, 在网格内容为空时, 它负责把私有属性cId设置为null值, 然后再刷新工具条按钮的状态. 有了私有属性cId, 还可以做到数据加载后,当前行不会总是跳转到第1行,而是保持在原来的位置.
在 booking-list.js 中, 你会看到这样的语句:
Divo.subscribe(Divo.msg.BOOKING_ADD,onNewBooking,this);
它的作用是: 新的预订酒店记录保存后(在 booking-form.js 中实现), 自动刷新预订酒店网格中的内容. 这里看到的是订阅语句, 而 在 booking-form.js 中能看到下面的事件发布语句:
Divo.publish(Divo.msg.BOOKING_ADD, {
id : retValue
});
divo.js 中对PageBus的订阅和发布方法进行了封装. 关于 PageBus 的详细说明, 请参见我的 这篇博客文章.
9.结语
ExtJS网格器件在功能、外观和性能等方面堪称一流, 而且有活跃和强大的社区力量的支持, 掌握并灵活运用它是ExtJS开发人员必备的技能.
附:下面是本系列所有文章的完整列表:
(1) 下载示例项目并安装运行
(2) 建立Eclipse开发环境
(3) 熟悉项目中与JSF相关内容
(4) 重新认识JS
(5) ExtJS之表单(Form)
(6) ExtJS之布局(Layout)
(7) ExtJS之网格(Grid)
(8) Java后台和前台的通讯机制
(9) Seam框架简化Java开发
(10) 分层架构设计
(11) 安全性
(12) 单元测试