Swing小应用(Todo-list)之二

前言

用过vim, emacs的人都知道,这两个工具中都有很好用的增量搜索(incremental search )功能,所谓增量搜索,就是随着你的关键字的输入,结果在不断的进行刷新匹配,现在的很多web搜索框都提供类似的功能,最著名的当然是Google的,速度快,匹配率比较高(要不然也不会令人“心神不宁”了,哈哈)。



 最近开发的那个小型的todo管理软件stodo , 其中涉及到todo list的search问题,也想使用这种增量搜索的功能,后来在sun的一篇文章中找到了相关的主题,就在stodo中实现了下,大家可以参考参考。sTodo 现在仍在开发中,随着进度,可以学到很多Swing的内在技巧或者说用法,我会陆续将之整理出来。(如果没有听说过sTodo,请参看上一篇文章:Swing小应用(Todo-list) )

 

效果及实现

 



 


 

 

效果如图所示,下边我们来看看大概说下原理,一般来说,我们需要一个搜索框,来对列表中的元素进行搜索,Swing采用MVC模式,所以实现起来比较容易,而且代码结构也更为直观,当搜索框中的内容发生变化时,我们需要对类表中的对象进行遍历,如果有匹配,将这些匹配的item放入一个临时的List中,而列表中原来的对象不做更改(那样,当搜索条件为空的时候,显示整个列表)。

 

每一个JInputField都是一个Document,Document上可以注册监听器,当JInputField内容发生变化时,通知List的datamodel进行更新,同时Swing会将更新反映在UI组件上(JList)。

 

先来看JList的数据模型的实现:

package org.free.todolist.model;

import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractListModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

/**
 * 
 * @author juntao.qiu@gmail.com
 *
 */
public class FilterableListModel extends AbstractListModel implements
		DocumentListener {
	private static final long serialVersionUID = -2409529218176332776L;
	
	private List<Object> list;
	private List<Object> filteredList;
	private String lastFilter = "";

	public FilterableListModel() {
		list = new ArrayList<Object>();
		filteredList = new ArrayList<Object>();
	}

	public void addElement(Object element) {
		list.add(element);
		filter(lastFilter);
	}

	public int getSize() {
		return filteredList.size();
	}

	public Object getElementAt(int index) {
		Object returnValue;
		if (index < filteredList.size()) {
			returnValue = filteredList.get(index);
		} else {
			returnValue = null;
		}
		return returnValue;
	}
	
	public void removeElement(int index){
		list.remove(index);
		filter(lastFilter);
	}
	
	private void filter(String search) {
		filteredList.clear();
		for (Object element : list) {
			if (element.toString().indexOf(search, 0) != -1) {
				filteredList.add(element);
			}
		}
		fireContentsChanged(this, 0, getSize());
	}

	public void insertUpdate(DocumentEvent event) {
		Document doc = event.getDocument();
		try {
			lastFilter = doc.getText(0, doc.getLength());
			filter(lastFilter);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}

	public void removeUpdate(DocumentEvent event) {
		Document doc = event.getDocument();
		try {
			lastFilter = doc.getText(0, doc.getLength());
			filter(lastFilter);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}

	public void changedUpdate(DocumentEvent event) {
	}

	public void clear() {
		list.clear();
		filteredList.clear();
	}
}

 主要的方法是这个filter(), 当Document内容发生改变时,它会raise一个事件给父类AbstractListModel,然后AbstractListModel去更改JList的UI,从而实现过滤的功能。

 

List的UI组件比较简单,只需要设置好其数据模型即可:

package org.free.todolist.ui;

import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.ListModel;

import org.free.todolist.model.FilterableListModel;

/**
 * 
 * @author juntao.qiu@gmail.com
 *
 */
public class FilterableList extends JList {
	private static final long serialVersionUID = 2827679372675804255L;

	public FilterableList() {
		FilterableListModel model = new FilterableListModel();
		setModel(model);
	}

	/**
	 * register the search box on list
	 */
	public void installFilterField(JTextField input) {
		if (input != null) {
			FilterableListModel model = (FilterableListModel) getModel();
			input.getDocument().addDocumentListener(model);
		}
	}

	/**
	 * unregister the search box on list.
	 */
	public void uninstallFilterField(JTextField input) {
		if (input != null) {
			FilterableListModel model = (FilterableListModel) getModel();
			input.getDocument().removeDocumentListener(model);
		}
	}

	public void setModel(ListModel model) {
		if (!(model instanceof FilterableListModel)) {
			throw new IllegalArgumentException();
		} else {
			super.setModel(model);
		}
	}

	public void addElement(Object element) {
		((FilterableListModel) getModel()).addElement(element);
	}
	
	/**
	 * get the filterable list model of current list
	 * @return
	 */
	public FilterableListModel getContents(){
		return (FilterableListModel)getModel();
	}

}

 如果需要完整的代码,可以到sTodo 的项目主页上下载。sTodo已经有了讨论组,如果有兴趣,欢迎加入:sTodo讨论组

 

后记

Swing的定制性相当高,几乎可以任意搭配,任意组合,但是灵活性高了,学习曲线就显得陡峭了,且所有的UI需要在EDT中更新,如果控制不好,很容易造成假死。

 

sTodo现在的版本是V0.3,基本功能已经完成,如对todo的增删改查,将某一个todo发送到指定邮箱,导出成各种格式(这个目前做的不好,代码还没有更新在SVN上),后期打算将这个项目做成一个可编程的小应用,你可以任意对其进行扩展,目前,插件部分已经基本可用,还没有移植到项目中去,等周末或者国庆长假的时候可能就可以做进去了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值