我的 JavaFX 应用程序出现 ClassCasting 错误,并且值出现在 tableView 上
ClassCasting Error on my JavaFX Application and Issue with Values showing up on tableView
一切正常,但后来我添加了泛型,现在这个 ClassCastException 不断弹出,我不知道为什么。
****重要****
所以我也尝试删除它,但这是另一个问题出现的地方。打印直到牵引力控制栏的所有值。在此之后,所有的值都不会出现在事件中,尽管除了其中一些的数据类型之外,一切都完全相同。
错误
Caused by: java.lang.ClassCastException:
app.westminster.car.rentalSystem.Car cannot be cast to
app.westminster.car.rentalSystem.Motorbike at
app.westminster.car.rentalSystem.GUI.MainGUI.lambda$start(MainGUI.java:139)
at
javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578)
at
javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:563)
at javafx.scene.control.TableCell.updateItem(TableCell.java:644) at
javafx.scene.control.TableCell.indexChanged(TableCell.java:468) at
javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116) at
com.sun.javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:533)
at
com.sun.javafx.scene.control.skin.TableRowSkinBase.init(TableRowSkinBase.java:147)
at
com.sun.javafx.scene.control.skin.TableRowSkin.(TableRowSkin.java:64)
at javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:212)
at javafx.scene.control.Control.impl_processCSS(Control.java:872) at
javafx.scene.Node.processCSS(Node.java:9056) at
javafx.scene.Node.applyCss(Node.java:9153) at
com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1964)
at
com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1797)
at
com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1879)
at
com.sun.javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2528)
at
com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1189)
at javafx.scene.Parent.layout(Parent.java:1087) at
javafx.scene.Parent.layout(Parent.java:1093) at
javafx.scene.Parent.layout(Parent.java:1093) at
javafx.scene.Scene.doLayoutPass(Scene.java:552) at
javafx.scene.Scene.preferredSize(Scene.java:1646) at
javafx.scene.Scene.impl_preferredSize(Scene.java:1720) at
javafx.stage.Window.invalidated(Window.java:864) at
javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
at
javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
at javafx.stage.Window.setShowing(Window.java:940) at
javafx.stage.Window.show(Window.java:955) at
javafx.stage.Stage.show(Stage.java:259) at
app.westminster.car.rentalSystem.GUI.MainGUI.start(MainGUI.java:154)
at
com.sun.javafx.application.LauncherImpl.lambda$launchApplication11(LauncherImpl.java:863)
at
com.sun.javafx.application.PlatformImpl.lambda$runAndWait4(PlatformImpl.java:326)
at
com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method) at
com.sun.javafx.application.PlatformImpl.lambda$runLater3(PlatformImpl.java:294)
at
com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at
com.sun.glass.ui.win.WinApplication.lambda$null7(WinApplication.java:177)
... 1 more
GUI Class
public class MainGUI extends Application {
private static Stage stage;
@Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
Platform.setImplicitExit(false);
stage.setTitle("Westminster Rentals");
VBox mainLayout = new VBox();
Scene scene = new Scene(mainLayout, 1655,800);
Label heading1 = new Label("Welcome to Westminster Rentals");
heading1.setStyle("-fx-font-size: 32px; -fx-font-family: -apple-system, sans-serif;");
heading1.setPadding(new Insets(20,20,20,20));
//_____________________Search Tab__________________________________//
// search Tab will hold search bar, search button and rent button
HBox searchTab = new HBox();
searchTab.setStyle("-fx-spacing: 10px; -fx-padding: 20px");
JFXButton searchButton = new JFXButton("Search");
searchButton.setAlignment(Pos.CENTER);
searchButton.setStyle("-fx-padding: 20px;-fx-background-color: #6143d5; -fx-text-fill: #fff;");
JFXTextField searchBar = new JFXTextField();
searchBar.setPrefWidth(500);
searchBar.setStyle("-fx-padding: 20px;");
searchBar.promptTextProperty().setValue("Search....");
HBox rentTab = new HBox();
JFXButton rent = new JFXButton("Rent a car");
rent.setOnAction(e->{
RentGUI.showRentPage();
});
rent.setStyle("-fx-padding: 20px;-fx-background-color: #1ad541; -fx-text-fill: #fff;");
rentTab.getChildren().add(rent);
searchTab.getChildren().addAll(searchBar,searchButton, rentTab);
//_____________________Search Tab --END--_____________________________//
//Main Heading will hold a vertical alignment for heading1 and the searchTab Hbox to create embedded layout
VBox mainHeading = new VBox();
mainHeading.getChildren().addAll(heading1,searchTab);
//Table view and Table columns are used to build the table attribute of the app
// This needs to be done as below unless FXML is used to build the application
TableView<Vehicle> tableView = new TableView<>();
tableView.setEditable(false);
TableColumn<Vehicle, String> makeColumn = new TableColumn<>("Make");
makeColumn.setPrefWidth(150);
makeColumn.setCellValueFactory(data-> new SimpleStringProperty(data.getValue().getMake()));
TableColumn<Vehicle,String> modelColumn = new TableColumn<>("Model");
modelColumn.setPrefWidth(200);
modelColumn.setCellValueFactory(new PropertyValueFactory<>("model"));
TableColumn<Vehicle,String> plateNumColumn = new TableColumn<>("Plate Number");
plateNumColumn.setPrefWidth(200);
plateNumColumn.setCellValueFactory(new PropertyValueFactory<>("plateNumber"));
TableColumn<Vehicle,String> fuelTypeColumn = new TableColumn<>("Fuel Type");
fuelTypeColumn.setPrefWidth(200);
fuelTypeColumn.setCellValueFactory(new PropertyValueFactory<>("fuelType"));
TableColumn<Vehicle, BigDecimal> priceColumn = new TableColumn<>("Price Per Hour (USD)");
priceColumn.setPrefWidth(200);
priceColumn.setCellValueFactory(new PropertyValueFactory<>("pricePerHour"));
TableColumn<Vehicle,String> transmissionColumn = new TableColumn<>("Transmission");
transmissionColumn.setPrefWidth(200);
transmissionColumn.setCellValueFactory(new PropertyValueFactory<>("transmission"));
TableColumn carColumn = new TableColumn("Car");
carColumn.setPrefWidth(200);
carColumn.setCellValueFactory(new PropertyValueFactory("car"));
TableColumn<Car,Boolean> tractionControlColumn = new TableColumn<>("Traction Control?");
tractionControlColumn.setPrefWidth(200);
tractionControlColumn.setCellValueFactory(new PropertyValueFactory<>("tractionControl"));
TableColumn<Car,Boolean> appleCarPlayColumn = new TableColumn<>("Apple Car Play?");
appleCarPlayColumn.setPrefWidth(200);
appleCarPlayColumn.setCellValueFactory(data-> new SimpleBooleanProperty(data.getValue().hasAppleCarPlay()));
TableColumn <Car,String>parkingAssistanceColumn = new TableColumn<>("Parking Assistance?");
parkingAssistanceColumn.setPrefWidth(200);
parkingAssistanceColumn.setCellValueFactory(data-> new SimpleStringProperty(String.valueOf(data.getValue().hasParkingAssistant())));
TableColumn<Car,String> blindSpotAwarenessColumn = new TableColumn<>("Blind spot awareness?");
blindSpotAwarenessColumn.setPrefWidth(200);
blindSpotAwarenessColumn.setCellValueFactory(data-> new SimpleStringProperty(String.valueOf(data.getValue().hasBlindSpotAwareness())));
TableColumn bikeColumn = new TableColumn("Motorbikes");
bikeColumn.setPrefWidth(200);
bikeColumn.setCellValueFactory(new PropertyValueFactory("motorbike"));
TableColumn<Motorbike, Boolean> basketColumn = new TableColumn<>("Basket?");
basketColumn.setPrefWidth(200);
basketColumn.setCellValueFactory(data-> new SimpleBooleanProperty(data.getValue().hasBasket()));
TableColumn<Motorbike, Boolean> gyroColumn = new TableColumn<>("Gyroscopic Balance?");
gyroColumn.setPrefWidth(200);
gyroColumn.setCellValueFactory(data-> new SimpleBooleanProperty(data.getValue().hasGyroscopicBalance()));
carColumn.getColumns().addAll(tractionControlColumn,appleCarPlayColumn,parkingAssistanceColumn,blindSpotAwarenessColumn);
bikeColumn.getColumns().addAll(basketColumn,gyroColumn);
tableView.getColumns().addAll(makeColumn,modelColumn,plateNumColumn,fuelTypeColumn,priceColumn,transmissionColumn,carColumn,bikeColumn);
mainLayout.getChildren().addAll(mainHeading, tableView);
tableView.setItems(addTableItems());
stage.setScene(scene);
stage.show();
}
//addTableItems will create an observable list required to enter values into the table.
private ObservableList<Vehicle> addTableItems() throws UnknownHostException {
ObservableList<Vehicle> musicItem = FXCollections.observableArrayList();
for (Vehicle item: Database.getDatastore().find(Vehicle.class).asList()){
musicItem.addAll(item);
}
return musicItem;
}
public static void main(){
launch();
}
public static void showStage(){
stage.show();
}
}
Main Class 和 Main 方法
public class Main extends Thread{
private static Scanner scanner = new Scanner(System.in);
private static Stage stage;
public static void main(String[] args) {
int userResponse;
RentalVehicleManager rentalVehicleManager = new WestminsterRentalVehicleManager();
Thread guiControlThread = new Thread(MainGUI::main);
guiControlThread.start();
}
}
假设我删除了 lambda 并放入了新的 PropertyValueFactory。然后错误消失,GUI 工作
但是
牵引力控制后的数值不显示
TableView
(Vehicle
) 的类型参数与您用于某些列的第一个类型参数之间存在差异。这两个类型参数应该匹配。否则会发生这样的事情。
由于 Vehicle
是 TableView
的类型参数,编译器允许您将可分配给 Vehicle
的所有内容添加到该 TableView
的 items
列表中=].
将 basketColumn
声明为 TableColumn<Motorbike, Boolean> basketColumn
"tells" 编译器认为 table 中的所有项目都是 Motorbike
。由于这个原因,以下代码片段会在编译后的代码中产生相同的结果:
TableColumn basketColumn = new TableColumn("Basket?"); // note the use of the raw type here
basketColumn.setPrefWidth(200);
// note the hidden cast inserted here by the compiler based on the type parameter in the declaration
// this is the cause of the ClassCastException
basketColumn.setCellValueFactory(data -> new SimpleBooleanProperty(((Motorbike) data.getValue()).hasBasket()));
因为您想将 Car
和 Motorbike
都放入 TableView
,您需要 return 根据 cellValueFactory
s:
TableColumn<Vehicle, Boolean> basketColumn = new TableColumn<>("Basket?");
basketColumn.setPrefWidth(200);
basketColumn.setCellValueFactory(data -> {
Vehicle item = data.getValue();
if (item instanceof Motorbike) {
return new SimpleBooleanProperty(((Motorbike) item).hasBasket());
} else {
return null; // put something else here, if you don't want empty cells for non Motorbikes
}
});
您的代码中还有多个其他地方需要像这样进行更改。
一切正常,但后来我添加了泛型,现在这个 ClassCastException 不断弹出,我不知道为什么。
****重要****
所以我也尝试删除它,但这是另一个问题出现的地方。打印直到牵引力控制栏的所有值。在此之后,所有的值都不会出现在事件中,尽管除了其中一些的数据类型之外,一切都完全相同。
错误
Caused by: java.lang.ClassCastException: app.westminster.car.rentalSystem.Car cannot be cast to app.westminster.car.rentalSystem.Motorbike at app.westminster.car.rentalSystem.GUI.MainGUI.lambda$start(MainGUI.java:139) at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:578) at javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:563) at javafx.scene.control.TableCell.updateItem(TableCell.java:644) at javafx.scene.control.TableCell.indexChanged(TableCell.java:468) at javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:116) at com.sun.javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:533) at com.sun.javafx.scene.control.skin.TableRowSkinBase.init(TableRowSkinBase.java:147) at com.sun.javafx.scene.control.skin.TableRowSkin.(TableRowSkin.java:64) at javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:212) at javafx.scene.control.Control.impl_processCSS(Control.java:872) at javafx.scene.Node.processCSS(Node.java:9056) at javafx.scene.Node.applyCss(Node.java:9153) at com.sun.javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1964) at com.sun.javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1797) at com.sun.javafx.scene.control.skin.VirtualFlow.getCellLength(VirtualFlow.java:1879) at com.sun.javafx.scene.control.skin.VirtualFlow.computeViewportOffset(VirtualFlow.java:2528) at com.sun.javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1189) at javafx.scene.Parent.layout(Parent.java:1087) at javafx.scene.Parent.layout(Parent.java:1093) at javafx.scene.Parent.layout(Parent.java:1093) at javafx.scene.Scene.doLayoutPass(Scene.java:552) at javafx.scene.Scene.preferredSize(Scene.java:1646) at javafx.scene.Scene.impl_preferredSize(Scene.java:1720) at javafx.stage.Window.invalidated(Window.java:864) at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109) at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144) at javafx.stage.Window.setShowing(Window.java:940) at javafx.stage.Window.show(Window.java:955) at javafx.stage.Stage.show(Stage.java:259) at app.westminster.car.rentalSystem.GUI.MainGUI.start(MainGUI.java:154) at com.sun.javafx.application.LauncherImpl.lambda$launchApplication11(LauncherImpl.java:863) at com.sun.javafx.application.PlatformImpl.lambda$runAndWait4(PlatformImpl.java:326) at com.sun.javafx.application.PlatformImpl.lambda$null2(PlatformImpl.java:295) at java.security.AccessController.doPrivileged(Native Method) at com.sun.javafx.application.PlatformImpl.lambda$runLater3(PlatformImpl.java:294) at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$null7(WinApplication.java:177) ... 1 more
GUI Class
public class MainGUI extends Application {
private static Stage stage;
@Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
Platform.setImplicitExit(false);
stage.setTitle("Westminster Rentals");
VBox mainLayout = new VBox();
Scene scene = new Scene(mainLayout, 1655,800);
Label heading1 = new Label("Welcome to Westminster Rentals");
heading1.setStyle("-fx-font-size: 32px; -fx-font-family: -apple-system, sans-serif;");
heading1.setPadding(new Insets(20,20,20,20));
//_____________________Search Tab__________________________________//
// search Tab will hold search bar, search button and rent button
HBox searchTab = new HBox();
searchTab.setStyle("-fx-spacing: 10px; -fx-padding: 20px");
JFXButton searchButton = new JFXButton("Search");
searchButton.setAlignment(Pos.CENTER);
searchButton.setStyle("-fx-padding: 20px;-fx-background-color: #6143d5; -fx-text-fill: #fff;");
JFXTextField searchBar = new JFXTextField();
searchBar.setPrefWidth(500);
searchBar.setStyle("-fx-padding: 20px;");
searchBar.promptTextProperty().setValue("Search....");
HBox rentTab = new HBox();
JFXButton rent = new JFXButton("Rent a car");
rent.setOnAction(e->{
RentGUI.showRentPage();
});
rent.setStyle("-fx-padding: 20px;-fx-background-color: #1ad541; -fx-text-fill: #fff;");
rentTab.getChildren().add(rent);
searchTab.getChildren().addAll(searchBar,searchButton, rentTab);
//_____________________Search Tab --END--_____________________________//
//Main Heading will hold a vertical alignment for heading1 and the searchTab Hbox to create embedded layout
VBox mainHeading = new VBox();
mainHeading.getChildren().addAll(heading1,searchTab);
//Table view and Table columns are used to build the table attribute of the app
// This needs to be done as below unless FXML is used to build the application
TableView<Vehicle> tableView = new TableView<>();
tableView.setEditable(false);
TableColumn<Vehicle, String> makeColumn = new TableColumn<>("Make");
makeColumn.setPrefWidth(150);
makeColumn.setCellValueFactory(data-> new SimpleStringProperty(data.getValue().getMake()));
TableColumn<Vehicle,String> modelColumn = new TableColumn<>("Model");
modelColumn.setPrefWidth(200);
modelColumn.setCellValueFactory(new PropertyValueFactory<>("model"));
TableColumn<Vehicle,String> plateNumColumn = new TableColumn<>("Plate Number");
plateNumColumn.setPrefWidth(200);
plateNumColumn.setCellValueFactory(new PropertyValueFactory<>("plateNumber"));
TableColumn<Vehicle,String> fuelTypeColumn = new TableColumn<>("Fuel Type");
fuelTypeColumn.setPrefWidth(200);
fuelTypeColumn.setCellValueFactory(new PropertyValueFactory<>("fuelType"));
TableColumn<Vehicle, BigDecimal> priceColumn = new TableColumn<>("Price Per Hour (USD)");
priceColumn.setPrefWidth(200);
priceColumn.setCellValueFactory(new PropertyValueFactory<>("pricePerHour"));
TableColumn<Vehicle,String> transmissionColumn = new TableColumn<>("Transmission");
transmissionColumn.setPrefWidth(200);
transmissionColumn.setCellValueFactory(new PropertyValueFactory<>("transmission"));
TableColumn carColumn = new TableColumn("Car");
carColumn.setPrefWidth(200);
carColumn.setCellValueFactory(new PropertyValueFactory("car"));
TableColumn<Car,Boolean> tractionControlColumn = new TableColumn<>("Traction Control?");
tractionControlColumn.setPrefWidth(200);
tractionControlColumn.setCellValueFactory(new PropertyValueFactory<>("tractionControl"));
TableColumn<Car,Boolean> appleCarPlayColumn = new TableColumn<>("Apple Car Play?");
appleCarPlayColumn.setPrefWidth(200);
appleCarPlayColumn.setCellValueFactory(data-> new SimpleBooleanProperty(data.getValue().hasAppleCarPlay()));
TableColumn <Car,String>parkingAssistanceColumn = new TableColumn<>("Parking Assistance?");
parkingAssistanceColumn.setPrefWidth(200);
parkingAssistanceColumn.setCellValueFactory(data-> new SimpleStringProperty(String.valueOf(data.getValue().hasParkingAssistant())));
TableColumn<Car,String> blindSpotAwarenessColumn = new TableColumn<>("Blind spot awareness?");
blindSpotAwarenessColumn.setPrefWidth(200);
blindSpotAwarenessColumn.setCellValueFactory(data-> new SimpleStringProperty(String.valueOf(data.getValue().hasBlindSpotAwareness())));
TableColumn bikeColumn = new TableColumn("Motorbikes");
bikeColumn.setPrefWidth(200);
bikeColumn.setCellValueFactory(new PropertyValueFactory("motorbike"));
TableColumn<Motorbike, Boolean> basketColumn = new TableColumn<>("Basket?");
basketColumn.setPrefWidth(200);
basketColumn.setCellValueFactory(data-> new SimpleBooleanProperty(data.getValue().hasBasket()));
TableColumn<Motorbike, Boolean> gyroColumn = new TableColumn<>("Gyroscopic Balance?");
gyroColumn.setPrefWidth(200);
gyroColumn.setCellValueFactory(data-> new SimpleBooleanProperty(data.getValue().hasGyroscopicBalance()));
carColumn.getColumns().addAll(tractionControlColumn,appleCarPlayColumn,parkingAssistanceColumn,blindSpotAwarenessColumn);
bikeColumn.getColumns().addAll(basketColumn,gyroColumn);
tableView.getColumns().addAll(makeColumn,modelColumn,plateNumColumn,fuelTypeColumn,priceColumn,transmissionColumn,carColumn,bikeColumn);
mainLayout.getChildren().addAll(mainHeading, tableView);
tableView.setItems(addTableItems());
stage.setScene(scene);
stage.show();
}
//addTableItems will create an observable list required to enter values into the table.
private ObservableList<Vehicle> addTableItems() throws UnknownHostException {
ObservableList<Vehicle> musicItem = FXCollections.observableArrayList();
for (Vehicle item: Database.getDatastore().find(Vehicle.class).asList()){
musicItem.addAll(item);
}
return musicItem;
}
public static void main(){
launch();
}
public static void showStage(){
stage.show();
}
}
Main Class 和 Main 方法
public class Main extends Thread{
private static Scanner scanner = new Scanner(System.in);
private static Stage stage;
public static void main(String[] args) {
int userResponse;
RentalVehicleManager rentalVehicleManager = new WestminsterRentalVehicleManager();
Thread guiControlThread = new Thread(MainGUI::main);
guiControlThread.start();
}
}
假设我删除了 lambda 并放入了新的 PropertyValueFactory。然后错误消失,GUI 工作
但是
牵引力控制后的数值不显示
TableView
(Vehicle
) 的类型参数与您用于某些列的第一个类型参数之间存在差异。这两个类型参数应该匹配。否则会发生这样的事情。
由于 Vehicle
是 TableView
的类型参数,编译器允许您将可分配给 Vehicle
的所有内容添加到该 TableView
的 items
列表中=].
将 basketColumn
声明为 TableColumn<Motorbike, Boolean> basketColumn
"tells" 编译器认为 table 中的所有项目都是 Motorbike
。由于这个原因,以下代码片段会在编译后的代码中产生相同的结果:
TableColumn basketColumn = new TableColumn("Basket?"); // note the use of the raw type here
basketColumn.setPrefWidth(200);
// note the hidden cast inserted here by the compiler based on the type parameter in the declaration
// this is the cause of the ClassCastException
basketColumn.setCellValueFactory(data -> new SimpleBooleanProperty(((Motorbike) data.getValue()).hasBasket()));
因为您想将 Car
和 Motorbike
都放入 TableView
,您需要 return 根据 cellValueFactory
s:
TableColumn<Vehicle, Boolean> basketColumn = new TableColumn<>("Basket?");
basketColumn.setPrefWidth(200);
basketColumn.setCellValueFactory(data -> {
Vehicle item = data.getValue();
if (item instanceof Motorbike) {
return new SimpleBooleanProperty(((Motorbike) item).hasBasket());
} else {
return null; // put something else here, if you don't want empty cells for non Motorbikes
}
});
您的代码中还有多个其他地方需要像这样进行更改。