Reputation: 44063
Say you have the following java bean:
public class MyBean
{
private List<String> names = new ArrayList<String>();
public void addName(String name)
{
names.add(name);
fireNamesPropertyChange(name);
}
}
How would you normally implement a property change event for a collection? Do you try and use the index property which seems to be more for arrays than collections?
Upvotes: 6
Views: 12350
Reputation: 61526
You can use an Observable Collection: https://commons.apache.org/dormant/events/apidocs/org/apache/commons/events/observable/ObservableCollection.html
Upvotes: 4
Reputation: 16496
JDK 7+ solution:
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");
}
}
Upvotes: 2
Reputation: 30642
Normally I'd do the following:
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 manages the listeners and fires the events on your behalf.
By passing null as the "old value" it forces the event to be fired. (It's likely that listeners won't really care about the old value anyway)
Upvotes: 2
Reputation: 29377
(NOTE: I updated this post after realizing a few mistakes of my own so this isn't the original but a more refined one instead)
For this purpose I'd do two new interfaces, ListListener
and Listenable
and then I would create a new class like ListenableArrayList
which would wrap every List
method with a call to one (or more) relevant methods defined in ListListener
. In code it'd be something like this:
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);
/* .. */
}
The reason I'd do it this way would be to allow for creating truly ad-hoc listeners on the fly instead of tying the ListenableArrayList to some specific implementation. For example with this the following would be possible:
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.");
}
});
A bit cluttered, maybe but on the other hand this would allow for easy extension to Collections, Sets and whatnot rather easily.
Upvotes: 11
Reputation: 147164
Are you perhaps looking for java.beans.PropertyChangeSupport
?
In my opinion, you should avoid PropertyChangeEvent
. IndexedPropertyChangeEvent
is worse, and very infrequently used by Swing anyway. It's better to narrow the focus of your types, and fire a javax.swing.event.ChangeEvent
or similar (even just call a Runnable
).
For certain types (like lists!), Glazed Lists (or equivalent) mentioned in another post by Peter Štibraný seem like a good way to go.
Upvotes: 0
Reputation: 32893
Take a look at Glazed Lists library, which has support for observable collections.
If I were to do it myself, I would likely create custom Listener interface with elementsAdded, elementsRemoved methods, or similar :-) (also depending on my needs)
Upvotes: 8
Reputation: 28752
Methinks you will need fireNamesPropertyAdd
, fireNamesProperyDelete
. A list level notification will IMHO not work, even if it was an array and an index was added as it can't handle deletes. If the element at some index can be changed, you will also need fireNamesProperyChange
. It might be useful to have index as parameter in addition to the string value.
Upvotes: 0
Reputation: 44173
For a swing GUI event I'd normally just use an EventListenerList to do the work for me.
EDIT: on the rephrase of the questions: how do you treat collections, I'd usually use an event similar to the collections type, so for example a TreeModel event usually takes a TreePath argument, or for something in a map I'd indicate the key.
However for simple JavaBeans the most common is assume a list/array and just use the index.
Upvotes: 0