问题
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
Vectorand put it in aJList - If no match is found, add a
String"No Match Found" inVector - Display
JWindowto user containing the results - Stop
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.
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
回答1:
JListorJComboBoxdoesn'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()forJListinJScrollPanedon't to use KeyListener, use DocumentListener (chars can be inserted from system clipboard) for JTextComponents
don't to reinvent the wheel, use AutoComplete JComboBox / JTextField, you can to redirect / returns result from matches to the popup JWindow / undecorated JDialog(quite the best workaround for popup recycle)
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
this idea could be quite easy, you can to put JTable to the JWindow
with one
Column,without
JTableHeaderadd there RowSorter (see code example in tutorial)
then every steps are done :-), nothing else is required there (maybe bonus to change
BackgroundofJTextFieldin the case thatRowFilterreturns no matches, addsetVisiblefor popup window fromDocumentListener(be sure to test for!isVisible))
回答2:
You should use JComboBox, and for the autocompletion, read this article.
回答3:
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.
Just change the initiateSearch() function like this:
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.
回答4:
One solution would be to change initiateDisplay() to this:
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);
}
来源:https://stackoverflow.com/questions/14849176/implementing-auto-complete-in-java-am-i-doing-it-right