2017-09-21 8 views
0

2日前にComboBoxにChangeListenerを接続して、2番目のComboBoxに表示される出力を指定することについてthis questionを投稿しました。要約すると、最初のComboBoxにはいくつかのユニットタイプが表示され、選択されたユニットタイプに応じて、選択されたユニットタイプに基づいて2番目のComboBoxに表示されるユニットリストに依存します。たとえば、最初のComboBoxに「Elites」ユニットタイプを選択した場合、2番目のComboBoxにはすべての「Elite」ユニットが設定されます。JavaFX - ComboBoxでChangeListenerを使用して別のComboBoxをArrayListに設定すると、ArrayListが空になる

my original questionと答えた人は、ChangeListenerのコードで多くの手助けをしてくれました。しかし、それは、あなたがユニットタイプに一度に1つのユニットを追加した場合にのみうまく動作します。理想的には、個々のユニットではなくユニット・タイプに、ユニットのArrayListやその他の適切なデータ構造を追加したいと考えています。これはコードを削減し、より効率的になります。あなたは、このコードスニペットで見ることができるよう

だから、現在のエリートユニットタイプaddUnit方法は、一度に私はそれをしたいと思いますように、私はArrayListのかまねを追加することができ

elites = new Unit_Type("Elites"); 
     elites.addUnit("Dreadnought"); 
     elites.addUnit("Ironclad Dreadnought"); 

を単一の文字列を受け付けます

elitesList = createArrayList("Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard","Sternguard Veteran", "Terminator", "Vanguard Veterans"); 

elites = new Unit_Type("Elites"); 
     elites.addUnit(elitesList); 

注異なるユニットタイプを表すこの各ような8つの他のリストが存在するとしてelitesListは、ヘルパーメソッドによって生成される:このコードスニペットのようなエリートユニットタイプaddUnitメソッドへのデータ構造。 ユニット・タイプ・クラスのコードを変更しようとしましたが、ユニットArrayListのタイプがArrayList<String>であり、また、addUnitメソッドをArrayList<String>のパラメータを受け入れるように変更しようとしましたが、プログラムを実行するときに、最初のComboBoxの結果、2番目のComboBoxに空の配列が作成されます。ここ

がAddUnitPaneクラス(ビュー)の両方のコード、およびUNIT_TYPEクラス(モデル)の残りの部分である

AddUnitPaneクラス

public class AddUnitPane extends GridPane 
{ 
    private Label unitTypeLbl, unitLbl, squadNameLbl, squadSizeLbl; 
    private ComboBox<Unit_Type> unitTypeCombo; 
    private ComboBox<String> unitCombo; 
    private ComboBox<Integer> squadSizeCombo; 
    private TextField squadNameTf; 
    private Button addSquadBtn; 

    private ArrayList<String> elitesList, fastAtkList, heavySptList, hqList, lordsowList, specialCList, transportList, troopsList; //Declare the sublists that hold all the units for the type of unit 
    Unit_Type elites, fastAttk, heavySpt, hQ, lordsOW, specialC, transport, troops; 

    public AddUnitPane() 
    { 
     this.setVgap(15); 
     this.setHgap(20); 
     this.setAlignment(Pos.CENTER); 

     ColumnConstraints col1 = new ColumnConstraints(); 
     col1.setHalignment(HPos.RIGHT); 

     this.getColumnConstraints().add(col1); 
        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

     elitesList = createArrayList("Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard", 
       "Sternguard Veteran", "Terminator", "Vanguard Veterans"); 

     fastAtkList = createArrayList("Attack Bike", "Stormhawk Interceptor", "Stormtalon Gunship", "Assault", "Bike", "Land Speeder", "Scout Bike"); 

     heavySptList = createArrayList("Hunter", "Land Raider Crusader", "Land Raider Redeemer", "Land Raider", "Predator", "Stalker", "Stormraaven Gunship", "Vindicator", 
       "Whirlwind", "Centurion Devastator", "Devastator", "Thunderfire Cannon"); 

     hqList = createArrayList("Captain", "Chaplain", "Librarian", "Techmarine"); 

     lordsowList = createArrayList("Marneus Calger", "Roboute Guilliman"); 

     specialCList = createArrayList("Antaro Chronus", "Cato Sicarius", "Ortan Cassius", "Torias Telion", "Varro Tigurius"); 

     transportList = createArrayList("Drop Pod", "Land Speeder Storm", "Razorback", "Rhino"); 

     troopsList = createArrayList("Scout", "Tactical"); 

     //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

     elites = new Unit_Type("Elites"); 
     //elites.addUnit(elitesList); 
     elites.addUnit("Dreadnought"); 
     elites.addUnit("Ironclad Dreadnought"); 

     fastAttk = new Unit_Type("Fast Attack"); 
     fastAttk.addUnit("Attack Bike"); 
     fastAttk.addUnit("Stormhawk Interceptor"); 

     ObservableList<Unit_Type> unitTypeOList = FXCollections.observableArrayList(elites, fastAttk); //add each Unit_Type to an Observable List 

     //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

     unitTypeLbl = new Label("Select The Unit Class: "); //Initialise all of the labels 
     unitLbl = new Label("Select The Unit: "); 
     squadNameLbl = new Label("Squad Name: "); 
     squadSizeLbl = new Label("Squad Size"); 

     //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

     unitTypeCombo = new ComboBox<Unit_Type>(); //Initialise the unitTypeCombo (first ComboBox) 
     unitTypeCombo.setItems(unitTypeOList); //Populate the unitTypeCombo with the UnitTypeOList (observable list) from line 82 
     //unitTypeCombo.getSelectionModel().selectFirst(); //Set the unitTypeCombo to show the first item 

     unitCombo = new ComboBox<>(); //Initialise the unitCombo (second ComboBox) 

     unitTypeCombo.valueProperty().addListener(new ChangeListener<Unit_Type>() 
     { 
      @Override 
      public void changed(ObservableValue<? extends Unit_Type> observable, Unit_Type oldValue, Unit_Type newValue) 
      { 
       unitCombo.setItems(newValue == null ? FXCollections.emptyObservableList() : newValue.getUnitsForType()); 
      } 
     }); 

     squadNameTf = new TextField(); 

     squadSizeCombo = new ComboBox<>(); 

     addSquadBtn = new Button("Add Squad"); 

     this.add(unitTypeLbl, 0, 1); 
     this.add(unitTypeCombo, 1, 1); 

     this.add(unitLbl, 0, 2); 
     this.add(unitCombo, 1, 2); 

     this.add(squadNameLbl, 0, 3); 
     this.add(squadNameTf, 1, 3); 

     this.add(squadSizeLbl, 0, 4); 
     this.add(squadSizeCombo, 1, 4); 

     this.add(new HBox(), 0, 5); 
     this.add(addSquadBtn, 1, 5);   
    } 

    public void AddUnitHandler(EventHandler<ActionEvent> handler) 
    { 
     addSquadBtn.setOnAction(handler);  
    } 

    private static <T> ArrayList<T> createArrayList(T... items) //generates the unit lists 
    { 
     ArrayList<T> result = new ArrayList<>(items.length); 
     for (T item : items) 
     { 
      result.addAll(result); 
     } 
     return result; 
    } 
} 

UNIT_TYPEクラス

public class Unit_Type implements Serializable 
{ 
    private String typeName; 
    private ArrayList<String> units; //a unit type is an aggregation of units. Tried changing this type to ArrayList<String> 

    public Unit_Type(String typeName) 
    { 
     this.typeName = typeName; 
     units = new ArrayList<>(); 
    } 

    public void addUnit(String u) //tried changing this parameter to ArrayList<String> 
    { 
     units.add(u); 
    } 

    public void setTypeName(String name) 
    { 
     typeName = name; 
    } 

    public ObservableList<String> getUnitsForType() //method used in the ChangeListener in the AddUnitPane class 
    { 
     ObservableList unitsOList = FXCollections.observableArrayList(units); 

     return unitsOList;  
    } 

    @Override 
    public String toString() //allows the ComboBox to display values correctly 
    { 
     return typeName;   
    } 
} 

答えて

1

私はバッキングリストをUnit_Typeに保存しません。 ss。 ObservableListをフィールドに格納し、カスタムのシリアル化メソッドを記述してフィールドを一時的にする方が良いでしょう。

あなたも

elites.getUnitsForType().addAll("Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard", 
           "Sternguard Veteran", "Terminator", "Vanguard Veterans"); 

を使用してユニットの種類を初期化することができ、この方法が、それはコンストラクタでリストを初期化するために、おそらく、さらに短いです:

public class Unit_Type implements Serializable { 

    private String typeName; 

    private transient ObservableList<String> units; 

    private void writeObject(ObjectOutputStream stream) 
      throws IOException { 
     stream.defaultWriteObject(); 

     // serialize units list as string array 
     stream.writeObject(units.toArray()); 
    } 

    private void readObject(ObjectInputStream stream) 
      throws IOException, ClassNotFoundException { 
     stream.defaultReadObject(); 

     // read array from stream and initialize list with it 
     // Note: because of the way we write objects of this type we can use the raw type here safely 
     units = (ObservableList) FXCollections.<Object>observableArrayList((Object[])stream.readObject()); 
    } 

    public Unit_Type(String typeName, String... units) { 
     this.typeName = typeName; 
     this.units = FXCollections.observableArrayList(units); 
    } 

    public void setTypeName(String name) { 
     typeName = name; 
    } 

    public ObservableList<String> getUnitsForType() { 
     return units; 
    } 

    @Override 
    public String toString() { 
     return typeName; 
    } 
} 
中に
elites = new Unit_Type("Elites", 
     "Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", 
     "Assault Terminator", "Centurion Assault", "Command", 
     "Honour Guard", "Sternguard Veteran", "Terminator", 
     "Vanguard Veterans" 
); 

(デ) ObservableList以外のすべてのシリアル化は、デフォルトのシリアル化メカニズムを使用して処理されます。

stream.defaultWriteObject(); 
stream.defaultReadObject(); 

transientキーワードは、(彼らがUI要素を参照する場合は特にリスナーを保持することは不可能/ハードされるのでObservableList sは、一般的にシリアライズされない)は無視されるべきフィールドを引き起こします。このケースでは、単に/配列としてリスト内の文字列を読み書き:

詳細について
stream.writeObject(units.toArray()); 
units = (ObservableList) FXCollections.<Object>observableArrayList((Object[])stream.readObject()); 

がここに既定のプロトコルセクションをカスタマイズするを参照してください:http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html

+0

これは完璧です、時間をとっていただきありがとうございます。私が実際に理解していないコードのいくつかは、前にObjectメソッドを読み書きすることはありませんでした。彼らはどのように動作するのか説明できますか?また、私はそれがストリームに何を意味するか分からない。私はそのキーワードも見ています。もう一度私は嫌いではないと思う、私はちょうど学ぶことを試みている。 – GR412

関連する問題