Фильтрация JList на основе JTextField

У меня есть JTextField и JList в моей программе. JList содержит контакты Пользователя. Я хотел бы отфильтровать JList на основе текста в JTextField. Например, если я введу "Майк", он будет показывать только контакты, включая"Майк". Когда пользователь очищает JTextField, он сбрасывает фильтр.

Я знаю, что могу сделать это вручную, имея два массива. Один для исходных контактов и один для отфильтрованных. Когда пользователь изменяет значение JTextField, я бы пошел trought исходный список, обновить временный список и обновить JList. Мне просто интересно, есть ли какая-то встроенная функция, чтобы избежать ручного труда.

3 ответов


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

package test;

import java.util.ArrayList;

import javax.swing.AbstractListModel;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

public class FilteredListModel extends AbstractListModel {
    public static interface Filter {
        boolean accept(Object element);
    }

    private final ListModel _source;
    private Filter _filter;
    private final ArrayList<Integer> _indices = new ArrayList<Integer>();

    public FilteredListModel(ListModel source) {
        if (source == null)
            throw new IllegalArgumentException("Source is null");
        _source = source;
        _source.addListDataListener(new ListDataListener() {
            public void intervalRemoved(ListDataEvent e) {
                doFilter();
            }

            public void intervalAdded(ListDataEvent e) {
                doFilter();
            }

            public void contentsChanged(ListDataEvent e) {
                doFilter();
            }
        });
    }

    public void setFilter(Filter f) {
        _filter = f;
        doFilter();
    }

    private void doFilter() {
        _indices.clear();

        Filter f = _filter;
        if (f != null) {
            int count = _source.getSize();
            for (int i = 0; i < count; i++) {
                Object element = _source.getElementAt(i);
                if (f.accept(element)) {
                    _indices.add(i);
                }
            }
            fireContentsChanged(this, 0, getSize() - 1);
        }
    }

    public int getSize() {
        return (_filter != null) ? _indices.size() : _source.getSize();
    }

    public Object getElementAt(int index) {
        return (_filter != null) ? _source.getElementAt(_indices.get(index)) : _source.getElementAt(index);
    }
}

чтобы использовать его, вам нужно установить его в свой JList, а затем вызвать setFilter() по мере необходимости. Вот пример:

    ListModel source = new DefaultListModel(); // use a model of your choice here;
    FilteredListModel filteredListModel = new FilteredListModel(source);
    JList list = new JList(filteredListModel);
    filteredListModel.setFilter(new FilteredListModel.Filter() {
        public boolean accept(Object element) {
            return false; // put your filtering logic here.
        }
    });

раз метод setFilter () вызывается ваш JList на экране, как ожидается, соответствующим образом изменит его содержимое.

кроме того, вы можете реализовать шаблон observer/observable для своего фильтра, чтобы вы могли повторно фильтровать список без вызова метода setFilter(). Вы можете поэкспериментировать с этим позже. Для первой итерации это достаточно хорошо, если вы вызываете метод setFilter каждый раз, когда пользователь вводит что-то в вашем JTextField.


более простым решением может быть использование JTable, который имеет встроенную способность фильтровать и сортировать (RowSorter). Таблица с одним столбцом не слишком отличается от списка.


Если вы в порядке с внешними библиотеками, я бы рекомендовал QuickListFilterField/QuickTreeFilterField Jide. С несколькими строками кода Вы можете получить визуально фильтруемый JList/JTree, чувствительный к регистру/нечувствительный поиск, подстановочный знак / регулярное выражение и т. д... Удивительно проста в использовании !