- 浏览: 801279 次
- 性别:
- 来自: 广州
最新评论
-
mixture:
语句int num1, num2;的频度为1;语句i=0;的频 ...
算法时间复杂度的计算 [整理] -
zxjlwt:
学习了。http://surenpi.com
[问题解决]Error: ShouldNotReachHere() [整理] -
Animal:
谢谢 楼主 好东西
算法时间复杂度的计算 [整理] -
univasity:
gaidandan 写道缓存失败,,模拟器上可以缓存,同样代码 ...
[开发总结]WebView使用中遇到的一些问题&解决 -
blucelee2:
那么麻烦干吗,而且这种方法会导致,当拉太小的时候样式会丢掉,整 ...
[SWT]SashForm中固定单侧大小(&实现面板隐藏)
//-------------------------------------------------------------------------------- 2010.10.17
重新整理了代码,发觉弄得太复杂了,还是按需要再独自实现吧,主要是实现思路清晰就行... 下面更新了代码。
//--------------------------------------------------------------------------------
最近学习Swing的开发,要用到一个像浏览器搜索栏那样的带有自动完成功能的文本框,但发觉Swing中并没有现成的实现,网上爬文然后动手写了一个,分享下。
网上主要介绍的实现方式有两种:
1. JComboBox
2. JTextField + PopupMenu + JList
第二种实现效果更贴切些。
我的实现思路是方便使用,于是封装成一个辅助工具,只要传一个JTextComponent给他,并设置数据就能用了。
一个使用的样例:
JTextField textField = new JTextField(); // 创建对象并绑定一个JTextComponent AutoCompleteExtender autoCompleteExtender = new AutoCompleteExtender(textField, data, null); // 设置参数 autoCompleteExtender.setMatchDataAsync(true); autoCompleteExtender.setSizeFitComponent(); autoCompleteExtender.setMaxVisibleRows(6); autoCompleteExtender.setCommitListener(new CommitListener() { // 值最终被选中时会触发该函数 public void commit(String value) { System.out.println("commit:" + value); } });
1.
构造函数AutoCompleteExtender(JTextComponent , DataProvider , DataMatchHelper ),其中JTextComponent为需要绑定的组件,DataProvider是我封装的一个用于提供数据的接口,DataMatchHelper是一个定义如何进行匹配的接口。
2.
其中setMatchDataAsync(true)是设置异步匹配数据,就是匹配时先返回界面再新建县城进行循环匹配操作,为了避免数据过多时造成延迟。但经测试,即使设为false,10000的数据量也并没发现明显延迟....
3.
setSizeFitComponent(true),使弹出列表自动切合文本组件的大小。当然也提供了setWidth的函数。
4.
setMaxVisibleRows(6)为设置一次最多可见的个数为6个,和JList.setVisibleRowCount()一致。
5.
CommitListener是我设置的一个用于监听确定事件的监听器,目前按firefox的操作规则是鼠标点中或回车键。
基本上目前实现的效果是模仿firefox的搜索栏的,能跟随光标和显示提示。
最终显示效果:
最后放上代码:
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package swingstudy.autocomplete; import java.awt.Dimension; import java.awt.Point; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.text.JTextComponent; import swingstudy.autocomplete.AutoCompleteExtender.DataProvider.DataChangeListener; /** * * @author Univasity */ public class AutoCompleteExtender { public static final int DefaultMaxVisibleRows = 5; /** * 绑定的文本组件 */ private JTextComponent textComponent; /** * 用于显示结果列表的弹出菜单组件 */ private JPopupMenu popupMenu; /** * 用于展示匹配结果的列表组件 */ private JList resultList; /** * 为列表提供滚动支持的组件 */ private JScrollPane scrollPane; /** * 数据提供器 */ private DataProvider dataProvider; /** * 标记匹配数据是否发生改变 */ private boolean matchDataChanged; /** * 记录当前被匹配的文本 */ private String matchedText; /** * 原始的编辑文本 */ private String originalEditText; /** * 数据匹配器 */ private DataMatchHelper dataMatchHelper; /** * 确定监听器,默认为按下'回车键'或鼠标点选会被触发 */ private CommitListener commitListener; /** * 默认的数据改变监听器 */ private final DataChangeListener DefaultDataChangeListener = new DataChangeListener() { public void dataChanged(int action, Object value) { notifyDataChanged(); } }; /** * 线程池 */ private BlockingQueue<Runnable> queue; // 用于储存任务的队列 private ThreadPoolExecutor executor; // 线程池对象 private boolean matchDataAsync = false; // 是否异步进行匹配操作 private int resultListWidth; private boolean widthWithScrollBar; private boolean autoSizeToFit; /** * 指定绑定的对象,数据提供器和匹配器来构建一个对象 * @param textComponent 不能为null * @param dataProvider 不能为null * @param dataMatchHelper 如果为null,则使用默认的匹配器 */ public AutoCompleteExtender(JTextComponent textComponent, DataProvider dataProvider, DataMatchHelper dataMatchHelper) { if (textComponent == null) { /** * 确保绑定的插件不为null */ throw new IllegalArgumentException("textComponent不能为null!"); } if (dataProvider == null) { /** * 确保数据提供器不为null */ throw new IllegalArgumentException("dataProvider不能为null!"); } this.textComponent = textComponent; this.dataProvider = dataProvider; this.dataProvider.setDataChangeListener(DefaultDataChangeListener); if (dataMatchHelper == null) { this.dataMatchHelper = new DefaultDataMatchHelper(); } else { this.dataMatchHelper = dataMatchHelper; } /** * 初始化数据 */ resetAll(); } /** * 指定绑定的对象,匹配数据和匹配器来构建一个对象 * @param textComponent 不能为null * @param data 初始的匹配数据 * @param dataMatchHelper 如果为null,则使用默认的匹配器 */ public AutoCompleteExtender(JTextComponent textComponent, Object[] data, DataMatchHelper dataMatchHelper) { if (textComponent == null) { /** * 确保绑定的插件不为null */ throw new IllegalArgumentException("textComponent不能为null!"); } this.textComponent = textComponent; this.dataProvider = new DefaultDataProvider(); if (data != null) { for (Object value : data) { this.dataProvider.appendData(value); } } this.dataProvider.setDataChangeListener(DefaultDataChangeListener); if (dataMatchHelper == null) { this.dataMatchHelper = new DefaultDataMatchHelper(); } else { this.dataMatchHelper = dataMatchHelper; } /** * 初始化数据 */ resetAll(); } public DataProvider getDataProvider() { return dataProvider; } /** * 设置为默认配置,原有数据将被清空 */ public synchronized void resetAll() { initTextComponent(); initResultList(); initValues(); setFocusOnTextComponent(); updateUI(); } /** * 刷新当前UI */ public synchronized void updateUI() { popupMenu.pack(); popupMenu.updateUI(); } /** * 清空匹配结果 */ public synchronized void clearMatchResult() { collapse(); if (queue != null) { queue.clear(); } ((DefaultListModel) resultList.getModel()).removeAllElements(); } /** * 标记匹配数据改变了 */ private void notifyDataChanged() { matchDataChanged = true; } public void setCommitListener(CommitListener commitListener) { this.commitListener = commitListener; } /** * 获取当前被匹配的文本 * @return */ public synchronized String getMatchText() { return matchedText; } /** * 获取当前匹配结果 * @return */ public synchronized Object[] getMatchResult() { return ((DefaultListModel) resultList.getModel()).toArray(); } /** * 获取当前选中的值 * @return */ public synchronized Object getSelectedValue() { return resultList.getSelectedValue(); } /** * 确定指定的文本为最终选定 * @param text */ public synchronized void commitText(String text) { originalEditText = text; textComponent.setText(text); if (commitListener != null) { commitListener.commit(text); } } /** * 获取当前选中项的索引值 * @return */ public synchronized int getSelectedIndex() { return resultList.getSelectedIndex(); } /** * 选中指定的索引值 * @param index */ public synchronized void setSelectedIndex(int index) { if (index < 0 || index >= getResultCount()) { return; } resultList.setSelectedIndex(index); // 使选中项处于可视范围内 resultList.ensureIndexIsVisible(index); } /** * 打开结果列表(如果未成匹配,则自动执行匹配处理,如果无有效结果则不会被展开)(焦点会转移到列表) * @return */ public synchronized boolean expand() { if (!hasMatched()) { if (doMatch()) { // 展开列表 updateExpandListUI(); popupMenu.show(textComponent, 0, textComponent.getHeight()); } } else if (getResultCount() > 0) { popupMenu.setVisible(true); } return popupMenu.isVisible(); } /** * 关闭结果列表(数据不会被清空,再次打开时直接重新显示) */ public synchronized void collapse() { removeSelectionInterval(); popupMenu.setVisible(false); } /** * 判断结果列表是否被打开 * @return */ public synchronized boolean isExpanded() { return popupMenu.isVisible(); } /** * 获取当前结果列表的条目数 * @return */ public synchronized int getResultCount() { return ((DefaultListModel) resultList.getModel()).getSize(); } /** * 获取一次最多的显示行数(超出的部分需通过拖动滚动条显示) * @param rows */ public synchronized void setMaxVisibleRows(int rows) { resultList.setVisibleRowCount(rows); } /** * 把焦点设置到文本编辑框上 */ public synchronized void setFocusOnTextComponent() { textComponent.requestFocus(); } /** * 把焦点设置到结果列表上 */ public synchronized void setFocusOnExpandList() { resultList.requestFocus(); } /** * 判断焦点是否在文本编辑框上 * @return */ public synchronized boolean isFocusOnTextComponent() { return textComponent.isFocusOwner(); } /** * 判断焦点是否在结果列表上 * @return */ public synchronized boolean isFocusOnExpandList() { return resultList.isFocusOwner(); } /** * 取消当前列表上的选中状态(使selectedIndex==-1) */ public synchronized void removeSelectionInterval() { final int selectedIndex = resultList.getSelectedIndex(); resultList.removeSelectionInterval(selectedIndex, selectedIndex); } /** * 判断是否已经匹配过了(匹配前应进行检测,避免重复匹配操作) * @return */ public synchronized boolean hasMatched() { if (matchDataChanged) { return false; } if (matchedText == null || matchedText.length() < 1) { return false; } String text = textComponent.getText(); if (text == null || !text.equals(matchedText)) { return false; } return true; } /** * 执行匹配操作 * @return */ public synchronized boolean doMatch() { // 清空原有结果 clearMatchResult(); matchedText = textComponent.getText(); originalEditText = matchedText; String keyWord = matchedText; if (keyWord != null) { keyWord = matchedText.trim(); } if (dataMatchHelper != null) { if (!dataMatchHelper.isMatchTextAccept(keyWord)) { return false; } } if (matchDataAsync) { doMatchAsync(keyWord); matchDataChanged = false; return true; } else { doMatchSync(keyWord); matchDataChanged = false; return getResultCount() > 0; } } /** * 设置异步匹配数据 * @param async */ public synchronized void setMatchDataAsync(boolean async) { if (this.matchDataAsync != async) { this.matchDataAsync = async; if (async) { queue = new LinkedBlockingQueue<Runnable>(); // 创建一个最多运行2个任务,支持10个任务, 允许延时20秒的线程池 executor = new ThreadPoolExecutor(2, 10, 20, TimeUnit.SECONDS, queue); } else { if (queue != null) { queue.clear(); } if (executor != null) { executor.shutdown(); } queue = null; executor = null; } } } /** * 判断当前是否异步匹配 * @return */ public synchronized boolean isMatchDataAsync() { return this.matchDataAsync; } /** * 在结果列表上显示过于选中项的提示条 * @param asNeed 是否根据需要显示(true->文本长度超出显示范围时才显示) */ public synchronized void showToolTipsWithSelectedValue(boolean asNeed) { Object value = resultList.getSelectedValue(); if (value != null) { // 显示提示 String txt = value.toString(); if (txt != null) { if (asNeed) { // 超出范围才显示提示 int txtW = SwingUtilities.computeStringWidth(resultList.getFontMetrics(resultList.getFont()), txt); if (txtW >= resultList.getFixedCellWidth()) { resultList.setToolTipText(txt); return; } } else { resultList.setToolTipText(txt); return; } } } resultList.setToolTipText(null); } /** * 在结果列表上显示指定的文本作为提示 * @param text */ public void showToolTips(String text) { if (text != null) { resultList.setToolTipText(text); } else { resultList.setToolTipText(null); } } /** * 获取一次最多可见行数 * @return */ public synchronized int getMaxVisibleRows() { return resultList.getVisibleRowCount(); } /** * 获取结果列表单元项的宽度 * @return */ public synchronized int getListCellWidth() { return resultList.getFixedCellWidth(); } /** * 获取结果列表单元项的高度 * @return */ public synchronized int getListCellHeight() { return resultList.getFixedCellHeight(); } public synchronized void setListCellSize(int cellWidth, int cellHeight) { resultList.setFixedCellWidth(cellWidth); resultList.setFixedCellHeight(cellHeight); autoSizeToFit = false; updateExpandListUI(); } public synchronized void setListWidth(int width, boolean withScrollBar) { this.resultListWidth = width; this.widthWithScrollBar = withScrollBar; autoSizeToFit = false; updateExpandListUI(); } /** * 使大小贴合组件 */ public synchronized void setSizeFitComponent() { autoSizeToFit = true; updateExpandListUI(); } /** * 指定点是否在文本框范围内 * @param p * @return */ public synchronized boolean isTextFieldContains(Point p) { if (p == null) { return false; } return textComponent.contains(p); } /** * 指定点是否在结果列表范围内 * @param p * @return */ public synchronized boolean isExpandListContains(Point p) { if (p == null) { return false; } return resultList.contains(p); } private synchronized void initTextComponent() { textComponent.setVisible(true); textComponent.setEnabled(true); textComponent.setEditable(true); // 必须先删除再添加,否则会重复.... textComponent.removeKeyListener(DefaultTextFieldKeyAdapter); textComponent.addKeyListener(DefaultTextFieldKeyAdapter); } private synchronized void initResultList() { /** * list */ if (resultList != null) { resultList.removeAll(); } else { resultList = new JList(new DefaultListModel()); resultList.addMouseListener(DefaultResultListMouseAdapter); resultList.addMouseMotionListener(DefaultResultListMouseMotionAdapter); } resultList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); resultList.setVisibleRowCount(DefaultMaxVisibleRows); // 允许提示框 ToolTipManager.sharedInstance().registerComponent(resultList); /** * scroll pane */ if (scrollPane == null) { scrollPane = new JScrollPane(resultList); } scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); /** * popup menu */ if (popupMenu == null) { popupMenu = new JPopupMenu(); } popupMenu.add(scrollPane); popupMenu.setVisible(false); popupMenu.setFocusable(false); popupMenu.setBorder(BorderFactory.createEmptyBorder()); // 去掉边框 } private synchronized void initValues() { setCommitListener(null); matchedText = null; matchDataChanged = true; this.matchDataAsync = false; originalEditText = textComponent.getText(); } /** * 根据给定的值执行匹配操作(该操作为异步的) * @param content * @return */ private synchronized void doMatchAsync(String content) { final String matchText = content; if (queue != null) { queue.clear(); } executor.execute(new Runnable() { public void run() { /** * 进行匹配 */ doMatchInner(matchText); /** * 如果无匹配项,关闭当前显示 */ if (getResultCount() > 0) { updateExpandListUI(); } else { collapse(); } } }); } /** * 根据给定的值执行匹配操作(该操作为同步的) * @param content * @return */ private synchronized void doMatchSync(String content) { /** * 进行匹配 */ doMatchInner(content); } /** * 处理匹配(内部调用) * @param matchText */ private void doMatchInner(String matchText) { if (dataProvider != null) { DefaultListModel listModel = (DefaultListModel) resultList.getModel(); for (Object value : dataProvider.toArray()) { if (dataMatchHelper != null) { if (dataMatchHelper.isDataMatched(matchText, value)) { listModel.addElement(value); } } else { // 直接添加 listModel.addElement(value); } } } } /** * 设置当前选项为最终选定值 */ private void commitTextBySelectedValue() { Object value = getSelectedValue(); if (value != null) { commitText(value.toString()); } collapse(); } /** * 转移焦点到文本编辑框,并关闭结果列表 */ private void changeFocusToTextField() { // 取消选择 removeSelectionInterval(); // 转移焦点到文本框 setFocusOnTextComponent(); // 设置为原本编辑的文本值 textComponent.setText(originalEditText); } /** * 设置当前选中项的值到文本框 */ private void showCurrentSelectedValue() { Object value = getSelectedValue(); if (value != null) { textComponent.setText(value.toString()); } } /** * 刷新结果列表的显示(焦点会转移到列表) */ private synchronized void updateExpandListUI() { DefaultListModel listModel = (DefaultListModel) resultList.getModel(); int dataSize = listModel.getSize(); int preferredWidth = 0; if (autoSizeToFit) { /** * 自动使大小贴合组件 */ resultList.setFixedCellWidth(textComponent.getWidth()); resultList.setFixedCellHeight(textComponent.getHeight()); preferredWidth = textComponent.getWidth(); if (dataSize > resultList.getVisibleRowCount()) { preferredWidth += scrollPane.getVerticalScrollBar().getPreferredSize().width; } } else { /** * 使用自定义的大小 */ preferredWidth = resultListWidth; if (dataSize > resultList.getVisibleRowCount()) { if (!widthWithScrollBar) { preferredWidth += scrollPane.getVerticalScrollBar().getPreferredSize().width; } } } int preferredHeight = Math.min(resultList.getVisibleRowCount(), dataSize) * resultList.getFixedCellHeight() + 3; // 多预留一些空间,这个值可自己调整不是很准的 scrollPane.setPreferredSize(new Dimension(preferredWidth, preferredHeight)); resultList.updateUI(); popupMenu.pack(); } /** * 默认提供的结果列表上鼠标运动事件处理器 */ private MouseMotionAdapter DefaultResultListMouseMotionAdapter = new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { /** * 该操作结果是: * 选中鼠标所在选项,并显示提示 */ Point p = e.getPoint(); if (isExpandListContains(p)) { /** * 鼠标在列表区域内移动时 */ int index = p.y / getListCellHeight(); // 光标跟随 setSelectedIndex(index); // 文本超长时显示提示 showToolTipsWithSelectedValue(true); // 焦点回归到文本编辑框 setFocusOnTextComponent(); } } }; /** * 默认提供的结果列表上鼠标按键事件处理器 */ private final MouseAdapter DefaultResultListMouseAdapter = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { /** * 该操作结果是: * 设置编辑框文字为选中项,关闭结果列表,焦点回到编辑框,同时触发commit监听器 */ Point p = e.getPoint(); if (isExpandListContains(p)) { /** * 鼠标点击列表项时 */ int index = p.y / getListCellHeight(); // 选中该项 setSelectedIndex(index); // if (getSelectedIndex() == index) { commitTextBySelectedValue(); } // 焦点回归到文本编辑框 setFocusOnTextComponent(); } } }; /** * 默认提供的文本编辑框上键盘按键事件处理器 */ private final KeyAdapter DefaultTextFieldKeyAdapter = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { /** * 只对处于当前焦点时作处理 */ if (!e.getComponent().isFocusOwner()) { return; } switch (e.getKeyCode()) { case KeyEvent.VK_ENTER: /** * 该操作结果是: * 设置编辑框文字为选中项,关闭结果列表,焦点回到编辑框,同时触发commit监听器 */ commitTextBySelectedValue(); break; case KeyEvent.VK_DOWN: /** * 该操作结果是: * 1.如果结果列表未打开,打开结果列表,并选中第一项,设置编辑框文字 * 2.如果当前选中项为最后一项,让焦点回到编辑框 * 3.否则,下移选项,并改变编辑框文字为当前选项 */ if (isExpanded()) { /** * 如果列表处于展开状态 */ final int selectedIndex = getSelectedIndex(); if (selectedIndex == getResultCount() - 1) { /** * 并且选中项为最后一项 */ // 将焦点集中到文本框 changeFocusToTextField(); } else { /** * 否则 */ // 下移一项 setSelectedIndex(selectedIndex + 1); showCurrentSelectedValue(); setFocusOnTextComponent(); } } else { if (expand()) { /** * 成功打开结果列表 */ // 选中第一项 setSelectedIndex(0); } } break; case KeyEvent.VK_UP: /** * 该操作结果是: * 1.如果结果列表未打开,打开结果列表,并选中最后一项,设置编辑框文字 * 2.如果当前选中项为第一项,让焦点回到编辑框 * 3.否则,上移选项,并改变编辑框文字为当前选项 */ if (isExpanded()) { /** * 如果列表处于展开状态 */ final int selectedIndex = getSelectedIndex(); if (selectedIndex == 0) { /** * 并且选中项为第一项 */ // 将焦点集中到文本框 changeFocusToTextField(); } else { /** * 否则 */ if (selectedIndex == -1) { // 移到最后一项 setSelectedIndex(getResultCount() - 1); } else { // 上移一项 setSelectedIndex(selectedIndex - 1); } showCurrentSelectedValue(); } } else { if (expand()) { /** * 成功打开结果列表 */ // 选中最后一项 setSelectedIndex(getResultCount() - 1); } } break; case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT: // 左右的操作相同 /** * 该操作结果是: * 设置编辑文字为选中项,并关闭结果列表,焦点回到编辑框 */ if (isExpanded()) { /** * 如果列表处于展开状态 */ if (getSelectedIndex() != -1) { /** * 并且有选项被选中了 */ showCurrentSelectedValue(); } collapse(); } // 转移焦点到文本编辑框 changeFocusToTextField(); break; } /** * 为了确保焦点始终处于编辑框 */ setFocusOnTextComponent(); } @Override public void keyReleased(KeyEvent e) { if (!e.getComponent().isFocusOwner()) { return; } int keyCode = e.getKeyCode(); if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_ENTER /*|| keyCode == KeyEvent.VK_BACK_SPACE*/) { return; } /** * 打开结果列表 */ expand(); /** * 为了确保焦点始终处于编辑框 */ setFocusOnTextComponent(); } }; /********************************************************* * 定义的一些接口 */ public interface CommitListener { public void commit(String value); } /** * 数据提供接口 * @author Univasity */ public interface DataProvider { public Object getData(int index); public void appendData(Object value); public void insertData(int index, Object value); public void replaceData(int index, Object value); public void replaceData(Object oldValue, Object newValue); public void removeDataAt(int index); public void removeData(Object value); public void clear(); public int getSize(); public Object[] toArray(); public void setDataChangeListener(DataChangeListener listener); /** * 数据改变监听接口 */ public interface DataChangeListener { public static final int APPEND = 1; public static final int INSERT = 2; public static final int REPLACE = 3; public static final int REMOVE = 4; public static final int CLEAR = 5; public void dataChanged(int action, Object value); } } public interface DataMatchHelper { /** * 判断指定的用于匹配文本是否被允许 * @param text * @return */ public boolean isMatchTextAccept(String text); /** * 判断给定的值是否与文本值匹配 * @param matchedText * @param data * @return */ public boolean isDataMatched(String matchText, Object data); } /********************************************************* * 默认的实现 */ private class DefaultDataProvider implements DataProvider { private ArrayList data; private DataChangeListener listener; public DefaultDataProvider() { data = new ArrayList(); } public synchronized Object getData(int index) { return data.get(index); } public synchronized void appendData(Object value) { if (data.add(value)) { if (listener != null) { listener.dataChanged(DataChangeListener.APPEND, value); } } } public synchronized void insertData(int index, Object value) { data.add(index, value); if (listener != null) { listener.dataChanged(DataChangeListener.INSERT, value); } } public synchronized void replaceData(int index, Object value) { if (data.set(index, value).equals(value)) { if (listener != null) { listener.dataChanged(DataChangeListener.REPLACE, value); } } } public synchronized void replaceData(Object oldValue, Object newValue) { int index = data.indexOf(oldValue); if (data.set(index, newValue).equals(newValue)) { if (listener != null) { listener.dataChanged(DataChangeListener.REPLACE, newValue); } } } public synchronized void removeDataAt(int index) { Object value = data.get(index); data.remove(index); if (listener != null) { listener.dataChanged(DataChangeListener.REMOVE, value); } } public synchronized void removeData(Object value) { if (data.remove(value)) { if (listener != null) { listener.dataChanged(DataChangeListener.REMOVE, value); } } } public synchronized void clear() { data.clear(); if (listener != null) { listener.dataChanged(DataChangeListener.CLEAR, null); } } public synchronized int getSize() { return data.size(); } public synchronized Object[] toArray() { return data.toArray(); } public synchronized void setDataChangeListener(DataChangeListener listener) { this.listener = listener; } } /** * 默认的数据匹配助手 */ private class DefaultDataMatchHelper implements DataMatchHelper { public boolean isMatchTextAccept(String text) { return (text != null && text.length() > 0); } public boolean isDataMatched(String matchText, Object value) { if (value != null && value.toString().indexOf(matchText) != -1) { return true; } return false; } } }
可能还不是很完善,但目前给出了一些函数,方便自定义自己的一些监听器,实现自己的规则,具体可参考代码中的Default...Adapter实现。
以上仅供参考,大家多多交流。
评论
非常好用,正好一直在找这个!正在消化中~~
不知道对swt有研究吗?
暂无深入研究,有时需要就用用,翻翻API...都是WindowBuidler完全可视化的,哈哈。
不知道对swt有研究吗?
呵呵,多多交流。实现是都点复杂了,网上有更简单的,思路就是JTextField + PopupMenu + JList,可以按需实现。我的邮箱joopererer@yahoo.com.cn。
可以实现的,目前通过JList来展示结果,只要设置自定义的CellRenderer就可以了。当然还要加上自己的逻辑处理。具体可以参考SUN提供的资料http://download.oracle.com/javase/tutorial/uiswing/components/list.html。
发表评论
-
[问题解决]个推SDK使用侧记 -- 多个账号注册导致的问题
2013-12-28 14:40 2161这是我们项目最近用到的东西,用来实现消息推送。 (还不了 ... -
[问题解决] 个推(igetui)SDK使用侧记 -- 多个账号注册同一应用导致的问题
2013-12-28 14:33 0这是我们项目最近用到的东西,用来实现消息推送。 (还不了解 ... -
[SWT]打开Windows文件夹的方法 [整理]
2012-10-24 21:03 2455参考论坛帖子:http://www.iteye.com/top ... -
[SWT]SashForm中固定单侧大小(&实现面板隐藏)
2012-09-20 16:06 7018<!-- 额,发觉写篇博客都不知怎么选分类了。。。名称太 ... -
[Everything模仿] 相关项目资源整理
2012-04-29 20:04 3662一段时间来,发觉还是 ... -
[问题解决]Ubuntu10.04安装出现的显示器“无信号”问题
2011-12-11 20:42 4267<!-- 旧帖转移,2010-09-25 --> ... -
9个主流的开源许可协议[整理]
2011-12-05 23:15 29172关于开源许可 现今存在的开源协议很多,而经过 ... -
电子邮件收发原理和实现(POP3, SMTP) [整理]
2011-09-16 11:12 28201<!-- 最近工作上接触到了邮箱的开发,整理一下学到的东 ... -
讲解极小极大 (Minimax Explained) [译]
2011-09-11 21:00 6784原文链接:Minimax Explaine ... -
理解极小极大算法 (Understanding The Minimax Algorithm) [译]
2011-09-11 20:45 26973原文链接:Understanding Th ... -
Maven In Android
2011-08-31 17:32 3437Maven 一个项目管理工具,类似于Ant。相比Ant, ... -
[基础回顾]基于Eclipse的J2me和Android开发环境搭建
2011-03-23 00:10 1839<!-- 越是基础的东西就容易被忽略和轻视...我是接触 ... -
[SVN]423 Locked problem (Solved)
2011-03-03 17:15 8969今天使用SVN上传代码,突然冒出了一行红字... Se ... -
Everything研究之快速获取USN记录的文件路径
2011-01-06 17:04 8888<!-- 发觉越是没事干,记忆越差,乘还记得点什么,记录 ... -
Everything研究之读取NTFS下的USN日志文件(2)
2010-11-08 01:08 15624续>> /******************* ... -
Everything研究之读取NTFS下的USN日志文件(1)
2010-11-08 01:02 32680我在第一次使用 Everything 时,对其速度确实感到 ... -
[Swing]Netbean中使用外部资源
2010-10-22 15:43 1593要在NetBean中使用外部资源,首先需要在项目目录下创建一个 ... -
[图形算法]J2me上的凹凸拼图实现思路
2010-04-05 21:31 6014出于个人兴趣,简单研究了一下凹凸拼图的实现。以下为本人的实现思 ... -
[特效研究]j2medev论坛里提到的一个显示特效实现
2010-03-14 16:05 2432原贴链接:http://www.j2medev.com/ ... -
[LUA]在eclipse中使用luajava
2009-10-17 23:23 4256<!--StartFragment--> st ...
相关推荐
NULL 博文链接:https://hw1287789687.iteye.com/blog/2217653
一个“文档”伴随窗口,用于显示有关当前所选完成选项的文档 参数帮助(例如,通过函数/方法参数进行切换,每个参数都有工具提示帮助以及每个参数的有效变量完成的可能列表) 添加到您的项目 该库在 ( ...
RSyntaxTextArea是Java Swing应用程序的可自定义的语法突出显示文本组件。 开箱即用,它支持40多种编程语言的语法突出显示,代码折叠,搜索和替换,并具有用于代码完成和拼写检查的附加库。 通过工具其他语言的语法...
摆动组件从 code.google.com/p/swing-components 自动导出Swing 组件是提供标准 Swing 工具包中没有的通用用户界面控件的库。 当前在库中的控件JSplitButton JCalendar小部件日期选择器按钮菜单项JIP文本字段J复选框...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...
用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整源代码 14个目标文件 内容索引:JAVA源码,系统相关,日历,...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...
Cleo 是一个灵活的软件库用于处理一些预输入和自动完成的搜索功能,该项目是 LinkedIn 公司的开源项目。 SwingSet 增强现实标记跟踪软件库 AccuTag AccuTag是AR(增强现实)标记跟踪软件库。它利用GPGPU的快速和...