两天前我发布了this question关于将一个ChangeListener附加到ComboBox以指示在第二个ComboBox上显示什么输出。简而言之,我们的想法是第一个ComboBox显示一些单位类型,并且取决于所选的单位类型将取决于根据所选单位类型在第二个ComboBox中显示的单位列表。例如,如果您选择" Elites"第一个ComboBox中的单元类型第二个ComboBox应填充所有" Elite"单元。
现在,回复my original question的人对ChangeListener中的代码提供了很多帮助,我确实设法使其正常运行。但是,只有在一次将一个单元添加到单元类型时,它才有效。理想情况下,我想要将UnitList或其他一些合适的单位数据结构添加到单元类型,而不是单个单元。这会减少代码,并且更有效率。
因此,您可以在此代码段中看到,目前elites单元类型addUnit方法一次只接受单个字符串,
elites = new Unit_Type("Elites");
elites.addUnit("Dreadnought");
elites.addUnit("Ironclad Dreadnought");
我希望如此,所以我可以向精英单元类型addUnit方法添加一个ArrayList或simular数据结构,就像这段代码片段一样:
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);
请注意,elitesList是由辅助方法生成的,因为还有其他8个列表,每个列表代表不同的单元类型。
现在我尝试更改Unit Type类中的代码,使单元ArrayList的类型为ArrayList<String>
,并尝试更改addUnit方法以接受ArrayList<String>
的参数但是每当我运行程序,在第一个ComboBox中选择一个Unit Type,导致第二个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;
}
}
答案 0 :(得分:1)
我不会将支持列表存储在Unit_Type
类中。最好将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
关键字会导致忽略该字段(ObservableList
s一般不可序列化,因为如果它们引用UI元素,则很难/不可能持久监听器。在这种情况下,我们只需将列表中的字符串读/写为数组:
stream.writeObject(units.toArray());
units = (ObservableList) FXCollections.<Object>observableArrayList((Object[])stream.readObject());
有关详细信息,请参阅此处的自定义默认协议部分:http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html