是的,我正在尝试创建一个程序,允许用户建立一个太空海军(战锤40k)军队,并且这是我正在努力的程序的特定部分。此部分允许用户从ComboBox中选择“单位类型”,然后下面的另一个ComboBox将填充您在第一个ComboBox中选择的“单位类型”的所有单位。
例如,如果您在第一个ComboBox中选择了精英'单位类型',那么第二个ComboBox应该填充精英单位类型的所有单位,如下所示:“Dreadnought”,“Ironclad Dreadnought”, “尊敬的无畏”,“突击终结者”,“百夫长突击”,“指挥”,“荣誉守卫”,“Sternguard退伍军人”,“终结者”,“先锋退伍军人”。有8个'单位类型',每个都有自己的单位。
我必须实现的当前设置是:我有一个名为unitTypeList的'单位类型'列表。此列表包含所有8个“单位类型”。我还有8个其他单独的列表(每个列表代表一个“单位类型”),它们为“单位类型”保留多个单位。然后我还有一个列表,其中包含前面提到的8个seprate列表中的每一个。所以这是一个列表,其中包含8个其他列表。
因此,为了使用'Unit Types'填充第一个ComboBox,我将unitTypeList放在名为unitTypeOlist的ObservableList中。然后我用ObservableList unitTypeOList填充第一个ComboBox。这很好。
现在为了用正确的单位填充第二个ComboBox,我决定将ChangeListener添加到第一个ComboBox,因此它可以获取第一个ComboBox的输入,然后使用基于该单位的单位正确填充第二个ComboBox。在第一个ComboBox中选择'Unit Type'。
但这是问题发生的地方。我在ChangeListener中创建了另一个ObservableList,并放置了包含8个单独列表的List,其中包含单元类型的每个单元。但是,当我尝试运行程序并从第一个ComboBox中选择“单元类型”时,程序终止时会出现一个巨大的错误;线程“JavaFX Application Thread”中的异常java.lang.ClassCastException:gui.model.Unit_Type无法强制转换为java.lang.Integer。
这显然与转换为int有关。但我不知道如何以任何其他方式使用ChangeListener实现我想要的东西。我需要一些帮助才能满足第一段的要求。
我已经尝试过搜索,并且发现this question已经非常有用了。 (我的设置很大程度上取决于这个问题)但我认为我的要求稍微复杂一些。
以下是我的程序的AddUnitPane类的代码(我试图尽我所能评论它):
package gui.view;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import elites.terminator.Terminator;
import gui.model.Unit;
import gui.model.Unit_Type;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import troops.scout.Scout;
public class AddUnitPane extends GridPane
{
private List<Unit_Type> unitTypeList; //Declare the unitTypeList, which holds a list of unit types
private List<String> elitesList, fastAtkList, heavySptList, hqList, lordsowList, specialCList, transportList, troopsList; //Declare the sublists that hold all the units for the type of unit
private List<List<String>> unitList; //Declare the unitList that holds all the sublists units
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;
public AddUnitPane()
{
this.setVgap(15);
this.setHgap(20);
this.setAlignment(Pos.CENTER);
ColumnConstraints col1 = new ColumnConstraints();
col1.setHalignment(HPos.RIGHT);
this.getColumnConstraints().add(col1);
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unitTypeList = new ArrayList<>(); //Initialise the unitTypeList
Collections.addAll(unitTypeList, new Unit_Type("Elites"), new Unit_Type("Fast Attack"), new Unit_Type("Heavy Support"), new Unit_Type("HQ"), new Unit_Type("Lords Of War"),
new Unit_Type("Special Characters"), new Unit_Type("Transport"), new Unit_Type("Troops")); //Populate the unitTypeList
ObservableList unitTypeOList = FXCollections.observableArrayList(unitTypeList); //Add the UnitTypeList to an observableArrayList
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
elitesList = new ArrayList<>(); //Initialise and populate all the of the sublists that hold each unit for that type
Collections.addAll(elitesList, "Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard",
"Sternguard Veteran", "Terminator", "Vanguard Veterans");
fastAtkList = new ArrayList<>();
Collections.addAll(fastAtkList, "Attack Bike", "Stormhawk Interceptor", "Stormtalon Gunship", "Assault", "Bike", "Land Speeder", "Scout Bike");
heavySptList = new ArrayList<>();
Collections.addAll(heavySptList, "Hunter", "Land Raider Crusader", "Land Raider Redeemer", "Land Raider", "Predator", "Stalker", "Stormraaven Gunship", "Vindicator",
"Whirlwind", "Centurion Devastator", "Devastator", "Thunderfire Cannon");
hqList = new ArrayList<>();
Collections.addAll(hqList, "Captain", "Chaplain", "Librarian", "Techmarine");
lordsowList = new ArrayList<>();
Collections.addAll(lordsowList, "Marneus Calger", "Roboute Guilliman");
specialCList = new ArrayList<>();
Collections.addAll(specialCList, "Antaro Chronus", "Cato Sicarius", "Ortan Cassius", "Torias Telion", "Varro Tigurius");
transportList = new ArrayList<>();
Collections.addAll(transportList, "Drop Pod", "Land Speeder Storm", "Razorback", "Rhino");
troopsList = new ArrayList<>();
Collections.addAll(troopsList, "Scout", "Tactical");
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unitList = new ArrayList<>(); //Initialise and populate the List thats holds other Lists that hold the different units
Collections.addAll(unitList, elitesList, fastAtkList, heavySptList, hqList, lordsowList, specialCList, transportList, troopsList);
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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
unitTypeCombo.setItems(unitTypeOList); //Populate the unitTypeCombo with the UnitTypeOList (observable list) from line 56
unitTypeCombo.getSelectionModel().selectFirst(); //Set the unitTypeCombo to show the first item
unitCombo = new ComboBox<>(); //Initialise the unitCombo
unitTypeCombo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() //add a change listener to the unitTypeCombo
{
@Override
public void changed(ObservableValue arg0, Object arg1, Object arg2)
{
ObservableList unitOList = FXCollections.observableArrayList(unitList.get((int) arg2)); //add the unitList from line 88 to an observable list and cast arg2 to an int
unitCombo.setItems(unitOList); //set the unitCombo items with the observable list from above
}
});
unitCombo = new ComboBox<>();
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 ComboBox<Unit_Type> getUnitClass()
{
return unitTypeCombo;
}
public ComboBox<String> getUnit()
{
return unitCombo;
}
public String getSquadName()
{
return squadNameTf.getText();
}
public ComboBox<Integer> getSquadSize()
{
return squadSizeCombo;
}
public void AddUnitHandler(EventHandler<ActionEvent> handler)
{
addSquadBtn.setOnAction(handler);
}
}
答案 0 :(得分:1)
这是您应该避免使用原始类型的原因之一。
您的ChangeListener
就像是在听IntegerProperty
而不是Property<Unit_Type>
一样。无法将Unit_Type
对象转换为Integer
,因此您在此表达式中获得异常:
unitList.get((int) arg2)
如果使用ChangeListener<Integer>
,您的编译器会抱怨此问题。
您可以改为监听selectedIndex
属性(当然检查有效索引 - -1
也是一个可能的值)。
但是,将列表作为属性添加到Unit_Type
会更容易。这将允许你写这样的东西:
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.getUnits());
}
});
顺便说一句:由于你从不调整列表的大小,下面的初始化方法会简单得多:
elitesList = Arrays.asList("Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard",
"Sternguard Veteran", "Terminator", "Vanguard Veterans");
...
即使您想使用特定的列表类型,最好减少样板代码并引入辅助方法:
private static <T> List<T> createArrayList(T... items) {
List<T> result = new ArrayList<>(items.length);
for (T item : items) {
result.add(result);
}
return result;
}
elitesList = createArrayList("Dreadnought", "Ironclad Dreadnought", "Venerable Dreadnought", "Assault Terminator", "Centurion Assault", "Command", "Honour Guard",
"Sternguard Veteran", "Terminator", "Vanguard Veterans");
...