java - AutoFilter Combobox 集合模型

标签 java swing autocomplete event-handling jcombobox

我有这个简单的可编辑 JComboBox,它在您键入时过滤可用的选项。 除了一些奇怪的情况外,它几乎可以工作,例如,当您键入“Sass”时,它会将可用选项过滤为单个“Sassi di Matera”,但如果您选择它,它会选择“Arte ruprestre della Vacamonica”,这恰好是 item[0 ] 原始模型而不是过滤后的模型。

我试了几个小时调试它,但似乎是一些奇怪的 updateModel(DefaultComboBoxModel filteredModel),我并没有提高自己。

import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;

public class AutoFilterDocument extends PlainDocument
{
    JComboBox comboBox;
    ComboBoxModel model;
    DefaultComboBoxModel filteredModel;
    JTextComponent editor;
    // flag to indicate if setSelectedItem has been called
    // subsequent calls to remove/insertString should be ignored
    boolean selecting = false;

    public void updateModel(List<String> data)
    {
        model = new DefaultComboBoxModel(data.toArray());
        selecting = true;
        comboBox.setModel(model);
        editor.select(0, 0);
        editor.setCaretPosition(editor.getText().length());
        comboBox.setSelectedItem(null);
        selecting = false;
    }

    public void updateModel(DefaultComboBoxModel filteredModel)
    {
        selecting = true;
        comboBox.setModel(filteredModel);
        editor.select(0, 0);
        editor.setCaretPosition(editor.getText().length());
        selecting = false;
    }

    public AutoFilterDocument(final JComboBox comboBox)
    {
        this.comboBox = comboBox;
        model = comboBox.getModel();
        editor = (JTextComponent) comboBox.getEditor().getEditorComponent();
    }

    @Override
    public void remove(int offs, int len) throws BadLocationException
    {
        if (selecting)
        {
            return;
        }
        String text = getText(0, offs);

        filteredModel = new DefaultComboBoxModel();
        // iterate over all items
        for (int i = 0, n = model.getSize(); i < n; i++)
        {
            Object currentItem = model.getElementAt(i);
            if (currentItem.toString().contains(text))
            {
                filteredModel.addElement(currentItem);
            }
        }
        updateModel(filteredModel);
        super.remove(offs, len);
    }

    @Override
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
    {
        // return immediately when selecting an item
        if (selecting || str == null || str.length() == 0)
        {
            return;
        }

        super.insertString(offs, str, a);
        String text = getText(0, offs); 
        lookupItem(text + str);
    }

    private Object lookupItem(String pattern)
    {
        Object selectedItem = comboBox.getModel().getSelectedItem();
        if (selectedItem != null && selectedItem.toString().toLowerCase().trim().contains(pattern.toLowerCase().trim()))
        {
            filteredModel = filter(pattern);
            updateModel(filteredModel);
            comboBox.setSelectedItem(selectedItem);
            return selectedItem;
        }
        else
        {
            filteredModel = new DefaultComboBoxModel();
            for (int i = 0, n = model.getSize(); i < n; i++)
            {
                Object currentItem = model.getElementAt(i);
                if (currentItem.toString().toLowerCase().trim().contains(pattern.toLowerCase().trim()))
                {
                    filteredModel.addElement(currentItem);
                }
            }
        }
        updateModel(filteredModel);
        if (filteredModel.getSize() > 0)
        {
            return filteredModel.getElementAt(0);
        }
        else
        {
            return null;
        }
    }

    public DefaultComboBoxModel filter(String pattern)
    {
        filteredModel = new DefaultComboBoxModel();
        // iterate over all items
        for (int i = 0, n = model.getSize(); i < n; i++)
        {
            Object currentItem = model.getElementAt(i);
            // current item starts with the pattern?
            if (currentItem.toString().toLowerCase().trim().contains(pattern.toLowerCase().trim()))
            {
                filteredModel.addElement(currentItem);
            }
        }
        return filteredModel;
    }

    private static void createAndShowGUI()
    {
        // the combo box (add/modify items if you like to)
        JComboBox comboBox = new JComboBox(new Object[]
        {
            "Arte rupestre della Valcamonica", "Centro storico di Roma", "Santa Maria delle Grazie", "Centro storico di Firenze", "Venezia e la sua laguna", "La piazza del Duomo di Pisa", "Centro storico di San Gimignano", "I Sassi di Matera", "La città di Vicenza e le Ville del Palladio nel Veneto", "Centro storico di Siena", "Centro storico di Napoli", "Crespi d’Adda", "Ferrara città del Rinascimento e il suo delta del Po", "Castel del Monte", "I trulli di Alberobello", "Monumenti paleocristiani di Ravenna", "Centro storico della città di Pienza", "Aree archeologiche di Pompei, Ercolano e Torre Annunziata", "Il Palazzo Reale del XVII sec. di Caserta con il parco, l’Acquedotto vanvitelliano e il Complesso di S. Leucio", "Costiera Amalfitana", "Modena: Cattedrale, Torre Civica e Piazza Grande", "Portovenere, Cinque Terre e Isole di Palmaria, Tino e Tinetto", "Residenze Sabaude", "Su Nuraxi di Barumini", "Area archeologica di Agrigento", "Villa romana del Casale a Piazza Armerina", "Orto Botanico di Padova", "Area archeologica di "
            + "Aquileia e basilica Patriarcale", "Centro storico di Urbino", "Parco Nazionale del Cilento", "Vallo di Diano", "Certosa di Padula", "Villa Adriana a Tivoli (Roma)", "Assisi, la Basilica di San Francesco e altri siti francescani", "Isole Eolie", "Città di Verona", "Villa d'Este a Tivoli (Roma)", "Città Barocche del Val di Noto", "Sacri Monti di Piemonte e Lombardia", "Monte San Giorgio", "Val d'Orcia", "Necropoli etrusche di Cerveteri e Tarquinia", "Siracusa e la Necropoli rocciosa di Pantalica", "Genova: Le Strade Nuove and the system of the Palazzi dei Rolli", "Mantova e Sabbioneta", "Ferrovia retica nel territorio di Albula/Bernina (Italia/Svizzera)", "Dolomiti", "I longobardi in Italia. Luoghi di potere", "Siti palafitticoli preistorici delle alpi", "Centro storico della città di Salisburgo", "Palazzo e giardini di Schönbrunn", "Panorama culturale di Hallstatt-Dachstein, Salzkammergut", "Ferrovia del Semmering", "Centro storico della città di Graz e Castello Eggenberg", "Panorama culturale della Wachau", "Centro storico di Vienna",
            "Panorama cultura del lago di Neusiedl (in comune con l'Ungheria)", "Antichi insediamenti sulle Alpi", "Parco nazionale Kakadu", "Grande barriera corallina", "Regione dei Laghi Willandra", "Regione selvaggia della Tasmania", "Lord Howe Island", "Riserve della foresta pluviale centro orientale", "Parco nazionale Uluru-Kata Tjuta", "Tropici del Queensland", "Baia degli squali", "Isola di Fraser", "Siti australiani dei mammiferi fossili (Riversleigh/Naracoorte)", "Isole Heard e McDonald", "Isola Macquarie", "Area delle Greater Blue Mountains", "Parco nazionale Purnululu", "Royal Exhibition Building e i Carlton Gardens", "Teatro dell'opera di Sydney", "Undici penitenziari costruiti tra il XVIII e il XIX secolo dall'impero britannico", "Costa di Ningaloo", "La Grande muraglia cinese", "Monte Taishan, provincia dello Shandong", "Palazzi Imperiali delle dinastie Ming e Qing a Pechino (Città proibita) e Shenyang (Palazzo Mukden)", "Grotte di Mogao a Dunhuang", "Provincia del Gansu", "Mausoleo del primo Imperatore Qin a Xi'an provincia di Shaanxi",
            "Sito dell'uomo di Pechino a Zhoukoudian Municipalità di Pechino", "Monti Huangshan provincia di Anhui", "Valle del Jiuzhaigou area di interesse scenico e storico provincia dello Sichuan", "Huanglong area di interesse scenico e storico provincia dello Sichuan", "Wulingyuan area di interesse scenico e storico provincia dello Hunan", "Località montana e templi circostanti Chengde provincia di Hebei", "Tempio e cimitero di Confucio e maniero della famiglia Kong a Qufu provincia dello Shandong", "Antico complesso di edifici nelle Monti Wudang provincia di Hubei", "Insieme storico del Palazzo del Potala Lhasa Tibet", "Parco nazionale Lushan provincia dello Jiangxi", "Area scenica del Monte Emei compreso il Buddha gigante di Leshan provincia dello Sichuan", "Città vecchia di Lijiang provincia di Yunnan", "Antica città di Ping Yao provincia di Shanxi", "Giardini classici di Suzhou provincia di Jiangsu", "Palazzo d'Estate e giardino imperiale di Pechino", "Il Tempio del paradiso: un altare sacrificale imperiale a Pechino",
            "Monte Wuyi provincia di Fujian", "Incisioni rupestri di Dazu provincia di Sichuan", "Monte Qincheng e il sistema di irrigazione del Dujiangyan provincia di Sichuan", "Antichi villaggi nell'Anhui meridionale-Xidi e Hongcun", "Grotte di Longmen vicino Luoyang provincia di Henan", "Tombe imperiali delle dinastie Ming e Qing", "Grotte di Yungang a Datong provincia di Shanxi", "Area protetta dei tre fiumi paralleli dello Yunnan", "Città capitali e tombe dell'antico regno Goguryeo", "Il centro storico di Macao", "Santuari del panda gigante nella provincia di Sichuan", "Sito archeologico di Yin Xu nella provincia di Henan", "Diaolou e i villaggi del Kaiping", "Paesaggio carsico della Cina meridionale", "Tulou di Fujian", "Parco nazionale del monte Sanqingshan", "Monte Wutai[1]", "Monumenti storici di Dengfeng", "Paesaggio culturale del lago dell'ovest di Hangzhou", "Sito fossile di Chengjiang", "Sito di Xanadu", "Mont Saint-Michel e la sua baia", "Cattedrale di Chartres", "Palazzo e Parco di Versailles", "Basilica e collina di Vézelay",
            "Grotte di Lascaux nella valle del Vézère", "Palazzo e Parco di Fontainebleau", "Cattedrale Notre-Dame di Amiens", "Teatro romano e dintorni e l'arco di Orange", "Monumenti Romani e Romanici di Arles", "Abbazia di Fontenay", "Saline Reali di Arc-et-Senans e Saline di Salins-les-Bains", "Place Stanislas Place de la Carrière e Place d'Alliance a Nancy", "Abbazia di Saint-Savin sur Gartempe", "Golfo di Porto Capo Girolata Riserva naturale di Scandola e Calanchi di Piana in Corsica", "Acquedotto romano di Pont du Gard", "Grande île nel centro di Strasburgo", "Parigi Argini della Senna", "Cattedrale di Notre-Dame ex Abbazia di Saint-Remi e Palazzo di Tau a Reims", "Cattedrale di Bourges", "Centro storico di Avignone", "Canal du Midi", "Storica città fortificata di Carcassonne", "Pirenei-Mont Perdu", "Strade francesi per Santiago de Compostela", "Sito storico di Lione", "Giurisdizione di Saint-Émilion", "Campanili di Belgio e Francia", "La Valle della Loira tra Sully-sur-Loire e Chalonnes-sur-Loire", "Provins città delle fiere medioevali",
            "La città di Le Havre", "Bordeaux Porto della Luna", "Fortificazioni di Vauban", "Lagune della Nuova Caledonia", "Città episcopale di Albi", "Antichi insediamenti sulle Alpi", "Causses e Cevenne paesaggio culturale agro-pastorale", "Bacino minerario del Nord-Passo di Calais", "Cattedrale di Aquisgrana", "Cattedrale di Spira", "Residenza di Würzburg con i giardini di corte e la piazza della residenza", "Chiesa del pellegrinaggio di Wies", "Castelli di Augustusburg e Falkenlust a Brühl", "Cattedrale di Santa Maria e Chiesa di San Michele a Hildesheim", "Monumenti Romani Cattedrale di San Pietro e Chiesa di Nostra Signora a Treviri", "Città anseatica di Lubecca", "Confini dell'Impero romano: Vallo di Adriano-Limes germanico-retico-Vallo Antonino", "Palazzi e parchi di Potsdam e Berlino", "Abbazia e vecchia cattedrale di Lorsch", "Miniere di Rammelsberg e città storica di Goslar", "Complesso monastico di Maulbronn", "Città di Bamberga", "Chiesa collegiata castello e città vecchia di Quedlinburg", "Fonderie di Völklingen",
            "Sito fossile del Pozzo di Messel", "Duomo di Colonia", "Il Bauhaus e i suoi siti a Weimar e Dessau", "Città luterane di Eisleben e Wittenberg", "Weimar classica", "Isola dei musei (Museumsinsel) Berlino", "Castello di Wartburg", "Regno giardino di Dessau-Wörlitz", "Isola di Reichenau", "Complesso industriale delle Miniere di carbone dello Zollverein ad Essen", "Gola del Reno fra Coblenza e Bingen", "Centri storici di Stralsund e Wismar", "Il municipio e la statua sulla piazza del mercato di Brema", "Il parco di Bad Muskau / Park Muzakowski", "La valle dell'Elba a Dresda", "Città vecchia di Ratisbona", "Foreste primordiali dei faggi dei Carpazi e Germania", "Residenze in stile moderno di Berlino", "Wattenmeer", "Officine Fagus ad Alfeld an der Leine", "Antichi insediamenti sulle Alpi", "Teatro dell'Opera margraviale di Bayreuth", "Monumenti buddhisti nella regione di Horyu-ji", "Castello di Himeji", "Shirakami-Sanchi", "Yakushima", "Monumenti storici dell'antica Kyoto (città di Kyoto Uji ed Ōtsu)", "Villaggi storici di Shirakawa-go e Gokayama",
            "Memoriale della pace di Hiroshima", "Santuario shintoista di Itsukushima"
        });
        comboBox.setEditable(true);
        JTextComponent editor = (JTextComponent) comboBox.getEditor().getEditorComponent();
        editor.setDocument(new AutoFilterDocument(comboBox));

        // create and show a window containing the combo box
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(3);
        frame.getContentPane().add(comboBox);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

--注意--

如果出现以下情况,请不要推荐其他 GUI 组件:

  • 他们不是 Swing
  • 它们的功能与上述功能不同:按部分字符串过滤组合框、按部分名称过滤下拉列表、单击时选择元素等。
  • 他们正在部分工作或做略有不同的事情

最佳答案

好吧没关系.. 我刚找到我需要的东西:

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;
import org.apache.log4j.Logger;

/**
 * Autocomplete combobox with filtering and text inserting of new text
 *
 * @author Exterminator13
 */
public class AutoCompleteCombo extends JComboBox
{
    private static final Logger logger = Logger.getLogger(AutoCompleteCombo.class);
    private Model model = new Model();
    private final JTextComponent textComponent = (JTextComponent) getEditor().getEditorComponent();
    private boolean modelFilling = false;
    private boolean updatePopup;

    public AutoCompleteCombo()
    {
        setEditable(true);
        setPattern(null);
        updatePopup = false;

        textComponent.setDocument(new AutoCompleteDocument());
        setModel(model);
        setSelectedItem(null);

        new Timer(20, new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if (updatePopup && isDisplayable())
                {
                    setPopupVisible(false);
                    if (model.getSize() > 0)
                    {
                        setPopupVisible(true);
                    }
                    updatePopup = false;
                }
            }
        }).start();
    }

    private class AutoCompleteDocument extends PlainDocument
    {
        boolean arrowKeyPressed = false;
        public AutoCompleteDocument()
        {
            textComponent.addKeyListener(new KeyAdapter()
            {
                @Override
                public void keyPressed(KeyEvent e)
                {
                    int key = e.getKeyCode();
                    if (key == KeyEvent.VK_ENTER)
                    {
                        logger.debug("[key listener] enter key pressed");
                        //there is no such element in the model for now
                        String text = textComponent.getText();
                        if (!model.data.contains(text))
                        {
                            logger.debug("addToTop() called from keyPressed()");
                            addToTop(text);
                        }
                    }
                    else if (key == KeyEvent.VK_UP
                            || key == KeyEvent.VK_DOWN)
                    {
                        arrowKeyPressed = true;
                        logger.debug("arrow key pressed");
                    }
                }
            });
        }

        void updateModel() throws BadLocationException
        {
            String textToMatch = getText(0, getLength());
            logger.debug("setPattern() called from updateModel()");
            setPattern(textToMatch);
        }

        @Override
        public void remove(int offs, int len) throws BadLocationException
        {
            if (modelFilling)
            {
                logger.debug("[remove] model is being filled now");
                return;
            }
            super.remove(offs, len);
            if (arrowKeyPressed)
            {
                arrowKeyPressed = false;
                logger.debug("[remove] arrow key was pressed, updateModel() was NOT called");
            }
            else
            {
                logger.debug("[remove] calling updateModel()");
                updateModel();
            }
            clearSelection();
        }

        @Override
        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
        {
            if (modelFilling)
            {
                logger.debug("[insert] model is being filled now");
                return;
            }
            // insert the string into the document
            super.insertString(offs, str, a);

            String text = getText(0, getLength());
            if (arrowKeyPressed)
            {
                logger.debug("[insert] arrow key was pressed, updateModel() was NOT called");
                model.setSelectedItem(text);
                logger.debug(String.format("[insert] model.setSelectedItem(%s)", text));
                arrowKeyPressed = false;
            }
            else if (!text.equals(getSelectedItem()))
            {
                logger.debug("[insert] calling updateModel()");
                updateModel();
            }

            clearSelection();
        }
    }

    public void setText(String text)
    {
        if (model.data.contains(text))
        {
            setSelectedItem(text);
        }
        else
        {
            addToTop(text);
            setSelectedIndex(0);
        }
    }

    public String getText()
    {
        return getEditor().getItem().toString();
    }
    private String previousPattern = null;

    private void setPattern(String pattern)
    {

        if (pattern != null && pattern.trim().isEmpty())
        {
            pattern = null;
        }

        if (previousPattern == null && pattern == null
                || pattern != null && pattern.equals(previousPattern))
        {
            logger.debug("[setPatter] pattern is the same as previous: " + previousPattern);
            return;
        }
        previousPattern = pattern;
        modelFilling = true;
        model.setPattern(pattern);

        if (logger.isDebugEnabled())
        {
            StringBuilder b = new StringBuilder(100);
            b.append("pattern filter '").append(pattern == null ? "null" : pattern).append("' set:\n");
            for (int i = 0; i < model.getSize(); i++)
            {
                b.append(", ").append('[').append(model.getElementAt(i)).append(']');
            }
            int ind = b.indexOf(", ");
            if (ind != -1)
            {
                b.delete(ind, ind + 2);
            }
            logger.debug(b);
        }
        modelFilling = false;
        if (pattern != null)
        {
            updatePopup = true;
        }
    }

    private void clearSelection()
    {
        int i = getText().length();
        textComponent.setSelectionStart(i);
        textComponent.setSelectionEnd(i);
    }

    public synchronized void addToTop(String aString)
    {
        model.addToTop(aString);
    }

    private class Model extends AbstractListModel implements ComboBoxModel
    {
        String selected;
        final String delimiter = ";;;";
        final int limit = 20;

        class Data
        {
            private List<String> list = new ArrayList<String>(limit);
            private List<String> lowercase = new ArrayList<String>(limit);
            private List<String> filtered;

            void add(String s)
            {
                list.add(s);
                lowercase.add(s.toLowerCase());
            }

            void addToTop(String s)
            {
                list.add(0, s);
                lowercase.add(0, s.toLowerCase());
            }

            void remove(int index)
            {
                list.remove(index);
                lowercase.remove(index);
            }

            List<String> getList()
            {
                return list;
            }

            List<String> getFiltered()
            {
                if (filtered == null)
                {
                    filtered = list;
                }
                return filtered;
            }

            int size()
            {
                return list.size();
            }

            void setPattern(String pattern)
            {
                if (pattern == null || pattern.isEmpty())
                {
                    filtered = list;
                    AutoCompleteCombo.this.setSelectedItem(model.getElementAt(0));
                    logger.debug(String.format("[setPattern] combo.setSelectedItem(null)"));
                }
                else
                {
                    filtered = new ArrayList<String>(limit);
                    pattern = pattern.toLowerCase();
                    for (int i = 0; i < lowercase.size(); i++)
                    {
                        //case insensitive search
                        if (lowercase.get(i).contains(pattern))
                        {
                            filtered.add(list.get(i));
                        }
                    }
                    AutoCompleteCombo.this.setSelectedItem(pattern);
                    logger.debug(String.format("[setPattern] combo.setSelectedItem(%s)", pattern));
                }
                logger.debug(String.format("pattern:'%s', filtered: %s", pattern, filtered));
            }

            boolean contains(String s)
            {
                if (s == null || s.trim().isEmpty())
                {
                    return true;
                }
                s = s.toLowerCase();
                for (String item : lowercase)
                {
                    if (item.equals(s))
                    {
                        return true;
                    }
                }
                return false;
            }
        }
        Data data = new Data();

        void readData()
        {
            String[] countries =
            {
                "Afghanistan",
                "Albania",
                "Algeria",
                "Andorra",
                "Angola",
                "Argentina",
                "Armenia",
                "Austria",
                "Azerbaijan",
                "Bahamas",
                "Bahrain",
                "Bangladesh",
                "Barbados",
                "Belarus",
                "Belgium",
                "Benin",
                "Bhutan",
                "Bolivia",
                "Bosnia & Herzegovina",
                "Botswana",
                "Brazil",
                "Bulgaria",
                "Burkina Faso",
                "Burma",
                "Burundi",
                "Cambodia",
                "Cameroon",
                "Canada",
                "China",
                "Colombia",
                "Comoros",
                "Congo",
                "Croatia",
                "Cuba",
                "Cyprus",
                "Czech Republic",
                "Denmark",
                "Georgia",
                "Germany",
                "Ghana",
                "Great Britain",
                "Greece",
                "Somalia",
                "Spain",
                "Sri Lanka",
                "Sudan",
                "Suriname",
                "Swaziland",
                "Sweden",
                "Switzerland",
                "Syria",
                "Uganda",
                "Ukraine",
                "United Arab Emirates",
                "United Kingdom",
                "United States",
                "Uruguay",
                "Uzbekistan",
                "Vanuatu",
                "Venezuela",
                "Vietnam",
                "Yemen",
                "Zaire",
                "Zambia",
                "Zimbabwe"
            };

            for (String country : countries)
            {
                data.add(country);
            }
        }
        boolean isThreadStarted = false;

        void writeData()
        {
            StringBuilder b = new StringBuilder(limit * 60);

            for (String url : data.getList())
            {
                b.append(delimiter).append(url);
            }
            b.delete(0, delimiter.length());

            //waiting thread is already being run
            if (isThreadStarted)
            {
                return;
            }
            //we do saving in different thread
            //for optimization reasons (saving may take much time)
            new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    //we do sleep because saving operation
                    //may occur more than one per waiting period
                    try
                    {
                        Thread.sleep(2000);
                    }
                    catch (InterruptedException ex)
                    {
                    }
                    //we need this synchronization to
                    //synchronize with AutoCompleteCombo.addElement method
                    //(race condition may occur)
                    synchronized (AutoCompleteCombo.this)
                    {

                        //HERE MUST BE SAVING OPERATION
                        //(SAVING INTO FILE OR SOMETHING)
                        //don't forget replace readData() method
                        //to read saved data when creating bean

                        isThreadStarted = false;
                    }
                }
            }).start();
            isThreadStarted = true;
        }

        public Model()
        {
            readData();
        }

        public void setPattern(String pattern)
        {
            int size1 = getSize();
            data.setPattern(pattern);
            int size2 = getSize();
            if (size1 < size2)
            {
                fireIntervalAdded(this, size1, size2 - 1);
                fireContentsChanged(this, 0, size1 - 1);
            }
            else if (size1 > size2)
            {
                fireIntervalRemoved(this, size2, size1 - 1);
                fireContentsChanged(this, 0, size2 - 1);
            }
        }

        public void addToTop(String aString)
        {
            if (aString == null || data.contains(aString))
            {
                return;
            }
            if (data.size() == 0)
            {
                data.add(aString);
            }
            else
            {
                data.addToTop(aString);
            }

            while (data.size() > limit)
            {
                int index = data.size() - 1;
                data.remove(index);
            }

            setPattern(null);
            model.setSelectedItem(aString);
            logger.debug(String.format("[addToTop] model.setSelectedItem(%s)", aString));

            //saving into options
            if (data.size() > 0)
            {
                writeData();
            }
        }

        @Override
        public Object getSelectedItem()
        {
            return selected;
        }

        @Override
        public void setSelectedItem(Object anObject)
        {
            if ((selected != null && !selected.equals(anObject))
                    || selected == null && anObject != null)
            {
                selected = (String) anObject;
                fireContentsChanged(this, -1, -1);
            }
        }

        @Override
        public int getSize()
        {
            return data.getFiltered().size();
        }

        @Override
        public Object getElementAt(int index)
        {
            return data.getFiltered().get(index);
        }
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(3, 1));
                final JLabel label = new JLabel("label ");
                frame.add(label);
                final AutoCompleteCombo combo = new AutoCompleteCombo();
                frame.add(combo);
                frame.pack();
                frame.setSize(500, frame.getHeight());
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

关于java - AutoFilter Combobox 集合模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17680776/

相关文章:

php - 我需要一个 jQuery Autocomplete 使用 ajax 返回 id 和 name 的示例

Java 正则表达式查看字符串是否包含 %s、%d、%n

java - 在maven结构中生成java源的脚本放在哪里?

java - 我应该链接 GUI 测试还是每次都重新启动小程序?

mysql - 如何在单个图表上从两个不同的 MySQL 表生成结果

javascript - 很棒的设置标签文本字段和隐藏字段值

java - 在 Eclipse 调试器中启动后进程暂停

java - Wildfly 在 Debug模式下部署超时

java - 组件在 JPanel 中不可见

jquery - 如何使用 jquery 将自动完成搜索中的值发送到 spring mvc 中的 Controller