首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaFX -使用ComboBox上的ChangeListener来使用ArrayList填充另一个ComboBox会导致ArrayList为空

JavaFX -使用ComboBox上的ChangeListener来使用ArrayList填充另一个ComboBox会导致ArrayList为空
EN

Stack Overflow用户
提问于 2017-09-21 11:21:26
回答 1查看 159关注 0票数 0

两天前,我发布了this question,内容是将ChangeListener附加到ComboBox,以规定在第二个ComboBox上显示什么输出。简而言之,第一个ComboBox显示了一些单元类型,而取决于所选的单元类型将取决于基于所选的单元类型在第二个ComboBox中显示的单元列表。例如,如果您在第一个ComboBox中选择了“精英”单元类型,那么第二个ComboBox应该填充所有“精英”单元。

现在,回答my original question的人在ChangeListener中的代码方面帮了很多忙,我确实设法让它正常工作。但是,目前只有当您一次向unit添加一个单元时,它才能工作。理想情况下,我希望向Unit中添加一个ArrayList或其他合适的单元数据结构,而不是单个单元。这将减少代码,并更有效。

因此,正如您在这个代码片段中所看到的,当前精英单元类型addUnit方法一次只接受单个字符串,

代码语言:javascript
复制
elites = new Unit_Type("Elites");
        elites.addUnit("Dreadnought");
        elites.addUnit("Ironclad Dreadnought");

根据我的意愿,我可以在精英单元类型的ArrayList方法中添加一个addUnit或模拟数据结构,比如这个代码片段:

代码语言:javascript
复制
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是由helper方法生成的,因为还有8个类似的列表,每个列表都代表不同的Unit。现在,我尝试更改Unit类中的代码,使单元ArrayList类型为ArrayList<String>,并尝试更改addUnit方法以接受ArrayList<String>的参数,但每当我运行程序时,在第一个ComboBox中选择Unit将导致第二个ComboBox中出现一个空数组。

下面是AddUnitPane类(视图)和Unit_Type类(模型)的其余代码

AddUnitPane类

代码语言:javascript
复制
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类

代码语言:javascript
复制
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;        
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-09-21 15:21:55

我不会将支持列表存储在Unit_Type类中。最好将ObservableList存储在字段中,编写自定义序列化方法,并使字段暂时化。

通过这种方式,您还可以使用

代码语言:javascript
复制
elites.getUnitsForType().addAll("Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard", 
                                "Sternguard Veteran", "Terminator", "Vanguard Veterans");

但是,在构造函数中初始化列表可能更短:

代码语言:javascript
复制
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;
    }
}
代码语言:javascript
复制
elites = new Unit_Type("Elites",
        "Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought",
        "Assault Terminator", "Centurion Assault", "Command",
        "Honour Guard", "Sternguard Veteran", "Terminator",
        "Vanguard Veterans"
);

在(反序列化)过程中,除ObservableList之外的一切都是使用默认序列化机制处理的。

代码语言:javascript
复制
stream.defaultWriteObject();
代码语言:javascript
复制
stream.defaultReadObject();

transient关键字会导致忽略该字段(通常情况下,ObservableList是不可序列化的,因为很难/不可能持久化监听器,特别是如果它们引用UI元素的话)。在本例中,我们只需将列表中的字符串读写为数组:

代码语言:javascript
复制
stream.writeObject(units.toArray());
代码语言:javascript
复制
units = (ObservableList) FXCollections.<Object>observableArrayList((Object[])stream.readObject());

有关详细信息,请参阅自定义默认协议部分:http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46342627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档