我正在尝试使用javax.swing.JTextField
构建javax.swing.JList
以自动完成,例如 Google 。
撰写单词时,Google
会显示多个匹配和
我的答案是关于Bible,我想在研究这个词时寻找一个特定的词。我见过Java2sAutoTextField,但箭头键没有这种特殊行为。
答案 0 :(得分:9)
这需要一个自定义编码组件。绝对是一个扩展JTextField的类,在该类中你有一个包含你的JList的JPopupMenu。您必须将JPopupMenu放在文本字段下面,使其看起来像1个组件。
您的下一个技巧是在键入时进行过滤。我通常使用Java6 TableRowSorter和一个JTable来做这个,我用它来预先填充数据。您需要在JTextField上使用一些更改侦听器并拦截键入的每个键并获取您的数据。
修改强>
我掀起了一个示例摇摆应用程序,以显示我说的内容。这是一个复制/粘贴示例,应该可以正常工作(需要JDK 1.6+)。我基本上得到了你想要的东西,我把评论放在我告诉你填补空白的地方......例如,Escape键事件已被消耗,你可以随心所欲地做任何事情。
方法initTableModel()只是用数据初始化表模型。通常,您希望使用来自数据库或其他内容的数据动态填充表模型。可以调整很多,但这只是为了清酒;)所以这应该是一个足够好的例子,你可以修改你完成你的目标。除此之外你还得付钱给我:)
package test.text.googleclone;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
public class SearchAutoFillTest {
private JFrame frame = null;
private JTextField searchField = null;
private JPopupMenu popup = null;
private JTable searchTable = null;
private TableRowSorter<DefaultTableModel> rowSorter = null;
private DefaultTableModel searchTableModel = null;
public SearchAutoFillTest() {
searchTableModel = new DefaultTableModel();
initTableModel();
rowSorter = new TableRowSorter<DefaultTableModel>(searchTableModel);
searchTable = new JTable(searchTableModel);
searchTable.setRowSorter(rowSorter);
searchTable.setFillsViewportHeight(true);
searchTable.getColumnModel().setColumnSelectionAllowed(false);
searchTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
searchTable.getTableHeader().setReorderingAllowed(false);
searchTable.setPreferredSize(new Dimension(775, 100));
searchTable.setGridColor(Color.WHITE);
searchField = new JTextField();
searchField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
showPopup(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
showPopup(e);
}
@Override
public void removeUpdate(DocumentEvent e) {
showPopup(e);
}
});
searchField.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
switch(code)
{
case KeyEvent.VK_UP:
{
cycleTableSelectionUp();
break;
}
case KeyEvent.VK_DOWN:
{
cycleTableSelectionDown();
break;
}
case KeyEvent.VK_LEFT:
{
//Do whatever you want here
break;
}
case KeyEvent.VK_RIGHT:
{
//Do whatever you want here
break;
}
}
}
@Override
public void keyPressed(KeyEvent e) {
}
});
KeyStroke keyStroke = KeyStroke.getKeyStroke("ESCAPE");
searchField.getInputMap().put(keyStroke, "ESCAPE");
searchField.getActionMap().put("ESCAPE", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
//Do what you wish here with the escape key.
}
});
popup = new JPopupMenu();
popup.add(searchTable);
popup.setVisible(false);
popup.setBorder(BorderFactory.createEmptyBorder());
JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
searchPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
searchPanel.add(searchField, BorderLayout.CENTER);
frame = new JFrame();
frame.setLayout(new BorderLayout(5, 5));
frame.add(searchPanel, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 500);
center(frame);
frame.setVisible(true);
}
private final void newFilter() {
RowFilter<DefaultTableModel, Object> rf = null;
try {
rf = RowFilter.regexFilter(getFilterText(), 0);
}
catch(PatternSyntaxException e) {
return;
}
rowSorter.setRowFilter(rf);
}
private final String getFilterText() {
String orig = searchField.getText();
return "("+orig.toLowerCase()+")|("+orig.toUpperCase()+")";
}
private void showPopup(DocumentEvent e) {
if(e.getDocument().getLength() > 0) {
if(!popup.isVisible()) {
Rectangle r = searchField.getBounds();
popup.show(searchField, (r.x-4), (r.y+16));
popup.setVisible(true);
}
newFilter();
searchField.grabFocus();
}
else {
popup.setVisible(false);
}
}
private void cycleTableSelectionUp() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 > 0) {
selModel.setSelectionInterval(index0-1, index0-1);
}
}
private void cycleTableSelectionDown() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 == -1) {
selModel.setSelectionInterval(0, 0);
}
else if(index0 > -1) {
selModel.setSelectionInterval(index0+1, index0+1);
}
}
private void initTableModel() {
String[] columns = new String[] {"A"};
String[][] data = new String[][]
{
new String[] {"a"},
new String[] {"aa"},
new String[] {"aaab"},
new String[] {"aaabb"},
new String[] {"aaabbbz"},
new String[] {"b"},
new String[] {"bb"},
new String[] {"bbb"},
new String[] {"bbbbbbb"},
new String[] {"bbbbbbbeee"},
new String[] {"bbbbbbbeeexxx"},
new String[] {"ccc"},
new String[] {"cccc"},
new String[] {"ccccc"},
new String[] {"cccccaaaa"},
new String[] {"ccccccaaaa"},
};
searchTableModel.setDataVector(data, columns);
}
private void center(Window w) {
int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
int windowWidth = w.getWidth();
int windowHeight = w.getHeight();
if (windowHeight > screenHeight) {
return;
}
if (windowWidth > screenWidth) {
return;
}
int x = (screenWidth - windowWidth) / 2;
int y = (screenHeight - windowHeight) / 2;
w.setLocation(x, y);
}
public static void main(String ... args) {
new SearchAutoFillTest();
}
}
答案 1 :(得分:3)
此组件称为自动完成,并包含在所谓的swing扩展项中。
请看一下:http://swingx.java.net/
有一个带演示的webstart:http://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp
答案 2 :(得分:3)
使用自动完成JTextField放入JToolBar / MenuBar,注意你必须在使用前对ArrayList进行排序,
使用未发现的JDialog而不是JPopup(仍然有一些重要的错误),
a)只创建一个JDialog,其父级为JTextField或JMenuBar或JFrame,
b)总是在屏幕上可见的JDialog之前从AutoComplete JTextField中搜索getBounds,这个Bounds用于在屏幕上正确显示JDialog
c)将JDialog #setVisible(true)包装到invokeLater()
将JButton关闭/隐藏到avoiding overrive rest of important methods on focusLost(这个日历在focusLost,mouseClick等等方面有很好的解决方法,用比较器的结果替换日历功能是否非常容易,你必须下载codesource)
你可以放在那里(我的观点)6/9 /最多12个按钮,你可以通过setBackground(Color.white)删除JButton Feels,例如,你不能,请不要用它来做JDialog和这些JButton,你的工作只会是setText(“比较器的结果”)
如果您的AutoComplete JTextField的ArrayList已经排序,那么您有两个选择
a)来自AutoComplete功能的最简单的覆盖偏差,通过为弹出式JDialog上的6/9 / max 12按钮添加fils单独的数组for setText(),如果你设置了BackBackground(Color.white),那么你不在乎某种方式隐藏没有文字的JButtons
b)另一种方法是创建自己的比较器进行搜索(相同的自动完成功能)第6/9 /最多12场比赛,
用于从6/9 /最多12个JButton捕获事件使用putClientProperty或EventHandler或Swing Actions,您只需测试文本是否为空:-),< / p>
也许Swing Actions
可能是最好的方法,因为它的事件是可扩展的,默认情况下你可以enabled/disable(如果JButtons发出文本isEmpty)输出
答案 3 :(得分:1)
听起来您需要JComboBox
(请参阅Swing guide)而不是JTextField
/ JList
。
当然,您有一个下拉按钮,但有可能的方法来解决这个问题 - 请参阅here。
答案 4 :(得分:1)
这将是以下几点:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.*;
public class Component extends JComponent {
private final static String[] terms = {"Jesus",
"Jesus walks on water" //...
};
private static ArrayList<String> recent = new ArrayList<String>();
JTextField jtf;
JList jl;
public Component(){
// set up design
jtf = new JTextField();
jtf.setSize(this.getWidth() - 25, 25);
this.add(jtf);
//...
// add key listeners
}
class Listener implements KeyListener{
@Override
public void keyPressed(KeyEvent arg0) {
}
@Override
public void keyReleased(KeyEvent arg0) {
}
@Override
public void keyTyped(KeyEvent arg0) {
if (arg0.getKeyCode() == KeyEvent.VK_DOWN){
// set next item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_UP){
// set previous item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
// search
}
else if (arg0.getKeyCode() == KeyEvent.VK_ESCAPE){
jtf.setText("");
}
else{
// check list for matches
}
}
}
}
答案 5 :(得分:0)
默认行为是所有键事件都转到具有焦点的组件。因此,您需要做的是确定应该真正转到其他组件的密钥,并为这两个组件安装KeyListener
。
在该侦听器中,您可以将事件转发到其他组件。
请参阅this answer如何将事件分派给新组件。在您的情况下,source
必须是另一个组件(列表,如果您的文本字段最初收到事件,反之亦然)。