`
abruzzi
  • 浏览: 444551 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Swing小应用(Todo-List)之三

阅读更多

前言

去年9月份开发的那个小工具sTodo,只是做到了能用,但是还很不好用,比如没有定时的提醒功能,整个框架比较死板,不方便扩展,虽然设计之初就考虑要使用脚本语言进行脚本化,提供更强的定制能力,但是一直因为工作上事情太多,没有经历投入而悬停。

 

不明真相的可以参看以前的两篇文章:

Swing小应用(Todo-List)之一

Swing小应用(Todo-List)之二

 

sTodo的现状

sTodo内部用了一套任务管理模块,可以做到定时提醒的功能,效果还是不错的:


虽然UI还很原始,但是基本功能都已经实现,剩下就是美化UI了。另外,插件系统也基本可用,后台使用JavaScript作为脚本语言,并使用rhino引擎解释。可以看一个例子:

 

 

/*
 * put all initialize code here
 */
function _init_(){
	var app = application;
	var ui = app.getUI();
	
	//set look and feel to windows
	ui.setLookAndFeel("windows");
	
	//load some new scripts
	app.activePlugin("scripts/help.js");
	app.activePlugin("scripts/util.js");
	
	var menubar = ui.getMenuBar();
	//menubar.add(new menu("", "", ""))
	//launch the main frame
	app.launch();
}

 

 

而同时在Java代码中,将application(STodo的实例)作为变量传递给脚本,就可以实现两者的通信了:

 

 

	public static void main(String[] args){
		STodo sTodo = new STodo(new MainFrame("My todo list"));
		sTodo.initEnv();
		Plugin system = TodoPluginManager.getInstance().getPlugin("system");
		system.putValueToContext("application", sTodo);
		system.execute("_init_", new Object());
	}

 

 

比如,上边的JavaScript代码中的这一句:

 

ui.setLookAndFeel("windows");

 

 表示,将界面风格设置为windows主题,而:

 

ui.setLookAndFeel("motif");

 

 表示,将界面风格设置为motif主题,就是SUN的那个solaris系统的默认风格。两者的对比如下:

 

 



 


 

关于脚本化Java,还可以参考这篇文章,是我之前发表在IBM Developerworks上的:

使用 JavaScript 脚本化 Java 应用 其中使用的例子就是这个sTodo.

目标

后边需要加入更多的内容,下面是一个列表:

 

 

  • 插件机制,包括暴露更多,更方便的全局引用给用户,方便定制
  • 提供更方便的编辑方式
  • 提供更灵活的日期格式,比如:明天晚上,这个周末,5分钟后等自然语言来定制提醒时刻
  • UI的完善,使得sTodo成为一个高可用的应用程序

如果你有更好的建议,无论是UI方面的还是程序设计方面的,欢迎讨论之至。

 

 

更新

最近离职了,新的公司要到5月10号左右去报到,因此有大量的时间来做sTodo后边的完善工作,经过近一周的重构,现在的sTodo已经基本可用了。正如上文中的目标部分列出来的项目,现在已经完成的己有:

 

  • 暴露了大部分UI组件
  • 暴露了更多的API,比如通过脚本插入新的待办事项,发送邮件等
  • 日期更加灵活,使用的是一个JavScript库(http://www.datejs.com/),这个库的发现,对sTodo来说,简直是雪中送炭
  • UI部分的美化,现在还没有做到,这个后期有时间再来慢慢修改
现在根据一些细节来说明本次的更新:
在Java代码中,Java唯一知道的是system.js这个脚本,system.js会加载其他的脚本,进行一些初始化,然后调用java端暴露出来的launch方法启动整个应用。

function main(){
	var app = Application;
	var ui = app.getUI();
	
	//set look and feel to windows
	ui.setLookAndFeel("windows");
	
	//load some new scripts
	app.activePlugin("scripts/json.js");
	app.activePlugin("scripts/date.js");
	app.activePlugin("scripts/util.js");
	app.activePlugin("scripts/menubar.js");
	app.activePlugin("scripts/misc.js");
	
	app.launch();
	//loadTodosFromFile("todos.txt");
}
 Application对象就是整个sTodo的引用,activePlugin(filename)方法会加载其他脚本并执行,上边的代码中可以看到,加载的有数据交换必须的json.js,日期格式分析的data.js,以及一些工具的定义util.js,还有UI方面的menubar.js,最后是杂项misc.js。加载完成之后,调用Application的launch方法启动应用。

值得一提的是,之前使用jQuery的extend方法,觉得非常好,特别在处理配置的时候,然后直接从jQuery中抽取出该方法:

var jQuery = jQuery || {};
jQuery.extend = function() {
	// copy reference to target object
	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction(target) )
		target = {};

	// extend jQuery itself if only one argument is passed
	if ( length == i ) {
		target = this;
		--i;
	}

	for ( ; i < length; i++ )
		// Only deal with non-null/undefined values
		if ( (options = arguments[ i ]) != null )
			// Extend the base object
			for ( var name in options ) {
				var src = target[ name ], copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy )
					continue;

				// Recurse if we're merging object values
				if ( deep && copy && typeof copy === "object" && !copy.nodeType )
					target[ name ] = jQuery.extend( deep, 
						// Never move original objects, clone them
						src || ( copy.length != null ? [ ] : { } )
					, copy );

				// Don't bring in undefined values
				else if ( copy !== undefined )
					target[ name ] = copy;

			}

	// Return the modified object
	return target;
};
 并将其定义在util.js中,然后在函数中调用它:
function createNewTodo(def){
	var item = {
			desc : "short description",
			type : "node",
			timeout : "now +5 min",
			period : "never",
			status : "new",
			note : "long message type here."
		};
		
	item = jQuery.extend(item, def);
	return item;	
}
 这样,我就可以很随意的定义新的todo了:

function insertNewTodo(def){
	//the default new to-do template
	var item = createNewTodo(def);
	DataModel.addItem(JSON.stringify(item));
}

insertNewTodo({desc : "Gonna to kill bill", timeout : "tomorrow 10 am" });
insertNewTodo({desc : "Relive bill killed", timeout : "5/1 9 pm" });
 因为jQuery的extend的特性:有就替换,没有的话,就加入,因此用来处理传入参数非常方便。当然,jQuery的extend不止是这些功效,它还有更强大的地方,如深度扩展,不过暂时不做讨论。上边的代码就可以向sTodo中插入两个新的todo了。发送邮件的代码跟创建新的todo非常类似,就不一一列举了,感兴趣的话可以到sTodo的网站上下载代码做测试,sTodo托管在Google code上:https://code.google.com/p/stodo/

另一个比较有意思的地方是关于菜单的定义上,我们可以定义一个类,专门用于创建菜单,当然是用JavaScript那种方式:

var STodoMenuItem = function(text, icon, func){
	this.menu = new JMenuItem();
	this.menu.setText(text);
	if(icon){
		this.menu.setIcon(new ImageIcon(icon));
	}
	if(func){
		this.click(func);
	}
};

STodoMenuItem.prototype.click = function(func){
	this.menu.addActionListener(
		new JavaAdapter(
			ActionListener, {
				actionPerformed : func
			}
		)
	);
};

STodoMenuItem.prototype.getMenuObject = function(){
	return this.menu;
}
 
这样定义之后,使用的时候就与前端的JavaScript操作非常类似了:

	var menu = new STodoMenuItem("test", "imgs/plugin.png");
	menu.click(function(){
		alert("tomorrow is another day");
	});
	
	menuHelp.add(menu.getMenuObject());
 比如,这个click方法,完全就是参照jQuery对象的那种写法,效果如下:


 当然,这里的Alert并非DOM中的window的属性,而是重新定义的,使用Swing的弹出对话框实现的:

//show the message as a message dialog
function alert(message){
	JOptionPane.showMessageDialog(
			null, 
			message, 
			"Alert", 
			JOptionPane.INFORMATION_MESSAGE);
}
好了,这一篇就先说这么多,代码开发之余,写写文档也是不错的。如果有下一篇,就讲讲sTodo中的任务调度部分,这是整个sTodo的核心。 

 

  • 大小: 8.6 KB
  • 大小: 15.7 KB
  • 大小: 32.2 KB
  • 大小: 35.3 KB
  • 大小: 23.3 KB
分享到:
评论
8 楼 BarryWei 2010-05-27  
这个To-do List想办法和Google的Calender实现链接就好了。
楼主可否尝试?
7 楼 abruzzi 2010-04-30  
childrentown 写道
你的JavaScript内核系列写完了没有?怎么又开始捣鼓Swing了?呵呵。

呵呵,怎么说呢,这两个是相辅相成的,而且这段时间我的时间比较多,正好完善一下sTodo,第一个介绍sTodo的帖子是09年9月的,已经拖了半年天气了。sTodo涉及到了JavaScript在Java平台中的应用,也算是《JavaScript内核》的一个实例,应该不冲突吧?
6 楼 childrentown 2010-04-30  
你的JavaScript内核系列写完了没有?怎么又开始捣鼓Swing了?呵呵。
5 楼 abruzzi 2010-04-30  
λ-lambda 写道
看了看lz的sTodo最新版本的代码,感觉挺好的,特别是将JavaScript嵌入到Java中,这种模式非常好。


嗯,我也觉得这种模式很有搞头,现在手头上有个小项目,准备将Java的一些基本的东西包装成方便JavaScript调用的形式,使得用JavaScript充分利用Java的好处,进行更方便的应用程序开发。设想一下:
import("scripts/io.js");
import("scripts/net.js");

function jsTest(){
    var s = Bios.open("file.txt");
    var buffer = null;
    buffer = s.readLine();
    //do something with the line.
     s.close();
}



诸如此类的,那样的话,开发起来可以充分利用JS的一些特性,又可以借助Java中强大的类库支持,将会是一个很有意思的方向。
4 楼 λ-lambda 2010-04-30  
看了看lz的sTodo最新版本的代码,感觉挺好的,特别是将JavaScript嵌入到Java中,这种模式非常好。
3 楼 abruzzi 2010-04-30  
greatghoul 写道
用javascript做脚本语言?有意思,研究下。

有没有办法直接在HTML页面里面利用 JavaScript与Java通信,比如说读写文件,邮件什么的。


直接用客户端的JavaScript来做IO之类的恐怕不行,因为有安全方面的考虑,不过可以使用如lambda兄提到的这种方式:在Server端运行JavaScript来做相同的事情,脚本语言的好处在于不用编译,动态性,开发效率高。

不过要说这两者通信来完成IO/mail的话,可以看看这个:
http://directwebremoting.org/dwr/index.html
引用
DWR is a Java library that enables Java on the server and JavaScript in a browser to interact and call each other as simply as possible
.
不过我没有尝试过这个框架,只是推荐,呵呵。
2 楼 λ-lambda 2010-04-30  
greatghoul 写道
用javascript做脚本语言?有意思,研究下。

有没有办法直接在HTML页面里面利用 JavaScript与Java通信,比如说读写文件,邮件什么的。


曾经见过一篇文章,写的非常棒:
http://www.ibm.com/developerworks/cn/web/wa-aj-javaee/
不过主要是在Server端使用JavaScript,然后通过JSP来调用(用JDK6里的脚本库),那样就可以实现用JavaScript来读写文件/发邮件,不过脚本泡在Server上,而不是客户端。
1 楼 greatghoul 2010-04-26  
用javascript做脚本语言?有意思,研究下。

有没有办法直接在HTML页面里面利用 JavaScript与Java通信,比如说读写文件,邮件什么的。

相关推荐

Global site tag (gtag.js) - Google Analytics