Добавить прослушиватель в ArrayList

У меня есть ArrayList, который я добавляю к нему некоторые объекты динамически, и у меня есть JButton. ArrayList пуст при запуске моей программы, а JButton - setEnabled (false). Я хочу включить свою кнопку всякий раз, когда в ArrayList или больше есть два элемента, и отключить его снова, если ArrayList имеет один элемент или пустой. Как я могу достичь этого?

Ответ 1

ArrayList не имеет какого-либо механизма уведомления.

Я предлагаю вам написать собственную реализацию List, которая делегирует частному ArrayList для своего хранилища, но добавляет возможность прослушивания уведомлений... или найти что-то подобное в самой Java. DefaultListModel может работать для вас, хотя сам он не реализует List.

Ответ 2

Как @Jon Skeet предлагает вам также сделать что-то вроде:

public class ListResponseModel<E> extends AbstractListModel {

    private static final long serialVersionUID = 1L;

    private ArrayList<E> delegate = new ArrayList<E>();

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

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

    public void add(E e){
        int index = delegate.size();
        delegate.add(e);
        fireIntervalAdded(this, index, index);
    }
}

Ответ 3

Javafx (часть JRE 8) обеспечивает реализацию наблюдаемого списка. Этот код работает для меня:

ObservableList<MyAnno> lstAnno1 = FXCollections.observableList(new ArrayList<MyAnno>());

lstAnno1.addListener((ListChangeListener.Change<? extends MyAnno> c) -> {
   c.next();
   updateAnnotation((List<MyAnno>) c.getAddedSubList(), xyPlot);
});

...
lstAnno1.add(new MyAnno(lTs, dValue, strType));
...

public void updateAnnotation(List<MyAnno> lstMyAnno, XYPlot xyPlot) {
   lstMyAnno.forEach(d -> {
   ...
   });
}

Ответ 4

Вы не можете так поступать с ArrayList, потому что @Jon Skeet говорит, что ArrayList не имеет никакого механизма уведомления. Вам следует попробовать привязать JGoodies ObservableList, который может помочь.

Или вы можете настроить таймер, который будет проверять размер ArrayList и соответственно изменить JButton. Вам потребуется поток для выполнения этой задачи списка мониторинга через некоторый промежуток времени.

Или, если вы знаете все, где вы добавляете/удаляете элементы из списка, тогда напишите этот логин во всем этом месте.

Ответ 5

Если вы пишете свою собственную реализацию List, как предлагает @Jon Skeet, вы можете дать ей EventListenerList. API описывает соответствующие методы.

Ответ 6

ObservableList<DynamicObjects> ol = FXCollections.ObservableArrayList(new ArrayList<DynamicObjects>());
ListProperty lp = new SimplePropertyList(ol);

lp.addListener(new ChangeListener(){
        @Override public void changed(ObservableValue o, Object oldVal,
                                      Object newVal){
            if (ol.size() > 1 && !JButton.isEnabled()) {
                JButton.setEnable(true);
            } else if (ol.size < 2 && JButton.isEnabled()) {
                JButton.setEnable(false);
            }
    });

Ответ 7

Следуя синтаксису SimpleIntegerProperty, я создал ArrayList, который срабатывает при изменении размера. В этом случае вам нужно теперь указать текущий размер ArrayList, так как вы хотите реагировать, когда размер равен 2, поэтому простое решение для этого делает следующее:

ArrayListProperty.java

public class ArrayListProperty<E> extends ArrayList<E> implements ObservableValue<Number> {
    private ExpressionHelper<Number> helper = null;
    private SimpleIntegerProperty sizeProperty;

    public ArrayListProperty(){
        super();
        sizeProperty = new SimpleIntegerProperty(0);
    }

    @Override
    public boolean add(E e) {
        boolean returnValue = super.add(e);
        sizeProperty.set(size());
        fireValueChangedEvent();
        return returnValue;
    }

    @Override
    public void add(int index, E element) {
        super.add(index, element);
        sizeProperty.set(size());
        fireValueChangedEvent();
    }

    @Override
    public E remove(int index) {
        E returnValue = super.remove(index);
        sizeProperty.set(size());
        fireValueChangedEvent();
        return returnValue;
    }

    @Override
    public boolean remove(Object o) {
        boolean returnValue = super.remove(o);
        if(returnValue){
            sizeProperty.set(size());
            fireValueChangedEvent();
        }
        return returnValue;
    }

    protected void fireValueChangedEvent(){
        ExpressionHelper.fireValueChangedEvent(helper);
    }

    @Override
    public void addListener(ChangeListener<? super Number> listener) {
        helper = ExpressionHelper.addListener(helper, sizeProperty, listener);
    }

    @Override
    public void removeListener(ChangeListener<? super Number> listener) {
        helper = ExpressionHelper.removeListener(helper, listener);
    }

    @Override
    public Number getValue() {
        return null;
    }

    @Override
    public void addListener(InvalidationListener listener) {
        helper = ExpressionHelper.addListener(helper, sizeProperty, listener);
    }

    @Override
    public void removeListener(InvalidationListener listener) {
        helper = ExpressionHelper.removeListener(helper, listener);
    }
}

В этом случае наблюдаемый размер массива, тогда при объявлении вашего arraylist вы можете добавить слушателя и действовать, когда размер равен 2.

ArrayListProperty<Object> arrayList = new ArrayListProperty<>();
arrayList.addListener((ob, ov, nv) -> { 
    if(nv.intValue() == 2) doSomething();
});

Эта реализация также позволяет вам добавить сравнение в ChangeListener, чтобы вы могли знать, когда что-то было добавлено или что-то удалено. Также вы можете сохранить добавленный или удаленный объект и получить его в слушателе.