2017-08-05 6 views
1

Donc mon problème est, que j'ai un ArrayList serilized et dois le mettre à jour dans mon GUI pour montrer son contenu dans un ListView dynamiquement. La sérialisation et la désérialisation fonctionnent correctement avec l'utilisation d'une interface DAO, mais l'interface graphique n'actualisera pas ma ListView.JavaFX, Liste à ObservableList à ListView

Cette classe contient mon interaction de données (sauf la plupart du temps, charge ...):

public class Medienverwaltung implements Serializable, IDAO{ 

    private static final long serialVersionUID = 1L; 
    private List<Medium> medienliste; 
    public ObservableList<Medium> obList; //public for test-reasons 

    public Medienverwaltung(){ 
     medienliste = new ArrayList<Medium>(); 
     obList = FXCollections.observableArrayList(medienliste); 
    } 

    //[...] 

    public List<Medium> getMedienliste(){ 
     return this.medienliste; 
    } 
    //[...] 
} 

vient ici mon interface graphique extrait de mise en œuvre:

public class HauptFenster extends Application{ 

    private Medienverwaltung medienverwaltung; 

    @Override 
    public void start(Stage stage) throws Exception{ 
     medienverwaltung = new Medienverwaltung(); 

     VBox root = new VBox(); 
     ListView<String> showliste = new ListView<String>(); 
     MenuBar menuBar = createMenuBar(stage); 
     root.getChildren().add(menuBar); 
     root.getChildren().add(showliste); 

     //Make Listener and refresh the shown list! 
     medienverwaltung.obList.addListener(new ListChangeListener<Medium>(){ 
      @Override 
      public void onChanged(ListChangeListener.Change<? extends Medium> change) { 
       showliste.getItems().clear(); 
       for(Medium medium : medienverwaltung.obList){ 
        //toString() is overwritten and works, too 
        showliste.getItems().add(medium.toString()); 
       } 
      } 
     }); 
     // this adds a Medium object to the Arraylist in Medienverwaltung 
     medienverwaltung.aufnehmen(new Bild("Foto12", 2017, "Zuhause")); 

     stage.setTitle("Medien Verwaltung"); 
     stage.setScene(new Scene(root, 800, 400)); 
     stage.show(); 
    } 
    //[...] 

J'ai aussi fatigué d'échanger toute ArrayList de la classe "Medienverwaltung" avec un ObservableList, de sorte qu'il ne reste qu'une seule liste, qui fonctionne pour l'interface graphique mais pas pour la sérialisation et la désérialisation comme je l'ai deviné auparavant. (et essayé quelques autres implémentations)

Est-ce que quelqu'un a une idée comment changer mon code pour que cela fonctionne? Et ma deuxième question est, quelle est la meilleure façon en termes d'architecture à 3 couches?

Ce qui suit est une référence à fabiens réponse et répond à mon commentaire sur cette

Mise à jour # 1.1 (additif pour explication)

public interface IDAO { 
    // Save method 
    void speichern(List<Medium> liste) throws PersistenzException; 
    // Load method 
    List<Medium> laden() throws PersistenzException; 
} 

vient ici mon béton méthode de sauvegarde:

@Override 
public void speichern(List<Medium> medienliste) throws PersistenzException{ 
    File sfile = new File("medienliste.dat"); 

    try(FileOutputStream fos = new FileOutputStream(sfile); ObjectOutputStream oos = new ObjectOutputStream(fos)){ 
     oos.writeObject(medienliste); 
     System.out.println("Serialisierung erfolgreich!"); 
    }catch(IOException e){ 
     e.printStackTrace(); 
     System.out.println("Serialisierung fehlgeschlagen!"); 
    } 
} 

Mise à jour # 1.2 (additif pour explication)

//[...] section of my GUI for saving 
MenuItem speichern = new MenuItem("Speichern"); 
    speichern.setOnAction(new EventHandler<ActionEvent>(){ 
     @Override 
     public void handle(ActionEvent e){ 
      try{ 
     //Before: medienverwaltung.speichern(medienverwaltung.getMedienliste()); -> doesn't work because of serializing an ObservableList 
       medienverwaltung.speichern(medienverwaltung.getBackingList()); 
      }catch(PersistenzException pe){ 
       pe.printStackTrace(); 
      } 
     } 
    }); 
//[...] 

Mais comme je suppose, ce n'est pas un bon moyen d'accéder à la backinlist de cette façon.

Mise à jour # 2:

à respecter le principe d'encapsulation d'une manière propre, je maintenant ajouté une méthode surchargée dans la classe Medienverwaltung:

public void speichern() throws PersistenzException{ 
    speichern(backingList); 
} 

Donc, mon GUI maintenant appelle seulement speichern (). Cela appelle en fait la méthode d'enregistrement avec la liste de diffusion qui n'est plus accessible de l'extérieur. J'espère que ce n'est pas mauvais style de codage ^^

BTW .: Si vous lisez ceci et ont un problème similaire, ne pas utiliser ObservableArrayList pour la synchronisation avec une normale Liste, cela ne fonctionnera pas ! Utilisez ObservableList à la place.

Répondre

0

Masquer la liste de fonds (medienliste) d'autres classes en supprimant le getter. Si vous modifiez cette liste en utilisant le ObservableList, le ListView (ou tout autre objet ayant ajouté un écouteur à la liste) sera correctement mis à jour.

En outre, à moins Medium étend Node vous pouvez simplement utiliser ce type d'objet comme des objets de la ListView, étant donné que les cellules donnent le texte au résultat de la méthode toString appelé à l'élément associé par défaut.

public class Medienverwaltung implements Serializable, IDAO{ 

    private static final long serialVersionUID = 1L; 
    private List<Medium> backingList; 

    // transient field not persisted 
    private transient ObservableList<Medium> medienliste; 

    public Medienverwaltung(){ 
     backingList = new ArrayList<Medium>(); 
     medienliste = FXCollections.observableArrayList(backingList); 
    } 

    // make sure an ObservableList is created when reading the serialized object 
    private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { 
     inputStream.defaultReadObject(); 
     medienliste = FXCollections.observableArrayList(backingList); 
    } 

    //[...] 

    public ObservableList<Medium> getMedienliste(){ 
     return this.medienliste; 
    } 

    //[...] 

} 
@Override 
public void start(Stage stage) throws Exception{ 
    medienverwaltung = new Medienverwaltung(); 

    VBox root = new VBox(); 
    ListView<Medium> showliste = new ListView<>(medienverwaltung.getMedienliste()); 

    MenuBar menuBar = createMenuBar(stage); 
    root.getChildren().add(menuBar); 
    root.getChildren().add(showliste); 

    // this adds a Medium object to the Arraylist in Medienverwaltung 
    medienverwaltung.aufnehmen(new Bild("Foto12", 2017, "Zuhause")); 

    stage.setTitle("Medien Verwaltung"); 
    stage.setScene(new Scene(root, 800, 400)); 
    stage.show(); 
} 

Notez que la méthode Medienverwaltung.aufnehmen directement ne devrait pas fonctionner avec la liste de soutien - il doit utiliser le ObservableList au lieu de vous assurer que les changements peuvent être observés ...


EDIT

En regardant leInterfaceil devrait probablement être un objet différent de Medienverwaltung, car sinon vous auriez violez la seperation des préoccupations principe de conception; il serait également illogique de passer une valeur en paramètre qui est déjà contenue en tant que propriété de l'objet lui-même.

Il semble que l'objet IDAO devrait être responsable de la lecture/écriture des données de la liste seulement ce qui rendrait l'implémentation Serializable inutile avec Medienverwaltung. Probablement quelque chose comme ceci est la solution attendue à votre excercise:

IDAO idao = new IDAOImplementation(); 
Medienverwaltung medienverwaltung = new Medienverwaltung(idao.laden()); 
public void handle(ActionEvent e){ 
    try{ 
     idao.speichern(medienverwaltung.getMedienliste()); 
    }catch(PersistenzException pe){ 
     pe.printStackTrace(); 
    } 
} 
public Medienverwaltung(List<Medium> medien) { 
    this.medienliste = FXCollections.observableArrayList(medien); 
} 

La mise en œuvre IDAO devrait très probablement pas dépendre de la mise en œuvre du List et donc pas attendre la List d'être sérialisable. Vous pouvez simplement contourner les listes non sérialisés par un) n'utilisant ObjectOutputStream pour conserver les données, mais d'une autre manière ne reposant pas sur des objets sérialisables ou b) il suffit de copier le contenu de la liste à une liste sérialisable:

@Override 
public void speichern(List<Medium> medienliste) throws PersistenzException{ 
    File sfile = new File("medienliste.dat"); 

    try(FileOutputStream fos = new FileOutputStream(sfile); ObjectOutputStream oos = new ObjectOutputStream(fos)){ 
     oos.writeObject(new ArrayList(medienliste)); 
     System.out.println("Serialisierung erfolgreich!"); 
    } catch(IOException e){ 
     throw new PersistenzException(e); 
    } 
} 
+0

Oh merci beaucoup, cela fonctionne autant que possible. Il n'y a qu'un seul problème reste, je ne suis pas autorisé à changer l'interface DAO (Oui, je l'ai dit avant que -.- », désolé) et j'ai encore des problèmes lors de la sérialisation. A partir de la DAO, je reçois les signatures suivantes: Voir Mise à jour # J'ai donc changé l'appel de ma méthode d'enregistrement dans ma GUI à la suivante: Voir Mise à jour # 1.2 Cela fonctionne maintenant, parce que j'accède à la backinglist au lieu de la medienlist, mais Ce n'est pas une bonne pratique. Y at-il un meilleur moyen que je n'ai pas encore vu? –

+0

Tout est correct et propre maintenant je pense. [1.] a écrit la classe d'objet DAO concrète [2.] les méthodes save/load transférées à la classe d'objets concrète DAO [3.] ont donné DAO concret à Medienverwaltung sur le constructeur, qui se déroule dans une référence DAO non-concédée (pour faire il est échangeable) [4.] bien que j'utilise toujours la backinglist, mais seulement pour la donner au DAO Alors, merci beaucoup de m'avoir aidé à améliorer mon code, Fabian = D –