假设你有以下java bean:
public class MyBean
{
private List<String> names = new ArrayList<String>();
public void addName(String name)
{
names.add(name);
fireNamesPropertyChange(name);
}
}
您通常如何为集合实现属性更改事件?您是否尝试使用索引属性,这对于数组而言似乎比集合更多?
答案 0 :(得分:9)
(注意:我在发现自己的一些错误后更新了这篇文章,所以这不是原版,而是更精致的一个)
为此,我会做两个新的接口,ListListener
和Listenable
,然后我会创建一个新的类,如ListenableArrayList
,它将包装每个List
方法调用ListListener
中定义的一个(或多个)相关方法。在代码中它是这样的:
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.");
}
});
有点混乱,但另一方面,这将允许轻松扩展到集合,集合等等。
答案 1 :(得分:8)
查看Glazed Lists库,它支持可观察的集合。
如果我自己动手,我可能会使用elementsAdded,elementsRemoved方法或类似方法创建自定义Listener接口:-)(也取决于我的需要)
答案 2 :(得分:4)
您可以使用Observable Collection:https://commons.apache.org/dormant/events/apidocs/org/apache/commons/events/observable/ObservableCollection.html
答案 3 :(得分: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作为“旧值”,它会强制触发事件。 (无论如何,听众可能不会真正关心旧的价值)
答案 4 :(得分:1)
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");
}
}
答案 5 :(得分:0)
对于swing GUI事件,我通常只使用EventListenerList为我做的工作。
编辑:关于问题的改述:你如何处理集合,我通常使用类似于集合类型的事件,所以例如TreeModel事件通常采用TreePath参数,或者地图中的某些东西'd表示关键。但是对于简单的JavaBeans,最常见的是假设一个列表/数组,只使用索引。
答案 6 :(得分:0)
您需要fireNamesPropertyAdd
,fireNamesProperyDelete
。列表级别通知将恕我直言不起作用,即使它是一个数组并添加了索引,因为它无法处理删除。如果某个索引处的元素可以更改,则还需要fireNamesProperyChange
。除了字符串值之外,将index作为参数可能很有用。
答案 7 :(得分:0)
您是否正在寻找java.beans.PropertyChangeSupport
?
在我看来,你应该避免PropertyChangeEvent
。 IndexedPropertyChangeEvent
更糟糕,而且很少被Swing使用。最好缩小类型的焦点,并触发javax.swing.event.ChangeEvent
或类似的(甚至只调用Runnable
)。
对于某些类型(如列表!),PeterŠtibraný在另一篇文章中提到的釉面列表(或等效物)似乎是一种很好的方式。