Фильтр jcombobox в java - выглядит и чувствует себя независимым

У меня есть простой код фильтра JComboBox:

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class FilterComboBox extends JComboBox {
    private List<String> array;

    public FilterComboBox(List<String> array) {
        super(array.toArray());
        this.array = array;
        this.setEditable(true);
        final JTextField textfield = (JTextField) this.getEditor().getEditorComponent();
        textfield.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent ke) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        comboFilter(textfield.getText());
                    }
                });
            }
        });

    }

    public void comboFilter(String enteredText) {
        List<String> filterArray= new ArrayList<String>();
        for (int i = 0; i < array.size(); i++) {
            if (array.get(i).toLowerCase().contains(enteredText.toLowerCase())) {
                filterArray.add(array.get(i));
            }
        }
        if (filterArray.size() > 0) {
            this.setModel(new DefaultComboBoxModel(filterArray.toArray()));
            this.setSelectedItem(enteredText);
            this.showPopup();
        }
        else {
            this.hidePopup();
        }
    }

    /* Testing Codes */
    public static List<String> populateArray() {
        List<String> test = new ArrayList<String>();
        test.add("");
        test.add("Mountain Flight");
        test.add("Mount Climbing");
        test.add("Trekking");
        test.add("Rafting");
        test.add("Jungle Safari");
        test.add("Bungie Jumping");
        test.add("Para Gliding");
        return test;
    }

    public static void makeUI() {
        JFrame frame = new JFrame("Adventure in Nepal - Combo Filter Test");
        FilterComboBox acb = new FilterComboBox(populateArray());
        frame.getContentPane().add(acb);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception {

        //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        makeUI();
    }
}

Производительность комбинированного фильтра не так хороша, но она подходит для небольшого количества наборов данных. Моя проблема в том, что когда я удаляю комментарий UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");, чтобы изменить внешний вид, фильтр не работает. В WindowsLookAndFeel поле со списком принимает в нем только один символ, заменяя ранее введенный символ.

Различные результаты после ввода 'moun'

Не могли бы вы рассказать мне, что происходит? ответ Маноджа Шреста ниже каким-то образом помогает, но не могли бы вы предоставить другие предложения для создания фильтра поля со списком в Java?


person Community    schedule 29.04.2012    source источник
comment
Чтобы быстрее получить помощь, опубликуйте 1 SSCCE.   -  person Andrew Thompson    schedule 29.04.2012
comment
@AndrewThompson, спасибо за комментарий. Я просмотрел статью, но не смог понять, какой момент мне не хватает в моем вопросе - [Короткий автономный правильный пример]?   -  person gtiwari333    schedule 29.04.2012
comment
SSCCE — это один образец кода, а не два. Как упоминалось в статье, понизьте классы до значений по умолчанию и выгрузите их в тот же исходный файл, что и main(). Также включите импорт. Что касается различных PLAF, во время выполнения вы можете подсказать, какие тестировать.   -  person Andrew Thompson    schedule 29.04.2012
comment
еще раз спасибо. Я исправил вопрос, чтобы соответствовать SSCCE.   -  person gtiwari333    schedule 29.04.2012
comment
Отлично работает на Aqua и Nimbus; +1 за sscce.   -  person trashgod    schedule 29.04.2012
comment
Хороший вопрос, я время от времени наблюдал поведение при использовании Windows 7 (чаще всего) при использовании родного PLAf, но не металла (т.е. может подтвердить ваши результаты) в Java 1.6.0_29-b11. Мы можем исключить, что это «ошибка с Java 7», но у меня нет новой информации или сведений о причине или исправлении. :(   -  person Andrew Thompson    schedule 29.04.2012
comment
@ Эндрю Томпсон, пожалуйста, не мог бы его величество протестировать код из моего ответа в Win7 / Java 7   -  person mKorbel    schedule 29.04.2012
comment
@AndrewThompson, может быть, я не совсем понял ваш комментарий, но моя версия JDK 6-jdk1.6.0_30. Итак, является ли это ошибкой (если это действительно так) и с JDK 6. Не так ли?   -  person gtiwari333    schedule 29.04.2012
comment
@gt_ebuddy Извините. Мой комментарий был на самом деле к mKorbel. Я сделаю это правильно. Что касается «ошибки и в 1.6», то не уверен, что это вообще ошибка, но в 1.7 замечено много проблем, которых нет в 1.6.   -  person Andrew Thompson    schedule 29.04.2012
comment
@mKorbel Хммм... Чувствую себя о. ленивым (тратить слишком много времени, пытаясь помочь злобным неблагодарным, утомило меня). Не могли бы вы сшить его в 1 код, который я могу выбрать (на панели параметров) во время выполнения, который нужно протестировать? Возможно, подробнее об этом позже, но я голосую за ваш ответ за 1-й пункт в списке вверху — «привязки клавиш».   -  person Andrew Thompson    schedule 29.04.2012
comment
У меня здесь нет окон, поэтому я даже не могу проверить, но, пожалуйста, посмотрите, решит ли удаление this.setSelectedItem(enteredText); вашу проблему (даже если это не то, что вам нужно). Если это так, фильтр действительно не имеет никакого отношения к проблеме.   -  person kritzikratzi    schedule 05.05.2012


Ответы (5)


Во-первых, вы каждый раз создаете новую модель, а затем вызываете всплывающее окно из кода, что приводит к мерцанию и т. д. Мы можем изменить саму модель. Во-вторых, вы устанавливаете текущий введенный текст как выбранный элемент, который, похоже, имеет поведение selectAll, как отмечалось другими. Я изменил код следующим образом:

public void comboFilter(String enteredText) {
    if (!this.isPopupVisible()) {
        this.showPopup();
    }

    List<String> filterArray= new ArrayList<String>();
    for (int i = 0; i < array.size(); i++) {
        if (array.get(i).toLowerCase().contains(enteredText.toLowerCase())) {
            filterArray.add(array.get(i));
        }
    }
    if (filterArray.size() > 0) {
        DefaultComboBoxModel model = (DefaultComboBoxModel) this.getModel();
        model.removeAllElements();
        for (String s: filterArray)
            model.addElement(s);

        JTextField textfield = (JTextField) this.getEditor().getEditorComponent();
        textfield.setText(enteredText);
    }
}

Надеюсь, это сработает для вас.

person Ashwinee K Jha    schedule 07.05.2012
comment
Спасибо за ваш комментарий . но он все еще не работает. pastebin.com/CbDZ7Uhg - person gtiwari333; 10.05.2012
comment
Можете ли вы сообщить мне, что именно не работает? Примечание. Я попробовал этот код с внешним видом Windows (UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel)) и, похоже, работал нормально. - person Ashwinee K Jha; 10.05.2012
comment
Если вы сначала нажмете на раскрывающийся список, прежде чем начать печатать, это работает нормально. Именно так я тестировал. Я редактирую код так, чтобы он работал нормально, не нажимая раскрывающийся список. - person Ashwinee K Jha; 10.05.2012
comment
Извините, я ранее запускал ваш код с комментарием //this.showPoupup() (в коде из вашего предыдущего редактирования). После того, как я удалил комментарий, он показывает отфильтрованное всплывающее окно без мерцания. Это действительно здорово. Хотя есть некоторые проблемы, такие как: 1) всплывающее окно, показывающее пустые строки при отображении отфильтрованного списка. 2) когда я выбираю один из отфильтрованных элементов с помощью клавиши со стрелкой вниз и нажимаю ввод. а затем нажмите клавишу Backspace, чтобы удалить выделенный текст - › список в поле со списком кажется сжатым. Я не очень хорошо знаком со свингом. Не могли бы вы посмотреть на это? - person gtiwari333; 10.05.2012
comment
Пожалуйста, попробуйте отредактированный код, он должен нормально работать для # 2. Что касается № 1, лучше сохранить фиксированный размер всплывающего окна, поскольку это позволяет избежать ненужного изменения размера/мерцания. - person Ashwinee K Jha; 10.05.2012
comment
Я только что нашел еще одну проблему: 3) первый элемент в отфильтрованном списке никогда не выбирался, когда я нажимаю клавишу ВВОД. Его можно выбрать только щелчком мыши. И к вашему сведению, проблема №2 осталась прежней. №1 не имеет большого значения. - person gtiwari333; 10.05.2012
comment
Это не работает в некоторых случаях, когда JComboBox находится в DefaultCellEditor и используется в JTable. Модель model.removeAllElements() вызывает остановку события редактирования и вызывает преждевременное обновление содержимого ячейки таблицы. - person Jason; 19.01.2013

очень длинный ответ, я думаю, что отличный пример того, как разные Look и Feel реализовали методы в API и работают

  • KeyListener не является подходящим прослушивателем для Swing JComponents, вам действительно нужно беспокоиться о KeyBindings,

  • KeyListener простой асинхронный,

  • JComboBox - это Compound JComponent, тогда требуется переопределить внутренние JComponents, весь вывод из KeyListener должен быть обернут в invokeLater(), обратите внимание, что я могу создать событие из coumpond JComponents, которое дважды invokeLater() не возвращает ожидаемый вывод в графический интерфейс, только Swing Таймер с Swing Action может сделать это правильно, просто зачем возиться с этим примером о неправильном пути,

код

import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

public class ComboBoxHoverOver {

    private JComboBox combo = new JComboBox();

    public ComboBoxHoverOver() {
        combo.setPrototypeDisplayValue("XXXXXXXXXXXXXXXXXXXXXX");
        combo.setRenderer(new ComboToolTipRenderer(combo));
        combo.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                //System.out.println(combo.getSelectedItem().toString());
            }
        });
        combo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                //System.out.println(combo.getSelectedItem().toString());
            }
        });
        combo.addItem("");
        combo.addItem("Long text 4");
        combo.addItem("Long text 3");
        combo.addItem("Long text 2");
        combo.addItem("Long text 1");
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(combo);
        f.pack();
        f.setVisible(true);
    }

    private class ComboToolTipRenderer extends BasicComboBoxRenderer {

        private static final long serialVersionUID = 1L;
        private JComboBox combo;
        private JList comboList;

        ComboToolTipRenderer(JComboBox combo) {
            this.combo = combo;
        }

        @Override
        public Component getListCellRendererComponent(JList list, Object value,
                int index, boolean isSelected, boolean cellHasFocus) {
            super.getListCellRendererComponent(
                    list, value, index, isSelected, cellHasFocus);
            if (comboList == null) {
                comboList = list;
                KeyAdapter listener = new KeyAdapter() {

                    @Override
                    public void keyReleased(KeyEvent e) {
                        if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_UP) {
                            int x = 5;
                            int y = comboList.indexToLocation(comboList.getSelectedIndex()).y;
                            System.out.println(comboList.getSelectedIndex());
                        }
                    }
                };
                combo.addKeyListener(listener);
                combo.getEditor().getEditorComponent().addKeyListener(listener);
            }
            if (isSelected) {
                //System.out.println(value.toString());
            }
            return this;
        }
    }

    public static void main(String[] args) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                ComboBoxHoverOver comboBoxHoverOver = new ComboBoxHoverOver();
            }
        });
    }
}
  • JComboBox - это Compound JComponent, тогда требуется переопределить BasicComboBoxUI, пожалуйста, извините, я ленив писать и имитировать слишком длинный код как код из первой точки

  • в противном случае все усилия, предпринимаемые двумя вышеперечисленными пунктами, бесполезны и контрпродуктивны, ничего больше, только ДОТ.


пожалуйста, может кто-нибудь протестировать следующий код в * nix и Apple OS X

из моего компилятора Java6 WinXP (все важное скрыто в используемых методах, кроме респекта анонимному автору из бывшей Sun Microsystems)

Вещество L&F

введите здесь описание изображения

WindowsLookAndFeel L&F

введите здесь описание изображения

Нимбус Л&Ф

введите здесь описание изображения

Металл L&F

введите здесь описание изображения

из классов Java

главный

import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import org.pushingpixels.substance.api.skin.SubstanceOfficeSilver2007LookAndFeel;

public class AutoCompleteTextField {

    private static JFrame frame = new JFrame();
    private ArrayList<String> listSomeString = new ArrayList<String>();
    private Java2sAutoTextField someTextField = new Java2sAutoTextField(listSomeString);
    private ArrayList<String> listSomeAnotherString = new ArrayList<String>();
    private Java2sAutoComboBox someComboBox = new Java2sAutoComboBox(listSomeAnotherString);

    public AutoCompleteTextField() {
        listSomeString.add("-");
        listSomeString.add("Snowboarding");
        listSomeString.add("Rowing");
        listSomeString.add("Knitting");
        listSomeString.add("Speed reading");
        listSomeString.add("Pool");
        listSomeString.add("None of the above");
//
        listSomeAnotherString.add("-");
        listSomeAnotherString.add("XxxZxx Snowboarding");
        listSomeAnotherString.add("AaaBbb Rowing");
        listSomeAnotherString.add("CccDdd Knitting");
        listSomeAnotherString.add("Eee Fff Speed reading");
        listSomeAnotherString.add("Eee Fff Pool");
        listSomeAnotherString.add("Eee Fff None of the above");
//
        someTextField.setFont(new Font("Serif", Font.BOLD, 16));
        someTextField.setForeground(Color.black);
        someTextField.setBackground(Color.orange);
        someTextField.setName("someTextField");
        someTextField.setDataList(listSomeString);
//
        someComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        someComboBox.setFont(new Font("Serif", Font.BOLD, 16));
        someComboBox.setForeground(Color.black);
        someComboBox.setBackground(Color.YELLOW);
        someComboBox.getEditor().selectAll();
        someComboBox.getEditor().getEditorComponent().setBackground(Color.YELLOW);
        ((JTextField) someComboBox.getEditor().getEditorComponent()).setDisabledTextColor(Color.black);
        someComboBox.setName("someComboBox");
        someComboBox.setDataList(listSomeAnotherString);
//
        frame.setLayout(new GridLayout(0, 1, 10, 10));
        frame.add(someTextField);
        frame.add(someComboBox);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocation(100, 100);
        frame.pack();
        frame.setVisible(true);
//
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                someTextField.setText("-");
                someComboBox.getEditor().setItem(0);
                someComboBox.getEditor().selectAll();
                someTextField.grabFocus();
                someTextField.requestFocus();
                someTextField.setText(someTextField.getText());
                someTextField.selectAll();
            }
        });

    }

    public static void main(String[] args) {
        /*SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                try {
                    UIManager.setLookAndFeel(new SubstanceOfficeSilver2007LookAndFeel());
                    SwingUtilities.updateComponentTreeUI(frame);
                } catch (UnsupportedLookAndFeelException e) {
                    throw new RuntimeException(e);
                }
            }
        });*/
        /*try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            System.out.println(info.getName());
            if ("Nimbus".equals(info.getName())) {
            UIManager.setLookAndFeel(info.getClassName());
            break;
            }
            }
        } catch (UnsupportedLookAndFeelException e) {
            // handle exception
        } catch (ClassNotFoundException e) {
            // handle exception
        } catch (InstantiationException e) {
            // handle exception
        } catch (IllegalAccessException e) {
            // handle exception
        }*/
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                AutoCompleteTextField aCTF = new AutoCompleteTextField();
            }
        });
    }
}

Автосо списком

import java.awt.event.ItemEvent;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.plaf.basic.BasicComboBoxEditor;

public class Java2sAutoComboBox extends JComboBox {

    private static final long serialVersionUID = 1L;
    private AutoTextFieldEditor autoTextFieldEditor;
    private boolean isFired;

    private class AutoTextFieldEditor extends BasicComboBoxEditor {

        private Java2sAutoTextField getAutoTextFieldEditor() {
            return (Java2sAutoTextField) editor;
        }

        AutoTextFieldEditor(java.util.List<String> list) {
            editor = new Java2sAutoTextField(list, Java2sAutoComboBox.this);
        }
    }

    public Java2sAutoComboBox(java.util.List<String> list) {
        isFired = false;
        autoTextFieldEditor = new AutoTextFieldEditor(list);
        setEditable(true);
        setModel(new DefaultComboBoxModel(list.toArray()) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void fireContentsChanged(Object obj, int i, int j) {
                if (!isFired) {
                    super.fireContentsChanged(obj, i, j);
                }
            }
        });
        setEditor(autoTextFieldEditor);
    }

    public boolean isCaseSensitive() {
        return autoTextFieldEditor.getAutoTextFieldEditor().isCaseSensitive();
    }

    public void setCaseSensitive(boolean flag) {
        autoTextFieldEditor.getAutoTextFieldEditor().setCaseSensitive(flag);
    }

    public boolean isStrict() {
        return autoTextFieldEditor.getAutoTextFieldEditor().isStrict();
    }

    public void setStrict(boolean flag) {
        autoTextFieldEditor.getAutoTextFieldEditor().setStrict(flag);
    }

    public java.util.List<String> getDataList() {
        return autoTextFieldEditor.getAutoTextFieldEditor().getDataList();
    }

    public void setDataList(java.util.List<String> list) {
        autoTextFieldEditor.getAutoTextFieldEditor().setDataList(list);
        setModel(new DefaultComboBoxModel(list.toArray()));
    }

    void setSelectedValue(Object obj) {
        if (isFired) {
            return;
        } else {
            isFired = true;
            setSelectedItem(obj);
            fireItemStateChanged(new ItemEvent(this, 701, selectedItemReminder, 1));
            isFired = false;
            return;
        }
    }

    @Override
    protected void fireActionEvent() {
        if (!isFired) {
            super.fireActionEvent();
        }
    }
}

Автотекстовое поле

import java.util.List;
import javax.swing.JTextField;
import javax.swing.text.*;

public class Java2sAutoTextField extends JTextField {

    private static final long serialVersionUID = 1L;
    private List<String> dataList;
    private boolean isCaseSensitive;
    private boolean isStrict;
    private Java2sAutoComboBox autoComboBox;

    public class AutoDocument extends PlainDocument {

        private static final long serialVersionUID = 1L;

        @Override
        public void replace(int i, int j, String s, AttributeSet attributeset)
                throws BadLocationException {
            super.remove(i, j);
            insertString(i, s, attributeset);
        }

        @Override
        public void insertString(int i, String s, AttributeSet attributeset)
                throws BadLocationException {
            if (s == null || "".equals(s)) {
                return;
            }
            String s1 = getText(0, i);
            String s2 = getMatch(s1 + s);
            int j = (i + s.length()) - 1;
            if (isStrict && s2 == null) {
                s2 = getMatch(s1);
                j--;
            } else if (!isStrict && s2 == null) {
                super.insertString(i, s, attributeset);
                return;
            }
            if (autoComboBox != null && s2 != null) {
                autoComboBox.setSelectedValue(s2);
            }
            super.remove(0, getLength());
            super.insertString(0, s2, attributeset);
            setSelectionStart(j + 1);
            setSelectionEnd(getLength());
        }

        @Override
        public void remove(int i, int j) throws BadLocationException {
            int k = getSelectionStart();
            if (k > 0) {
                k--;
            }
            String s = getMatch(getText(0, k));
            if (!isStrict && s == null) {
                super.remove(i, j);
            } else {
                super.remove(0, getLength());
                super.insertString(0, s, null);
            }
            if (autoComboBox != null && s != null) {
                autoComboBox.setSelectedValue(s);
            }
            try {
                setSelectionStart(k);
                setSelectionEnd(getLength());
            } catch (Exception exception) {
            }
        }
    }

    public Java2sAutoTextField(List<String> list) {
        isCaseSensitive = false;
        isStrict = true;
        autoComboBox = null;
        if (list == null) {
            throw new IllegalArgumentException("values can not be null");
        } else {
            dataList = list;
            init();
            return;
        }
    }

    Java2sAutoTextField(List<String> list, Java2sAutoComboBox b) {
        isCaseSensitive = false;
        isStrict = true;
        autoComboBox = null;
        if (list == null) {
            throw new IllegalArgumentException("values can not be null");
        } else {
            dataList = list;
            autoComboBox = b;
            init();
            return;
        }
    }

    private void init() {
        setDocument(new AutoDocument());
        if (isStrict && dataList.size() > 0) {
            setText(dataList.get(0).toString());
        }
    }

    private String getMatch(String s) {
        for (int i = 0; i < dataList.size(); i++) {
            String s1 = dataList.get(i).toString();
            if (s1 != null) {
                if (!isCaseSensitive
                        && s1.toLowerCase().startsWith(s.toLowerCase())) {
                    return s1;
                }
                if (isCaseSensitive && s1.startsWith(s)) {
                    return s1;
                }
            }
        }

        return null;
    }

    @Override
    public void replaceSelection(String s) {
        AutoDocument _lb = (AutoDocument) getDocument();
        if (_lb != null) {
            try {
                int i = Math.min(getCaret().getDot(), getCaret().getMark());
                int j = Math.max(getCaret().getDot(), getCaret().getMark());
                _lb.replace(i, j - i, s, null);
            } catch (Exception exception) {
            }
        }
    }

    public boolean isCaseSensitive() {
        return isCaseSensitive;
    }

    public void setCaseSensitive(boolean flag) {
        isCaseSensitive = flag;
    }

    public boolean isStrict() {
        return isStrict;
    }

    public void setStrict(boolean flag) {
        isStrict = flag;
    }

    public List<String> getDataList() {
        return dataList;
    }

    public void setDataList(List<String> list) {
        if (list == null) {
            throw new IllegalArgumentException("values can not be null");
        } else {
            dataList = list;
            return;
        }
    }
}

РЕДАКТИРОВАТЬ

вывод из Win7 64b/Java7

Металл L&F

введите здесь описание изображения

Windows L&F (смешное пустое пространство рядом с кнопкой в ​​JComboBox)

введите здесь описание изображения

Нимбус Л&Ф

введите здесь описание изображения

не стесняйтесь редактировать (я)

person mKorbel    schedule 29.04.2012
comment
Спасибо, это действительно длинный ответ. Но я хотел иметь Filter , а не функцию автозаполнения для моего JComboBox. - person gtiwari333; 30.04.2012
comment
@gt_ebuddy huuuuh, извините, речь идет о фильтрации, для правильного вывода из JTextComponent вы должны использовать только Document/DocumentListener - person mKorbel; 30.04.2012
comment
Я внес некоторые изменения в использование DocumentListener — pastebin.com/btMHW9QR. Но получаю ошибку: java.lang.IllegalStateException: Попытка изменить в уведомлении. Похоже, мы не можем изменить содержимое JTextComponent из его DocumentListener. Не могли бы вы посмотреть и прокомментировать, что делать.? - person gtiwari333; 01.05.2012
comment
@gt_ebuddy, пожалуйста, зачем изобретать велосипед, не делайте этого таким образом, вам нужно заменить документ, я отправил сюда хороший код, созданный великими умами, используйте его или измените в соответствии с вашими требованиями. - person mKorbel; 01.05.2012

очевидно, сбой в используемом компоненте текстового поля. Что происходит, когда используется внешний вид окна, текст в этом компоненте выбирается так же, как с использованием строки «textfield.selectAll();», и, следовательно, когда вы вводите что-либо еще, выделенный текст очищается из компонента текстового поля. Таким образом, в приведенном ниже коде положение каретки этого компонента регулируется. Вот как это работает: сначала сохраните текущую позицию курсора текстового поля в переменной «currentCaretPosition», затем переместите позицию курсора в начало текста в компоненте. После фильтрации положение каретки восстанавливается до значения переменной «currentCaretPosition». Я надеюсь, что это работает так, как вы хотите.

Уточненный код приведен ниже: -

                                       /****Beginning of code****/
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class FilterComboBox extends JComboBox {
    private List<String> array;
    private int currentCaretPosition=0;


    public FilterComboBox(List<String> array) {
        super(array.toArray());
        this.array = array;
        this.setEditable(true);
        final JTextField textfield = (JTextField) this.getEditor().getEditorComponent();
        textfield.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent ke) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        currentCaretPosition=textfield.getCaretPosition();
                        if(textfield.getSelectedText()==null)
                        {
                        textfield.setCaretPosition(0);
                        comboFilter(textfield.getText());
                        textfield.setCaretPosition(currentCaretPosition);
                        }
                     }
                });
            }

        });

    }

    public void comboFilter(String enteredText) {
        List<String> filterArray= new ArrayList<String>();
        for (int i = 0; i < array.size(); i++) {
            if (array.get(i).toLowerCase().contains(enteredText.toLowerCase())) {
                filterArray.add(array.get(i));
            }


        }
        if (filterArray.size() > 0) {

            this.setModel(new DefaultComboBoxModel(filterArray.toArray()));
            this.setSelectedItem(enteredText);
            this.showPopup();
        }
        else {
            this.hidePopup();
        }
    }

    /* Testing Codes */
    public static List<String> populateArray() {
        List<String> test = new ArrayList<String>();
        test.add("");
        test.add("Mountain Flight");
        test.add("Mount Climbing");
        test.add("Trekking");
        test.add("Rafting");
        test.add("Jungle Safari");
        test.add("Bungie Jumping");
        test.add("Para Gliding");
        return test;
    }

    public static void makeUI() {
        JFrame frame = new JFrame("Adventure in Nepal - Combo Filter Test");
        FilterComboBox acb = new FilterComboBox(populateArray());
        frame.getContentPane().add(acb);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception {

        UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        makeUI();
    }
}


                                       /******* End of code**********/
person Community    schedule 18.07.2013
comment
Сочетание вашего кода вставки с comboFilter() @Ashwinee дает лучший редактируемый ComboBox. Спасибо парень! - person Noor ul Ain; 09.03.2021

Этот компонент называется автозаполнением и включен в так называемый проект расширений свинга.

Просто взгляните на: http://swingx.java.net/
Вот веб-старт: http://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp

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

person Dudelilama    schedule 10.05.2012
comment
Привет, я должен признать, что автозаполнение не фильтрует. Но цель обоих компонентов должна быть одинаковой — более быстрый пользовательский ввод. И автозаполнение отлично работает для этого ;-) - person Dudelilama; 11.05.2012
comment
но фильтр допускает частичное совпадение и позволяет выбрать нужный элемент из отфильтрованного (сокращенного) списка. - person gtiwari333; 11.05.2012
comment
Вы можете попробовать заказать элементы, у вас будет похожее поведение, без проблем с производительностью и других нежелательных проблем. - person Dudelilama; 15.05.2012

Похоже, как вы упомянули, когда пользователь вводит какие-либо тексты в поле со списком, Windows Look & Feel выбирает (подсвечивает) введенный текст. Итак, когда вы нажимаете другую клавишу, она заменяет предыдущую. Итак, решение состоит в том, чтобы не выделять введенные тексты. Вы можете добиться этого, добавив любое из следующих утверждений в свой прослушиватель ключей.

textfield.setCaretPosition(textfield.getText().length());

OR

textfield.setSelectionStart(textfield.getText().length());

Итак, ваш ключевой прослушиватель должен выглядеть так:

final JTextField textfield = (JTextField) this.getEditor().getEditorComponent();
    textfield.addKeyListener(new KeyAdapter() {
        public void keyReleased(KeyEvent ke) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    comboFilter(textfield.getText());
                    textfield.setCaretPosition(textfield.getText().length());
                }
            });
        }
    });
person Manoj Shrestha    schedule 04.05.2012
comment
НЕ ДЕЛАЙТЕ ЭТОГО. КОГДА-ЛИБО. это, например, полностью отключит клавиши управления курсором. это также приведет к совершенно безумным результатам, когда пользователь щелкнет в середине текста и наберет несколько символов. - person kritzikratzi; 05.05.2012