在 Java 中实现自动完成 - 我做得对吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14849176/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implementing auto complete in Java - am I doing it right?
提问by Little Child
Algorithm
算法
- Start
- Input a city name - partial or complete
- If the user hits enter , take the text from
JTextField
- Begin brute force search.
- If the matches are found, put them in a
Vector
and put it in aJList
- If no match is found, add a
String
"No Match Found" inVector
- Display
JWindow
to user containing the results - Stop
- 开始
- 输入城市名称 - 部分或完整
- 如果用户按回车键,则从
JTextField
- 开始蛮力搜索。
- 如果找到匹配项,将它们放入 a
Vector
并放入 aJList
- 如果未找到匹配项,请添加
String
“未找到匹配项”Vector
JWindow
向用户显示包含结果- 停止
Code:
代码:
package test;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.Vector;
public class AutoCompleteTest extends JFrame{
JTextField city = new JTextField(10);
String enteredName = null;
String[] cities = {"new jersey","new hampshire",
"sussex","essex","london","delhi","new york"};
JList list = new JList();
JScrollPane pane = new JScrollPane();
ResultWindow r = new ResultWindow();
//------------------------------------------------------------------------------
public static void main(String[] args) {
new AutoCompleteTest();
}
//------------------------------------------------------------------------------
public AutoCompleteTest(){
setLayout(new java.awt.FlowLayout());
setVisible(true);
add(city);
// add(pane);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
city.addKeyListener(new TextHandler());
}
//------------------------------------------------------------------------------
public void initiateSearch(String lookFor){
Vector<String> matches = new Vector<>();
lookFor = lookFor.toLowerCase();
for(String each : cities){
if(each.contains(lookFor)){
matches.add(each);
System.out.println("Match: " + each);
}
}
this.repaint();
if(matches.size()!=0){
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}else{
matches.add("No Match Found");
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}
}
//------------------------------------------------------------------------------
public class ResultWindow extends JWindow{
public JScrollPane pane;
public JList searchResult;
//------------------------------------------------------------------------------
public ResultWindow(){
}
//------------------------------------------------------------------------------
public void initiateDisplay(){
pane.setViewportView(searchResult);
add(pane);
pack();
this.setLocation(AutoCompleteTest.this.getX() + 2,
AutoCompleteTest.this.getY()+
AutoCompleteTest.this.getHeight());
// this.setPreferredSize(city.getPreferredSize());
this.setVisible(true);
}
}
//------------------------------------------------------------------------------
class TextHandler implements KeyListener{
@Override
public void keyTyped(KeyEvent e){
}
@Override
public void keyPressed(KeyEvent e){
if(r.isVisible()){
r.setVisible(false);
}
if(e.getKeyChar() == '\n'){
initiateSearch(city.getText());
}
}
@Override
public void keyReleased(KeyEvent e){
}
}
//------------------------------------------------------------------------------
}
Output
输出
Problem
问题
The size of the JWindow
displaying the results (which is a JList
in a JScrollPane
) changes based on the results - if the city name is small, JWindow
is small, if the city name is big, JWindow
is big.
JWindow
显示结果的大小(a JList
in a JScrollPane
)根据结果而变化 - 如果城市名称小,JWindow
则小,如果城市名称大,JWindow
则大。
I have tried every possible combination. I tried using setPreferredDimension()
of the JWindow
, the JList
and JScrollPane
but the issue won't go.
I want it to match the size of the decorated JFrame
no matter what
我已经尝试了所有可能的组合。我试着用setPreferredDimension()
的JWindow
,在JList
和JScrollPane
,但问题得不到解决。无论如何
我都希望它与装饰的尺寸相匹配JFrame
采纳答案by mKorbel
JList
orJComboBox
doesn't returns properPreferredSize
, have to set this value, use JList.setPrototypeCellValue()withpack()
forJWindow
(must be packed after any changes) and or with JList.setVisibleRowCount(), then value returnsgetPreferredScrollableViewportSize()
forJList
inJScrollPane
don't to use
KeyListener
, useDocumentListener
(chars can be inserted from system clipboard) forJTextComponents
don't to reinvent the wheel, use AutoComplete JComboBox / JTextField, you can to redirect / returns result from matches to the popup
JWindow
/ undecoratedJDialog
(quite the best workaround for popup recycle)
JList
或JComboBox
不返回正确PreferredSize
,必须设置此值,使用JList.setPrototypeCellValue()和pack()
forJWindow
(必须在任何更改后打包)和或JList.setVisibleRowCount(),然后值返回getPreferredScrollableViewportSize()
forJList
inJScrollPane
不要使用
KeyListener
,使用DocumentListener
(字符可以从系统剪贴板插入)用于JTextComponents
不要重新发明轮子,使用AutoComplete JComboBox / JTextField,您可以将匹配结果重定向/返回到弹出窗口
JWindow
/未装饰JDialog
(非常适合弹出窗口回收的最佳解决方法)
EDIT
编辑
Anyways so basically I will have to manually create a list of all the cities that are to be supported right ?? bx @Little Child
无论如何,基本上我将不得不手动创建要支持的所有城市的列表,对吗?bx @小孩子
this idea could be quite easy, you can to put
JTable
to theJWindow
with one
Column
,without
JTableHeader
add there RowSorter(see code example in tutorial)
then every steps are done :-), nothing else is required there (maybe bonus to change
Background
ofJTextField
in the case thatRowFilter
returns no matches, addsetVisible
for popup window fromDocumentListener
(be sure to test for!isVisible
))
这种想法可能是相当容易的,你可以把
JTable
到JWindow
与一个
Column
,没有
JTableHeader
添加RowSorter(参见教程中的代码示例)
然后每个步骤都完成了:-),那里不需要其他任何东西(在没有返回匹配项的情况下更改
Background
的奖励,添加弹出窗口(一定要测试))JTextField
RowFilter
setVisible
DocumentListener
!isVisible
回答by Ankit
You need to use the width of the the JFrame
every time you initiate the search and use it calculate the width of the list.
JFrame
每次启动搜索时都需要使用 的宽度,并使用它来计算列表的宽度。
Just change the initiateSearch() function like this:
只需像这样更改initialSearch()函数:
public void initiateSearch(String lookFor){
//add the following two statements to set the width of the list.
int newWidth = AutoCompleteTest.this.getSize().width;
list.setPreferredSize(new Dimension(newWidth, list.getPreferredSize().height));
Vector<String> matches = new Vector<String>();
lookFor = lookFor.toLowerCase();
for(String each : cities){
if(each.contains(lookFor)){
matches.add(each);
System.out.println("Match: " + each);
}
}
this.repaint();
if(matches.size()!=0){
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}else{
matches.add("No Match Found");
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}
}
Here is a sample output:
这是一个示例输出:
and
和
PS: Just for better aesthetics try using some layout to make the text field fill the entire width.
PS:为了更好的美观,请尝试使用一些布局使文本字段填充整个宽度。
回答by Elist
You should use JComboBox, and for the autocompletion, read this article.
回答by joese
One solution would be to change initiateDisplay() to this:
一种解决方案是将initialDisplay()更改为:
public void initiateDisplay()
{
this.pane.setViewportView(this.searchResult);
this.add(this.pane);
this.pack();
this.setLocation(AutoCompleteTest.this.getX() + 2, AutoCompleteTest.this.getY()
+ AutoCompleteTest.this.getHeight());
int padding = 5;
int height = this.searchResult.getModel().getSize()
* AutoCompleteTest.this.city.getSize().height;
int windowWidth = AutoCompleteTest.this.getSize().width;
this.setSize(windowWidth, height);
this.setVisible(true);
}