jcombobox filtre en java Look and feel indépendant

j'ai un code de filtre JComboBox simple comme ceci:

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

la performance du filtre combo n'est pas si bonne mais il est très bien pour quelques ensembles de données. Mon problème est lorsque je supprime le commentaire UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); pour changer l'apparence, le filtre ne fonctionne pas. Dans WindowsLookAndFeel, la boîte combo ne prend qu'un seul caractère en remplaçant le caractère entré précédemment.

Different Outputs after typing 'moun'

pouvez-vous s'il vous plaît me dire ce qui se passe? Manoj Shrestha est la réponse ci-dessous aide d'une certaine façon , mais, pouvez-vous s'il vous plaît fournir quelques autres suggestions pour réaliser le filtre de boîte combo en Java?

10
demandé sur gtiwari333 2012-04-29 04:59:26

5 réponses

tout d'abord vous créez un nouveau modèle à chaque fois et ensuite vous invitez show popup à partir du code qui mène au clignotement etc. Nous pouvons modifier le modèle lui-même. Deuxièmement, vous définissez le texte actuellement entré comme élément sélectionné qui semble avoir un comportement selectAll comme noté par d'autres. J'ai modifié le code comme suit:

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

j'Espère que cela fonctionne pour vous.

12
répondu Ashwinee K Jha 2012-05-10 16:18:10

réponse très longue, je pense que cet exemple exelent sur la façon dont différents Look et Feel ont été mis en œuvre des méthodes dans L'API et fonctionne

  • KeyListener N'est pas un bon auditeur pour Swing JComponents, vous devez vraiment avoir des problèmes avec KeyBindings,

  • KeyListener est simple asynchrone,

  • JComboBox est composé JComponent, alors il est nécessaire de surpasser JComponents internes, toute sortie de KeyListener doit être enveloppé dans invokeLater (), noter que je peux créer un événement à partir de Coumpond JComponents qui deux fois invokeLater () ne renvoie pas la sortie attendue à L'interface graphique, seul Swing Timer avec Swing Action peut le faire correctement, simple pourquoi déranger wiht cet exemple sur la mauvaise voie,

code

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 est composé JComponent, alors il est nécessaire de surcharger BasicComboBoxUI, s'il vous plaît désolé je paresseux d'écrire et de simuler trop longtemps code comme le code du premier point

  • sinon tous les efforts au-dessus de deux points sont inutiles et contraproductifs, rien d'autre, seulement point


s'il vous plaît quelqu'un peut-il tester suit le code sous *nix et apple OS X

à partir de mon Java6 WinXP compo (tous les important est caché dans les méthodes utilisées, enless bravo pour l'auteur anonyme de l'ancien Sun Microsystems)

Substance L & F

enter image description here

WindowsLookAndFeel L & F

enter image description here

Nimbus L&F

enter image description here

Métal L&F

enter image description here

à partir des Classes Java

main

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

AutoComboBox

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

AutoTextField

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

EDIT

sortie de Win7 64b / Java7

Métal L & F

enter image description here

Windows L&F (drôle espace vide près de Bouton dans JComboBox)

enter image description here

Nimbus L&F

enter image description here

n'hésitez pas pour les modifier(s)

8
répondu mKorbel 2012-04-29 20:58:29

ce composant est appelé autocomplete et est inclus dans un porject appelé Swing extensions.

Juste un coup d'oeil: http://swingx.java.net/

Il y a un webstart:http://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp

Autocomplete est le Menu à sélectionner. Avoir du plaisir et moins sujette aux erreurs de code :)

1
répondu Dudelilama 2012-05-10 11:31:13

évidemment, le problème est dans le composant textfield utilisé. Ce qui se passe, lorsque apparence windows est utilisé , le texte de ce composant est sélectionné, l'utilisation de la ligne "textfield.selectAll ();", et donc quand vous tapez quoi que ce soit d'autre le texte sélectionné est effacé de la composante textfield. Ainsi, dans le code ci-dessous, la position caret de ce composant est ajustée. C'est comme ça que ça marche, d'abord stocker la position caret actuelle du champ de texte dans une variable "currentCaretPosition", puis déplacer la position du curseur au début du texte dans le composant. Après avoir filtré, restaurer la position de caret à la valeur de la variable "currentCaretPosition". J'espère que ça marche comme tu le veux.

le code raffiné est donné ci-dessous: -

                                       /****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**********/
1
répondu G.Srinivas Kishan 2013-07-18 06:50:25

il semble, comme vous l'avez mentionné, que lorsque l'utilisateur entre des textes dans combobox, Windows Look & Feel sélectionne (met en évidence) le texte entré. Donc, quand vous appuyez sur une autre touche, elle remplace la précédente. Donc, la solution n'est pas de mettre en évidence les textes. Vous pouvez atteindre cet objectif en ajoutant l'un des énoncés suivants dans votre keylistener.

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

OR

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

Donc, votre keylistener devrait ressembler à ceci :

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());
                }
            });
        }
    });
0
répondu Manoj Shrestha 2012-05-04 19:30:16