6

假设您有以下 java bean:

public class MyBean
{
    private List<String> names = new ArrayList<String>();

    public void addName(String name)
    {
        names.add(name);
        fireNamesPropertyChange(name);
    }
}

您通常如何为集合实现属性更改事件?您是否尝试使用似乎更适用于数组而不是集合的 index 属性?

4

8 回答 8

11

注意:我在意识到自己的一些错误后更新了这篇文章,所以这不是原来的,而是更精致的)

为此,我会做两个新接口,ListListener然后Listenable我会创建一个新类,就像它会通过调用一个(或多个)相关方法来ListenableArrayList包装每个方法。在代码中它会是这样的:ListListListener

public class ListenableArrayList<T> extends ArrayList<T>
                                    implements Listenable<T> {

    private ArrayList<T> internalList;
    private ListListener<T> listener;

    /* .. */

    public void add(T item) {
        listener.beforeAdd(T item);
        internalList.add(item);
        listener.afterAdd(T item);
    }

    /* .. */

    public void setListener(ListListener<T> listener) {
        this.listener = listener;
    }

}

public interface ListListener<T> {
    /* .. */
    void beforeAdd(T item);
    void afterAdd(T item);
    /* .. */
}

public interface Listenable<T> {
    /* .. */
    void setListener(ListListener<T> listener);
    /* .. */
}

我这样做的原因是允许动态创建真正的临时侦听器,而不是将 ListenableArrayList 绑定到某些特定实现。例如,以下是可能的:

Listenable<String> list = new ListenableArrayList<String>();

list.setListener(new ListListener<String>() {
    @Override
    public void beforeAdd(String item) {
        System.out.println("About to add element "+item+"...");
    }
    @Override
    public void afterAdd(String item) {
        System.out.println("...element "+item+" has been added.");
    }
});

可能有点混乱,但另一方面,这可以很容易地扩展到 Collections、Sets 等等。

于 2009-02-16T14:10:11.997 回答
8

看看Glazed Lists库,它支持可观察的集合。

如果我自己做,我可能会使用 elementsAdded、elementsRemoved 方法或类似方法创建自定义 Listener 接口:-)(也取决于我的需要)

于 2009-02-16T14:12:29.277 回答
4

您可以使用 Observable 集合:https ://commons.apache.org/dormant/events/apidocs/org/apache/commons/events/observable/ObservableCollection.html

于 2009-02-16T15:18:28.260 回答
2

通常我会做以下事情:

public class MyBean {
    private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    private List<String> names = new ArrayList<String>();
    public void addName(String name) {
        names.add(name);
        pcs.firePropertyChange("names", null, Collections.unmodifiableList(names));
    }
    public void addPropertyChangeListener(PropertyChangeListener l) {
        pcs.addPropertyChangeListener(l);
    }
    public void removePropertyChangeListener(PropertyChangeListener l) {
        pcs.removePropertyChangeListener(l);
    }
}

PropertyChangeSupport 代表您管理侦听器并触发事件。

通过将 null 作为“旧值”传递,它会强制触发事件。(无论如何,听众很可能不会真正关心旧值)

于 2009-02-18T04:07:39.477 回答
2

JDK 7+ 解决方案:

import javafx.collections.*;
import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("s1");
        list.add("s2");

        ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> change) {
                while(change.next()){
                    System.out.println("added: " + change.getAddedSubList());
                }
            }
        });

        observableList.add("s3");
    }
}
于 2013-10-23T21:28:23.763 回答
0

对于摇摆 GUI 事件,我通常只使用EventListenerList为我完成工作。

编辑:关于问题的改写:你如何对待集合,我通常会使用类似于集合类型的事件,因此例如 TreeModel 事件通常需要一个 TreePath 参数,或者对于地图中的某些东西我会指出钥匙。

然而,对于简单的 JavaBeans,最常见的是假设一个列表/数组并只使用索引。

于 2009-02-16T11:54:06.270 回答
0

我认为您将需要fireNamesPropertyAdd, fireNamesProperyDelete。恕我直言,列表级别的通知将不起作用,即使它是一个数组并且添加了一个索引,因为它无法处理删除。如果可以更改某个索引处的元素,您还需要fireNamesProperyChange. 除了字符串值之外,将索引作为参数可能会很有用。

于 2009-02-16T13:57:05.287 回答
0

你也许在寻找java.beans.PropertyChangeSupport

在我看来,你应该避免PropertyChangeEvent. IndexedPropertyChangeEvent更糟糕的是,无论如何 Swing 很少使用。最好缩小类型的焦点,并触发 ajavax.swing.event.ChangeEvent或类似的(甚至只是调用 a Runnable)。

对于某些类型(如列表!),Peter Štibraný 在另一篇文章中提到的 Glazed Lists(或等效项)似乎是一个不错的选择。

于 2009-02-16T15:15:28.640 回答