说实话, 我也是特别懒的人, 很早就想看看 Ext, 尤其是做一个实时编辑的带后台的表格例子, 一直没能深入, 今天抽时间深入看了看 Ext 的 EditorGrid,可编辑的表格控件,总算凑出来了个实时增删改的例子(不单独弹出添加对话框的那种),带用DWR 1 (不用DWR 2 是因为2个头太大了)开发的后台服务器端,没有整合Spring,JPA啊,Struts,Hibernate等等的流感框架, 这样总的代码非常的小,省得当大家接触到了一些大量的自己不熟悉的框架的时候会产生发晕的感觉,而且那样下来整个例子的源码会远远超过1MB,发布的包更是估计要超过5MB了. 在此之前上网找了好多资料, 然而大部分都是基于 Ext 1 开发, 而 2.0 的呢, 大多又找不到源码下载, 而且其类库比较复杂, 所以今天做它是花了一番功夫,不过当最后的结果出来后, 一切辛苦都显的那么值得了, 学技术,归根到底就是一种学习和总结的能力,您觉得是不是呢(我说的不是发明技术,那个我做不来)?
广告: 如果您或者您所在公司需要 Java EE 或者 AJAX 方面的技术顾问或者培训服务,欢迎联系本人!
您可以查看在线演示(不带服务器端代码): http://beansoft.java-cn.org/ajax/extgrid/
源代码下载(带完整注释): http://beansoft.java-cn.org/ajax/extgrid/extdwrgrid.zip 778 KB
视频下载: http://beansoft.java-cn.org/ajax/extgrid/ext.exe 16.1 MB 43分44秒
运行效果:
服务器的输出:
添加用户 新用户3, 地区:北京
修改用户 4的字段:area, 值为:河南南阳
修改用户 1的字段:email, 值为:beansoft@126.com22
修改用户 3的字段:email, 值为:aa@bb.com22
删除用户 2
核心的代码(无DWR部分,便于大家自测,注意先把Ext类库所在的目录改对了就可以了):
页面的(注意编码是 UTF-8):
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>表格编辑器示例</title>
<link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css" />
<!-- 图标样式 CSS 信息 -->
<link rel="stylesheet" type="text/css" href="edit-grid2.css" />
<!-- GC -->
<!-- LIBS -->
<script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
<!-- ENDLIBS -->
<script type="text/javascript" src="ext/ext-all.js"></script>
<!-- 中文提示信息支持 -->
<script type="text/javascript" src="ext/source/locale/ext-lang-zh_CN.js"></script>
<!-- 本页的功能代码 -->
<script type="text/javascript" src="edit-gridnojava.js"></script>
<!-- DWR JavaScript 类库 -->
<script type='text/javascript' src='/dwrtest/dwr/interface/JUserManager.js'></script>
<script type='text/javascript' src='/dwrtest/dwr/engine.js'></script>
</head>
<body>
<h1>Ext 2.0 & DWR 1表格实时编辑器示例(无Java服务器端)</h1>
<p>这个例子展示了如何创建可编辑的表格控件.</p>
<p>注意脚本没有压缩, 因此便于读者阅读. 点击浏览 <a href="edit-gridnojava.js">edit-gridnojava.js</a>.</p>
<p>表格的数据文件加载自 <a href="users.xml">users.xml</a>.</p>
<!-- 这个默认不显示的下拉选择框必须在这里定义, 因为'地区'列的编辑器需要用它在这里取值 -->
<select name="area" id="area" style="display: none;">
<option value="北京">北京</option>
<option value="河南南阳">河南南阳</option>
<option value="河北涿州">河北涿州</option>
</select>
<!-- 放置可编辑控件的 DIV -->
<div id="editor-grid"></div>
作者: 刘长炯<br>
邮件: beansoft@126.com<br>
博客: <a href="http://beansoft.blogjava.net/">http://beansoft.blogjava.net/</a><br>
2008-01-27<br>
本页面和JS的编码都是 UTF-8.
</body>
</html>
CSS(自己把图放进去就好了) editor-grid2.css:
/** 定义了一些工具栏按钮的 CSS 样式 */
.add {
background-image:url(./images/add.gif) !important;
}
.remove {
background-image:url(./images/delete.gif) !important;
}
.details {
background-image:url(./images/details.gif) !important;
}
.user-delete {
background-image:url(./images/user_delete.gif) !important;
}
以及数据文件 users.xml
<?xml version="1.0" encoding="GBK"?>
<users>
<user>
<id>1</id>
<name>刘长炯</name>
<area>河南南阳</area>
<email>beansoft@126.com</email>
<age>28</age>
<sex>true</sex>
<birth>1980/01/01</birth>
</user>
<user>
<id>2</id>
<name>BeanSoft</name>
<area>北京</area>
<email>beansoft@126.com</email>
<age>28</age>
<sex>true</sex>
<birth>1980/01/01</birth>
</user>
<user>
<id>3</id>
<name>MM</name>
<area>河北涿州</area>
<email>aa@bb.com</email>
<age>22</age>
<sex>false</sex>
<birth>1985/01/01</birth>
</user>
</users>
后台的Java类,很简单的模拟数据库操作:
/**
* 基于 DWR 的用户管理类示例, 数据库操作和数据传输协议的选择可以根据情况自行加入,
* 推荐 JPA + JSON 或者 Hibernate + XML.
*
* @author BeanSoft
* 2008-01-27
*/
public class UserManager {
private int counter = 3;
/**
* 虚拟的添加用户功能.
* TODO: 封装并传递所有参数.
* @param username 用户名
* @param area 地区
* @return 新的数据ID
*/
public int addUser(String username, String area) {
System.out.println("添加用户 " + username + ", 地区:" + area);
return ++counter;
}
/**
* 虚拟的删除用户操作.
* @param userid 用户编号
* @return 成功或者失败
*/
public boolean removeUser(int userid) {
System.out.println("删除用户 " + userid);
return new java.util.Random().nextBoolean();
}
/**
* 虚拟的修改用户操作.
* @param userid 用户编号
* @param field 改变的字段
* @param newValue 新的取值
* @return 是否更改成功
*/
public boolean editUser(int userid, String field, String newValue) {
System.out.println("修改用户 " + userid + "的字段:" + field + ", 值为:" + newValue);
// 模拟网络延迟, 停2秒
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new java.util.Random().nextBoolean();
}
/**
* 虚拟的删除所有用户的操作.
* @return 是否成功
*/
public boolean removeAllUser() {
return new java.util.Random().nextBoolean();
}
}
DWR的配置文件 dwr.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<init>
</init>
<allow>
<!-- 将 Java 类 UserManager 映射为 JavaScript 里面的对象 JUserManager -->
<create creator="new" javascript="JUserManager" scope="application">
<param name="class" value="UserManager"/>
</create>
</allow>
<signatures>
<![CDATA[
import java.util.*;
import uk.ltd.getahead.testdwr.*;
]]>
</signatures>
</dwr>
最后,核心的 JS 文件
edit-gridnojava.js
/*
* Ext JS Library 2.0.1
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
/**
* 无 DWR Java 后台静态页面演示版本.
* 简体中文 Demo 制作: 刘长炯 beansoft@126.com
* http://beansoft.blogjava.net/
*/
Ext.onReady(function(){
Ext.QuickTips.init();
// 格式化日期显示
function formatDate(value){
return value ? value.dateFormat('Y, M d') : '';
}
// 格式化性别显示,这是个 renderer, 渲染器
function formatSex(value) {
return value ? "男" : "女";
}
// 弄个缩写的别名
var fm = Ext.form;
// 列模型定义了表格所有列的信息,
// dataIndex 将特定的列映射到数据源(Data Store)中的数据列(在后面创建)
var cm = new Ext.grid.ColumnModel([
{
id:'id',
header: "编号",
dataIndex: 'id',
width: 50
},
{
id:'name',
header: "用户名",
dataIndex: 'name',
width: 250,
editor: new fm.TextField({
allowBlank: false// 不能为空
})
},
{
header: "地区",
dataIndex: 'area',
width: 100,
editor: new Ext.form.ComboBox({
typeAhead: true,
triggerAction: 'all',
transform:'area',// 对应的选择框的ID
lazyRender:true,
listClass: 'x-combo-list-small'
})
},
{
header: "电子邮件",
dataIndex: 'email',
width: 220,
align: 'left',
editor: new fm.TextField({
allowBlank: true
})
},
{
header: "年龄",
dataIndex: 'age',
width: 70,
align: 'right',
editor: new fm.NumberField({
allowBlank: true,
allowNegative: false,
maxValue: 100
})
},
{
header: "生日",
dataIndex: 'birthDay',
width: 95,
renderer: formatDate,
editor: new fm.DateField({
format: 'y/m/d',
minValue: '1970/01/01',//最小值
disabledDays: [0, 6],// 禁止选择的日期
disabledDaysText: '不许周末出生孩子'
})
},
{
header: "性别",
dataIndex: 'sex',
width: 95,
renderer: formatSex,
editor: new fm.Checkbox()
}
]);
// 默认情况下列是可排序的
cm.defaultSortable = true;
// 定义一个用户对象,这样便于我们动态的添加记录,虽然也可以设置成匿名内置对象
var User = Ext.data.Record.create([
// 下面的 "name" 匹配读到的标签名称, 除了 "birthDay",它被映射到标签 "birth"
{name: 'id', type: 'int' },
{name: 'name', type: 'string'},
{name: 'area'},
{name: 'email', type: 'string'},
{name: 'age', type: 'int'}, // automatic date conversions
{name: 'birthDay', mapping: 'birth', type: 'date', dateFormat: 'Y/m/d'},
{name: 'sex', type: 'bool'}
]);
// 创建 Data Store
var store = new Ext.data.Store({
// 使用 HTTP 加载
url: 'users.xml',
// 因为返回值是 XML, 所以我们创建一个解析器
reader: new Ext.data.XmlReader({
// 记录必须包含 "user" 标签
record: 'user'
}, User),
sortInfo:{field:'name', direction:'ASC'}// 排序信息
});
// 创建编辑器表格
var grid = new Ext.grid.EditorGridPanel({
store: store,
cm: cm,
renderTo: 'editor-grid',
width:800,
height:300,
autoExpandColumn:'name',
title:'用户管理',// 标题
frame:true,
clicksToEdit:1,//设置点击几次才可编辑
selModel: new Ext.grid.RowSelectionModel({singleSelect:false}),//设置单行选中模式, 否则将无法删除数据
// 顶部工具栏按钮
tbar: [
{
text: '添加用户',
iconCls:'add',//按钮图标的CSS名称
handler : function(){// 点击按钮执行的操作
var n = grid.getStore().getCount();// 获得总行数
var p = new User({
id: n + 1,
name: '新用户' + n,
area: '北京',
email: 'beansoft@126.com',
age: 20,
birthDay: (new Date()).clearTime(),
sex: true
});
grid.stopEditing();// 停止编辑
store.insert(n, p);// 插入到最后一行
grid.startEditing(n, 1);// 开始编辑1单元格
}
},
{
text: '查看所选',
iconCls: 'details',
handler : function(){
var recordtoedit = grid.getSelectionModel().getSelected();// 返回值为 Record 类型
if(recordtoedit) {
Ext.Msg.alert('查看选中', "您现在选中的用户其名字为:" + recordtoedit.get("name"));// 取得用户名
// alert("您现在选中的用户其名字为:" + recordtoedit.get("name"));
}
}
},
{
text: '删除所选',
iconCls:'remove',
handler : function(){
var record = grid.getSelectionModel().getSelected();// 返回值为 Record 类型
if(!record){
Ext.Msg.alert("提示","请先选择要删除的行!");
return;
}
// 弹出对话框警告
if(record) {
Ext.MessageBox.confirm('确认删除',
'你真的要删除所选用户吗?',
function(btn) {
if(btn == 'yes') {// 选中了是按钮
// 更新界面, 来真正删除数据
store.remove(record);
}
}
);
}
}
},
{
text: '删除所有',
iconCls: 'user-delete',
handler : function(){
Ext.MessageBox.confirm('确认删除',
'你真的要删除所有用户信息吗?',
function(btn) {
if(btn == 'yes') {// 选中了是按钮
// 更新界面, 来真正删除数据
store.removeAll();
}
}
);
}
}
]
});
// 单元格编辑后事件处理
grid.on("afteredit", afterEdit, grid);
// 事件处理函数
function afterEdit(e) {
var record = e.record;// 被编辑的记录
// 显示等待对话框
Ext.Msg.wait("请等候", "修改中", "操作进行中...");
// 更新界面, 来真正删除数据
Ext.Msg.alert('您成功修改了用户信息', "被修改的用户是:" + e.record.get("name") + "\n 修改的字段是:"
+ e.field);// 取得用户名
};
// 触发数据加载
store.load();
});