今天在java中使用jxl导出数据到excel工作表的时候,无论是在线直接打开还是保存到本地再打开,都会提示下面的错误信息:
“Excel在‘excel.xls'中发现不可读取的内容。是否恢复此工作薄的内容?如果信任此工作薄的来源,请单击‘是’。”
“修复到“excel.xls”
通过修复或删除不可读取的内容,Excel已能够打开该文件。
重新命名无效的工作表名称。
......
单击查看修复记录:C:\Users\dragon\AppData\Local\Temp\error069320_01.xml
”
截图如下:
工作环境:WIN7 64位 + MyEclipse6.5 + jxl
在百度、google搜索了一番,都没有找到答案,后来跟踪代码突然发现,原来自己写入excel是通过一个for循环来实现的。
在循环中对同名的工作表进行了重复定义与赋值,导致了这个问题的发生。
“重新命名无效的工作表名称。”出现几行就证明重写了几个WritableSheet。例如我这里出现了8次,就是在for循环内重写了8次excel的工作表。代码如下:
WritableWorkbook wwb = Workbook.createWorkbook(response.getOutputStream());
for(int i=0; i<size; i++){
.......
WritableSheet ws = wwb.createSheet(name, num);
......
}
后来对上面的代码进行改造,取消了循环,就正常了。
这个问题的关键在于在for循环内定义了同名的WritableSheet,才导致这个问题的出现。
dojo.isString(test): 当test为字符串字面量或者字符串对象时,返回true
dojo.isFunction(test): 当test为函数或者继承自函数时, 返回true
dojo.isObject(test): 当test为null, 数组, 对象和函数时返回true(不包括字符串)
dojo.isArray(test): 当test为数组或者继承自数组时返回true
dojo.isArrayLike(test): 当test包含一个有限长度的非字符串, 非数组, 非函数,非DOM节点的属性时,返回true
dojo.isAlien(test): 当test本应被报告一个为函数而实际上没有时返回true
本文链接
DOM事件编程
事件接口,所有属性为只读属性
键盘事件
dojo.keys的属性值:
事件传播
eventObj.stopPropagation()来阻止事件的传播,不论是冒泡还是捕获
默认事件
eventObj.preventDefault()来阻止默认事件
dojo.stopEvent(eventObj)相当于一次调用上面两个函数
关联处理函数
handle = dojo.connect(objDOM, event, context, handler):
objDOM是一个DOM节点, event表示一个事件的字符串(如:"click"), context表示处理函数执行上下文(可选), handler事件处理函数。
使用时要注意:
1 处理函数中的this 只等于context
2 一个DOM节点可以通过connect关联多个事件,但这些事件不一定书写顺序执行,若果确实要这样,应将他们全部放到另一个函数中。
初始化事件
dojo.addOnLoad(): 该函数的调用示例如下:
dojo.addOnLoad(function() {...});
dojo.addOnLoad(o, "f");//函数o["f]
dojo.addOnLoad事件可以别调用多次,而且严格按照顺序执行,其触发的条件是:
1 DOM树已经构建
2 dojo.require加载的资源已经全部加载
3 dojo小部件已经全部解析
也可以使用dojo.loaded()函数达到同样的效果
dojo事件框架
1 使用dojo.connect/dojo.disconnect关联取消事件
2 使用target/currentTarget获取事件原始节点和当前事件节点
3 增加了键盘事件
4 使用dojo.addonLoad进行初始化操作
5 事件处理函数通常接受一个与事件相关的事件对象作为参数
6 能冒泡的通常冒泡,而捕获阶段通常被禁止。
以上所列内容和浏览器无关
dojo事件框架支持的事件
利用dojo关联用户自定义事件
首先我们来看浏览器如何触发事件,当用户点击鼠标的时候,就有一个消息被插入队列,浏览器从队列中取出一个消息并调用一个函数,这个被调用的函数(称为触发函数)就是"事件", 该出发函数就调用事件处理函数。dojo.connect就是遵循这个机制,它可以将事件处理函数关联到任何函数上。
我们来看一个例子
var g = f;
f = function() {
var result = g.apply(this, argument);
console.log("hello, world!");
return result;
}
g保存了f的引用,然后f被定义成了新的函数,这个新的函数调用了g函数(也就是原来的函数f)。在这里,新定义的f函数就相当于触发函数,而dojo.connect就是采用了这种方式:
console.log("Hello, world");
}
var myHandler = function() {
console.log("I'm Handler");
}
dojo.connect("f", myHandler);
这样,函数f会被重新定义,然后再新f里面调用myHandler函数。此时,当你调用函数f(相当于"事件"被触发), 会先执行原来的函数f,在执行myHandler函数(相当于事件处理函数被调用),控制台输出"Hello, world" "I'm Handler"。
关联自定义事件的规则:
1 如果dojo.connect的obj参数为DOM对象,那么event(字符串)一定要是DOM事件
2 如果dojo.connect的obj参数为null或者缺失,那么dojo.global[event(字符串)]要是一个函数,来作为触发函数
3 如果dojo.connect的obj参数为非DOM对象,那么event(字符串)要是这个obj的属性(即obj[event],并且为一个函数作为触发函数)
用户自定义事件和DOM事件的一个不同是,dojo.connect仍然可以在一个事件上关联多个事件处理函数,但是这些事件处理函数严格按照书写顺序执行。
发布者和订阅者
handle = dojo.subscribe(topic, context, handler): 当dojo.publish(topic)是,有dojo.hitch(context, handler)被调用。topic为发布的主题,为一个字符串。这个函数就是让handler"订阅"发布者的主题topic。
dojo.unsubscribe(handle): 删除有dojo.subscribe建立的链接,handle是上面函数的返回值
dojo.public(topic, args): 发布者发布主题topic, args为一个数组,里面的元素将依次传递给所有的订阅者函数handler。
这些订阅者函数按照订阅的次序依次执行。如: