Реализация автоматического завершения в Java - правильно ли я делаю это?

Алгоритм

  • Начало
  • Введите название города - частичное или полное
  • Если пользователь нажимает Enter, возьмите текст из JTextField
  • Начните поиск грубой силы.
  • Если совпадения найдены, поместите их в Vector и поместите в JList
  • Если совпадение не найдено, добавьте String "Нет совпадения найденных" в Vector
  • Отобразить JWindow пользователю, содержащему результаты
  • Стоп

Код:

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){

        }
    }
//------------------------------------------------------------------------------
}

Выход

enter image description here

Проблема

Размер JWindow, отображающий результаты (который является JList в JScrollPane), изменяется в зависимости от результатов - если название города невелико, JWindow невелик, если название города большой, JWindow большой.

Я пробовал все возможные комбинации. Я попытался использовать setPreferredDimension() для JWindow, JList и JScrollPane, но проблема не исчезнет.
Я хочу, чтобы он соответствовал размеру украшенного JFrame независимо от того, что

Ответ 1

ИЗМЕНИТЬ

В любом случае, так что в принципе мне придется вручную создать список всех города, которые должны поддерживаться правильно? bx @Маленький ребенок

  • эта идея может быть довольно простой, вы можете добавить JTable в JWindow

  • с одним Column,

  • без JTableHeader

  • добавить RowSorter (см. пример кода в учебнике)

  • тогда все шаги выполняются:-), там ничего не требуется (возможно, бонус к изменению Background of JTextField в случае, если RowFilter не возвращает совпадений, добавляет setVisible для всплывающего окна от DocumentListener (обязательно проверьте !isVisible))

Ответ 2

Вам нужно использовать ширину JFrame при каждом запуске поиска и использовать его для вычисления ширины списка.

Просто измените функцию initiateSearch() следующим образом:

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();
        }

    }

Вот пример вывода:

small size

и

enter image description here

PS: Просто для лучшей эстетики попробуйте использовать какой-либо макет, чтобы текстовое поле заполнило всю ширину.

Ответ 3

Вы должны использовать JComboBox, и для автозаполнения прочитайте эту статью.

Ответ 4

Одним из решений было бы изменить initiateDisplay() на это:

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