2017-08-05 224 views
1

所以我的问题是,我有一个serilized ArrayList,并且必须在我的GUI中更新它以动态显示其在ListView中的内容。 序列化和反序列化使用DAO接口可以正常工作,但GUI不会刷新我的ListView。JavaFX,List到ObservableList到ListView

此类包含我的数据交互(主要是保存,加载...):

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; 
    } 
    //[...] 
} 

这才是我的GUI实现片断:

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(); 
    } 
    //[...] 

我也累了,从更换整个的ArrayList带有一个ObservableList的“Medienverwaltung”类,这样只剩下一个List,这对于GUI来说是有用的,但是对于我之前猜测的序列化和反序列化来说却没有。 (并尝试了一些其他的实现)

有没有人有一个想法如何改变我的代码,以便它的工作? 而我的第二个问题是,3层架构的最佳方式是什么?

以下是费边参考答案,并回复了我对

更新#1.1(附录进行说明)评论

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

这才是我的具体保存方法:

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

更新#1.2(附录进行说明)

//[...] 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(); 
      } 
     } 
    }); 
//[...] 

但正如我猜,这不是一个好方法来访问backinlist这种方式。

更新#2:

尊重一个干净的方式封装的原则,我现在在班上Medienverwaltung增加了一个重载的方法:

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

所以我的GUI,现在只要求speichern( )。这实际上调用了用于从外部不能访问的备份列表保存的方法。我希望这没有什么不好的编码风格^^

BTW。:如果你读这篇文章,也有类似的问题,不要为同步使用ObservableArrayList与正常列表,这是不行的!改为使用ObservableList

回答

0

通过删除getter来隐藏其他类的支持列表(medienliste)。如果使用ObservableList修改此列表,ListView(或每个其他添加了侦听器的对象都将正确更新)。

而且除非Medium延伸Node,你可以简单地使用这种类型的对象为ListView的项目,因为该单元设置文字向全世界呼吁,默认情况下,关联项目的toString方法的结果。

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(); 
} 

注意,Medienverwaltung.aufnehmen方法不应与后台列表直接工作 - 它应该使用ObservableList代替,以确保变化可以看出...


编辑

看着IDAO接口它应该可能是一个不同于Medienverwaltung的对象,否则你会违反关注点分离设计原则;也传递一个值作为参数已经包含作为对象本身的属性是没有意义的。

似乎IDAO对象应该只负责读取/写入列表数据,这将使得不需要实现SerializableMedienverwaltung。大概是这样的,预计解决您的锻炼; Tibial:

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

IDAO实现应该最有可能不依赖于List的执行,因此不能指望List是序列化。你可以简单地解决由非序列化列表)不使用ObjectOutputStream坚持数据,而不是依靠序列化对象的其他方式或b)只是将列表中的内容复制到一个序列化的列表:

@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

哦,非常感谢,尽可能地运作。只剩下一个问题,我不允许更改DAO接口(是的,我应该在-.-之前提​​到,对不起),所以在序列化的时候我仍然遇到问题。从DAO中,我得到以下签名:请参阅更新#1.1 因此,我将我的GUI中的保存方法的调用更改为以下内容:请参阅更新#012 现在可以使用,因为我访问备份列表而不是medienlist,但这不是一个好习惯。 有没有更好的方式我没有看到? –

+0

现在,我认为了一切正确和清洁。 [1.]写了具体的DAO对象类 [2.]将保存/加载方法转换为具体的DAO对象类 [3.]在构造函数中给出了具体的DAO给Medienverwaltung,该构造函数发生在一个不相关的DAO引用中它可以交换) [4.]虽然我仍然使用备份列表,但只是为了给它DAO 所以,非常感谢你帮助我改进我的代码,Fabian = D –

相关问题