- 浏览: 809947 次
- 性别:
- 来自: 广州
最新评论
-
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 2254这是我们项目最近用到的东西,用来实现消息推送。 (还不了 ... -
[问题解决] 个推(igetui)SDK使用侧记 -- 多个账号注册同一应用导致的问题
2013-12-28 14:33 0这是我们项目最近用到的东西,用来实现消息推送。 (还不了解 ... -
[SWT]打开Windows文件夹的方法 [整理]
2012-10-24 21:03 2639参考论坛帖子:http://www.iteye.com/top ... -
[SWT]SashForm中固定单侧大小(&实现面板隐藏)
2012-09-20 16:06 7165<!-- 额,发觉写篇博客都不知怎么选分类了。。。名称太 ... -
[Everything模仿] 相关项目资源整理
2012-04-29 20:04 3808一段时间来,发觉还是 ... -
[问题解决]Ubuntu10.04安装出现的显示器“无信号”问题
2011-12-11 20:42 4372<!-- 旧帖转移,2010-09-25 --> ... -
9个主流的开源许可协议[整理]
2011-12-05 23:15 29400关于开源许可 现今存在的开源协议很多,而经过 ... -
电子邮件收发原理和实现(POP3, SMTP) [整理]
2011-09-16 11:12 28383<!-- 最近工作上接触到了邮箱的开发,整理一下学到的东 ... -
讲解极小极大 (Minimax Explained) [译]
2011-09-11 21:00 6918原文链接:Minimax Explaine ... -
理解极小极大算法 (Understanding The Minimax Algorithm) [译]
2011-09-11 20:45 27115原文链接:Understanding Th ... -
Maven In Android
2011-08-31 17:32 3487Maven 一个项目管理工具,类似于Ant。相比Ant, ... -
[基础回顾]基于Eclipse的J2me和Android开发环境搭建
2011-03-23 00:10 1894<!-- 越是基础的东西就容易被忽略和轻视...我是接触 ... -
[SVN]423 Locked problem (Solved)
2011-03-03 17:15 9029今天使用SVN上传代码,突然冒出了一行红字... Se ... -
Everything研究之快速获取USN记录的文件路径
2011-01-06 17:04 9012<!-- 发觉越是没事干,记忆越差,乘还记得点什么,记录 ... -
Everything研究之读取NTFS下的USN日志文件(2)
2010-11-08 01:08 15840续>> /******************* ... -
Everything研究之读取NTFS下的USN日志文件(1)
2010-11-08 01:02 33071我在第一次使用 Everything 时,对其速度确实感到 ... -
[Swing]Netbean中使用外部资源
2010-10-22 15:43 1643要在NetBean中使用外部资源,首先需要在项目目录下创建一个 ... -
[图形算法]J2me上的凹凸拼图实现思路
2010-04-05 21:31 6148出于个人兴趣,简单研究了一下凹凸拼图的实现。以下为本人的实现思 ... -
[特效研究]j2medev论坛里提到的一个显示特效实现
2010-03-14 16:05 2484原贴链接:http://www.j2medev.com/ ... -
[LUA]在eclipse中使用luajava
2009-10-17 23:23 4328<!--StartFragment--> st ...
相关推荐
Swing是Java编程语言中的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分,由Sun Microsystems开发并引入Java平台。Swing提供了一系列组件,用于创建丰富的桌面应用程序,包括按钮、文本框...
本项目是使用Swing实现的一个仿QQ截图小工具,它旨在提供类似QQ截图的功能,让用户在桌面环境中能够方便地进行屏幕截图并进行编辑。 首先,Swing组件库提供了丰富的组件,如JFrame、JButton、JPanel等,这些组件...
Swing 是 Java 的一个图形用户界面(GUI)工具包,它是 Java Foundation Classes (JFC) 的一部分,由 Sun Microsystems 开发。Swing 提供了一系列组件,用于构建功能丰富的桌面应用程序,包括文本编辑器。在 Swing ...
Swing是Java编程语言中的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分,由Sun ...在实际应用中,Swing文本编辑器可以作为一个基础,进一步扩展成满足特定需求的专业文本编辑工具。
这个功能在许多GUI应用中都非常常见,例如用户选择一个选项后,相应的文本框会自动更新为所选选项的详细信息。以下是对这一知识点的详细说明: 首先,我们需要了解Swing中的基本组件。`JComboBox`是Swing提供的一种...
总之,创建一个Java Swing文本编辑器涉及到多个技术层面,包括组件使用、事件处理、文件操作、文本格式化以及可能的扩展功能实现。通过深入理解和实践这些知识点,开发者可以构建出功能完备且用户友好的文本编辑器。
Swing是Java编程语言中的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分。在Swing中实现中英切换是一项常见的需求,特别是在开发多语言应用时。Swing提供了强大的本地化(Localization)...
为了实现文本编辑功能,我们需要在内存中维护一个文本缓冲区,每次用户输入或修改文本时,更新缓冲区并重新绘制窗口。 4. **文本读取**:程序需要能够打开和加载现有的文本文件。这通常涉及`fopen`、`fgets`等文件...
在Java的GUI编程中,Swing是一个非常重要的库,它提供了丰富的组件和工具来创建桌面应用程序。本篇文章将深入探讨如何使用Swing实现QQ聊天窗口中的“泡泡模式”,这是一种常见且吸引人的消息显示方式。 首先,Swing...
而"demo"文件可能是一个示例或者演示程序,让用户了解工具的实际效果和操作流程。 总的来说,Swing界面内容抓取工具是开发者和测试人员的有力辅助工具,它简化了从Swing应用中获取界面数据的过程,提高了工作效率。...
"swingTextEditor"项目就是一个基于Java Swing实现的简单文本编辑器示例。在这个项目中,我们将深入探讨Java Swing如何用于创建一个基本的文本编辑器。 首先,Swing 提供了 `JFrame` 类,它是所有窗口的基础。在`...
3. **JTextField**: 提供一个单行文本输入框,用户可以在这里输入文本。 4. **JTextArea**: 用于多行文本输入和显示,支持滚动条。 5. **JCheckBox**: 用于提供二元选择,用户可以勾选或取消勾选。 6. **...
总的来说,这款基于Swing的日志分析工具提供了一个强大的平台,让用户能够有效地管理和分析日志数据。它的易用性、源码开放性以及作为工具的实用性,使其成为开发者和运维人员的强大助手。通过不断学习和定制,用户...
Java Frame实现的Java文本编辑器是一种基于Swing或者JavaFX的替代方案,它利用了`org.eclipse.swt`库,这是一个强大的图形用户界面(GUI)工具包,尤其在跨平台的Java应用中广受欢迎。`org.eclipse.swt`是Eclipse...
另一个标签“工具”暗示了这个文本编辑器可能包含了一些实用功能,比如自动完成、语法高亮、代码折叠等,这些都是现代文本编辑器的常见特性。开发者可能使用了Java的标准库或其他第三方库来实现这些功能。 在压缩包...
Swing是Java编程语言中的一个图形用户界面(GUI)工具包,它是Java Foundation Classes (JFC)的一部分。Swing提供了一套丰富的组件,用于创建桌面应用程序,包括按钮、文本框、菜单、滚动面板等。Swing是完全由Java...
【基于Swing的编辑器】是一种使用Java Swing库开发的文本编辑工具,它提供了一个基本的用户界面,供用户创建、查看和编辑文本文件。Swing是Java Foundation Classes (JFC)的一部分,它为Java应用程序提供了丰富的...
【标签】:“源码”与“工具”两个标签表明这篇博客内容将涉及FEST-Swing的源代码理解和实际应用,以及它是如何作为一个测试工具来提高GUI测试效率的。 【正文】: FEST-Swing是一个开源Java库,它的设计目的是...
虽然这个文本编辑器没有实现多文档功能,但对于初学者来说,它是一个很好的学习Java GUI编程和文本处理的基础项目。通过理解并扩展这个项目,开发者可以逐渐掌握更复杂的应用程序开发技能,如多线程、插件系统、以及...