2009-02-16 11 views
6

Digamos que tiene la siguiente Java Bean:Monitor de cambios en una colección

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

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

¿Cómo se implementará normalmente un evento de cambio de propiedad de una colección? ¿Intenta utilizar la propiedad de índice que parece ser más para matrices que para colecciones?

Respuesta

8

Eche un vistazo a la biblioteca Glazed Lists, que tiene soporte para colecciones observables.

Si tuviera que hacerlo yo mismo, yo probablemente crearía interfaz de escucha personalizado con elementsAdded, métodos elementsRemoved, o similares :-) (también en función de mis necesidades)

+0

Eso es lo que normalmente hago también. Solo curiosidad por lo que todos los demás estaban haciendo. Al menos obtuve un buen enlace a Collection que en realidad es oberserable. :) – willcodejavaforfood

+1

La respuesta de AndreyChaschev no necesita ninguna biblioteca externa (pero requiere Java7) – Benj

+0

@Benj: no sorprende que la respuesta de hace 8 años ya no sea relevante ;-) –

0

Para un evento de GUI de oscilación normalmente solo usaría un EventListenerList para hacer el trabajo por mí.

EDITAR: sobre la reformulación de las preguntas: cómo se tratan las colecciones, normalmente usaría un evento similar al tipo de colecciones, por ejemplo, un evento TreeModel suele tener un argumento TreePath o algo en un mapa Yo indicaría la clave.

Sin embargo, para los JavaBeans simples, el más común es asumir una lista/matriz y simplemente usar el índice.

+0

No estoy interesado en cómo se almacenan los oyentes. Lo que busco es una alternativa al PropertyChange que pueda manejar colecciones. – willcodejavaforfood

+0

y tenga en cuenta que esto no es específico de Swing – willcodejavaforfood

0

Me parece que necesitará fireNamesPropertyAdd, fireNamesProperyDelete. Una notificación de nivel de lista no funcionará en mi humilde opinión, incluso si se tratara de una matriz y se agregó un índice, ya que no puede gestionar las eliminaciones. Si se puede cambiar el elemento en algún índice, también necesitará fireNamesProperyChange. Puede ser útil tener un índice como parámetro además del valor de la cadena.

8

(NOTA: He actualizado este post tras darse cuenta de algunos errores de mi propia por lo que este no es el original, pero una vez más refinado)

Para ello me gustaría hacer dos nuevos interfaces, ListListener y Listenable y luego crearía una nueva clase como ListenableArrayList que envolvería cada método List con una llamada a uno (o más) métodos relevantes definidos en ListListener. En el código sería algo como esto:

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); 
    /* .. */ 
} 

La razón por la que lo haría de esta manera sería la de permitir la creación de oyentes verdaderamente ad-hoc sobre la marcha en lugar de atar el ListenableArrayList a alguna aplicación específica. Por ejemplo, con esto, el siguiente sería posible:

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."); 
    } 
}); 

Un poco desordenado, tal vez, pero por otro lado esto permitiría una fácil extensión a las colecciones, conjuntos y otras cosas con bastante facilidad.

+0

... por supuesto, puede llamar directamente a los métodos de escucha también, solo trato de ser lo más claro posible con el ejemplo. – Esko

+0

Lista list = new ListenableArrayList (); (lista (Listenable)) .setListener (new ListListener() { ? Icky! –

+0

Scary eso es lo único de lo que te quejas ya que hay otro problema más importante que acabo de notar. Actualizaré la publicación en un minuto. – Esko

0

¿Está quizá buscando java.beans.PropertyChangeSupport?

En mi opinión, debe evitar PropertyChangeEvent. IndexedPropertyChangeEvent es peor, y muy poco utilizado por Swing de todos modos. Es mejor restringir el enfoque de sus tipos, y disparar un javax.swing.event.ChangeEvent o similar (incluso simplemente llame a Runnable).

Para ciertos tipos (como las listas!), Las listas esmaltadas (o equivalentes) mencionadas en otra publicación de Peter Štibraný parecen una buena forma de hacerlo.

+0

Estoy buscando una alternativa :) – willcodejavaforfood

2

Normalmente yo haría lo siguiente:

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 gestiona los oyentes y los incendios de los acontecimientos en su nombre.

Al pasar nulo como el "valor anterior" fuerza el evento a ser disparado. (Es probable que los oyentes no serán realmente se preocupan por el valor antiguo de todos modos)

+0

Estaba tan obsesionado con las propiedades indexadas que ni siquiera pensé en eso. Eso funciona bien cuando realmente no te importa si un objeto fue agregado/eliminado solo que algo cambió. – willcodejavaforfood

+0

@willcodejavaforfood Esto es un millón de años más tarde, pero si le importa si un objeto se agregó o eliminó, puede cambiar la identificación del 'PropertyChangeEvent'. – sdasdadas

+2

@sdasdadas - whoa - ¡no hagas eso! El nombre en PropertyChangeEvent _must_ coincide con el nombre de la propiedad real (el mismo que el nombre del método get/set - "get"/"set" y con una primera letra minúscula.) Nunca lo ajuste a algo así como "name -added "o" name-removed ". De lo contrario, se rompe cualquier marco o humano que entienda cómo funcionan los JavaBeans ... –

1

JDK 7+ solución:

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"); 
    } 
} 
+1

es la solución javafx – dit

+0

¿qué pasa con eso? Está aislado de la parte UI –

Cuestiones relacionadas