在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 17:36:59  来源:igfitidea点击:

Implementing auto complete in Java - am I doing it right?

javaswingautocompletejframejwindow

提问by Little Child

Algorithm

算法

  1. Start
  2. Input a city name - partial or complete
  3. If the user hits enter , take the text from JTextField
  4. Begin brute force search.
  5. If the matches are found, put them in a Vectorand put it in a JList
  6. If no match is found, add a String"No Match Found" in Vector
  7. Display JWindowto user containing the results
  8. Stop
  1. 开始
  2. 输入城市名称 - 部分或完整
  3. 如果用户按回车键,则从 JTextField
  4. 开始蛮力搜索。
  5. 如果找到匹配项,将它们放入 aVector并放入 aJList
  6. 如果未找到匹配项,请添加String“未找到匹配项”Vector
  7. JWindow向用户显示包含结果
  8. 停止

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

输出

enter image description here

在此处输入图片说明

Problem

问题

The size of the JWindowdisplaying the results (which is a JListin a JScrollPane) changes based on the results - if the city name is small, JWindowis small, if the city name is big, JWindowis big.

JWindow显示结果的大小(a JListin a JScrollPane)根据结果而变化 - 如果城市名称小,JWindow则小,如果城市名称大,JWindow则大。

I have tried every possible combination. I tried using setPreferredDimension()of the JWindow, the JListand JScrollPanebut the issue won't go.
I want it to match the size of the decorated JFrameno matter what

我已经尝试了所有可能的组合。我试着用setPreferredDimension()JWindow,在JListJScrollPane,但问题得不到解决。无论如何
我都希望它与装饰的尺寸相匹配JFrame

采纳答案by mKorbel

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 JTableto the JWindow

  • 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 Backgroundof JTextFieldin the case that RowFilterreturns no matches, add setVisiblefor popup window from DocumentListener(be sure to test for !isVisible))

  • 这种想法可能是相当容易的,你可以把JTableJWindow

  • 与一个Column

  • 没有 JTableHeader

  • 添加RowSorter(参见教程中的代码示例)

  • 然后每个步骤都完成了:-),那里不需要其他任何东西(在没有返回匹配项的情况下更改Background的奖励,添加弹出窗口(一定要测试))JTextFieldRowFiltersetVisibleDocumentListener!isVisible

回答by Ankit

You need to use the width of the the JFrameevery 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:

这是一个示例输出:

small size

小尺寸

and

enter image description here

在此处输入图片说明

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.

您应该使用JComboBox,对于自动完成,请阅读这篇文章

回答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);
    }