我正在做一个小项目,试图将数据库中的数据绑定到TableView(在main.fxml中),下面是我的错误。基于错误,在我看来是fxml文件中有问题。
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class javafx.scene.control.TableColumn cannot be cast to class javafx.scene.control.TableColumn$CellDataFeatures (javafx.scene.control.TableColumn and javafx.scene.control.TableColumn$CellDataFeatures are in module javafx.controls of loader 'app')
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:133)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.createCell(TableRowSkin.java:213)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.createCell(TableRowSkin.java:62)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.createCellAndCache(TableRowSkinBase.java:740)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.recreateCells(TableRowSkinBase.java:734)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.<init>(TableRowSkinBase.java:158)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:89)
at javafx.controls/javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:213)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:897)
at javafx.controls/javafx.scene.control.Control$1.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:146)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9456)
at javafx.graphics/javafx.scene.Node.applyCss(Node.java:9543)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1814)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1791)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getOrCreateCellSize(VirtualFlow.java:2966)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.getOrCreateCellSize(VirtualFlow.java:2949)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.recalculateAndImproveEstimatedSize(VirtualFlow.java:3021)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.recalculateEstimatedSize(VirtualFlow.java:3013)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1052)
at javafx.controls/javafx.scene.control.skin.VirtualFlow$5.invalidated(VirtualFlow.java:885)
at javafx.base/javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.base/javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:148)
at javafx.controls/javafx.scene.control.skin.VirtualFlow.setCellCount(VirtualFlow.java:899)
at javafx.controls/javafx.scene.control.skin.TableViewSkinBase.updateItemCount(TableViewSkinBase.java:555)
at javafx.controls/javafx.scene.control.skin.VirtualContainerBase.checkState(VirtualContainerBase.java:184)
at javafx.controls/javafx.scene.control.skin.VirtualContainerBase.layoutChildren(VirtualContainerBase.java:159)
at javafx.controls/javafx.scene.control.skin.TableViewSkinBase.layoutChildren(TableViewSkinBase.java:407)
at javafx.controls/javafx.scene.control.Control.layoutChildren(Control.java:601)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1207)
at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1214)
at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:579)
at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2515)
at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:421)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:420)
at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:450)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:353)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class javafx.scene.control.TableColumn cannot be cast to class javafx.scene.control.TableColumn$CellDataFeatures (javafx.scene.control.TableColumn and javafx.scene.control.TableColumn$CellDataFeatures are in module javafx.controls of loader 'app')
at javafx.controls/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:133)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.createCell(TableRowSkin.java:213)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.createCell(TableRowSkin.java:62)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.createCellAndCache(TableRowSkinBase.java:740)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.recreateCells(TableRowSkinBase.java:734)
at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.<init>(TableRowSkinBase.java:158)
at javafx.controls/javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:89)
at javafx.controls/javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:213)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:897)
at javafx.controls/javafx.scene.control.Control$1.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:146)
at javafx.graphics/javafx.scene.Parent.doProcessCSS(Parent.java:1400)
at javafx.graphics/javafx.scene.Parent$1.doProcessCSS(Parent.java:125)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.processCSSImpl(ParentHelper.java:98)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:146)
at javafx.graphics/javafx.scene.Parent.doProcessCSS(Parent.java:1400)
at javafx.graphics/javafx.scene.Parent$1.doProcessCSS(Parent.java:125)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.processCSSImpl(ParentHelper.java:98)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:146)
at javafx.graphics/javafx.scene.Parent.doProcessCSS(Parent.java:1400)
at javafx.graphics/javafx.scene.Parent$1.doProcessCSS(Parent.java:125)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.processCSSImpl(ParentHelper.java:98)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.superProcessCSSImpl(ControlHelper.java:63)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.superProcessCSS(ControlHelper.java:55)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:886)
at javafx.controls/javafx.scene.control.Control$1.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:146)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9456)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9449)
at javafx.graphics/javafx.scene.Scene.doCSSPass(Scene.java:572)
at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2510)
at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:421)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:420)
at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:450)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:353)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
package com.example.musicui;
import com.example.musicui.model.Artist;
import com.example.musicui.model.Datasource;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
public class Controller {
@FXML
private TableView<Artist> artistTable;
public void listArtists() {
Task<ObservableList<Artist>> task = new GetAllArtistsTask();
artistTable.itemsProperty().bind(task.valueProperty());
new Thread(task).start(); // *** ERROR HERE ***
}
}
class GetAllArtistsTask extends Task {
@Override
public ObservableList<Artist> call() {
return FXCollections.observableArrayList(Datasource.getInstance().queryArtists(Datasource.ORDER_BY_ASC));
}
}
public class Main extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("main.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 800, 600);
Controller controller = fxmlLoader.getController();
controller.listArtists();
stage.setTitle("Music DataBase");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
@Override
public void init() throws Exception {
super.init();
if(!Datasource.getInstance().open()){
System.out.println("FATAL ERROR: Couldn't connect to database");
Platform.exit();
}
}
@Override
public void stop() throws Exception {
super.stop();
Datasource.getInstance().close();
}
public class Datasource {
public boolean open() {
try {
conn = DriverManager.getConnection(CONNECTION_STRING);
querySongInfoView = conn.prepareStatement(QUERY_VIEW_SONG_INFO_PREP);
insertIntoArtists = conn.prepareStatement(INSERT_ARTIST, Statement.RETURN_GENERATED_KEYS);
insertIntoAlbums = conn.prepareStatement(INSERT_ALBUMS, Statement.RETURN_GENERATED_KEYS);
insertIntoSongs = conn.prepareStatement(INSERT_SONGS);
queryArtist = conn.prepareStatement(QUERY_ARTIST);
queryAlbum = conn.prepareStatement(QUERY_ALBUM);
return true;
} catch (SQLException e) {
System.out.println("Couldn't connect to database: " + e.getMessage());
e.printStackTrace();
return false;
}
}
public void close() {
try {
if (insertIntoArtists != null) {
insertIntoArtists.close();
}
if (insertIntoAlbums != null) {
insertIntoAlbums.close();
}
if (insertIntoSongs != null) {
insertIntoSongs.close();
}
if (querySongInfoView != null) {
querySongInfoView.close();
}
if (queryArtist != null) {
queryArtist.close();
}
if (queryAlbum != null) {
queryAlbum.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
System.out.println("Couldn't close connection: " + e.getMessage());
}
}
//SELECT * FROM TABLE_ARTISTS ORDER BY COLUMN_ARTIST_NAME COLLATE NOCASE DESC;
public List<Artist> queryArtists(int sortOrder) {
StringBuilder sb = new StringBuilder("SELECT * FROM ");
sb.append(TABLE_ARTISTS);
if (sortOrder != ORDER_BY_NONE) {
sb.append(" ORDER BY ");
sb.append(COLUMN_ARTIST_NAME);
sb.append(" COLLATE NOCASE ");
if (sortOrder == ORDER_BY_DESC) {
sb.append("DESC");
} else {
sb.append("ASC");
}
}
try (Statement statement = conn.createStatement();
ResultSet results = statement.executeQuery(sb.toString())) {
List<Artist> artists = new ArrayList<>();
while (results.next()) {
Artist artist = new Artist();
artist.setId(results.getInt(INDEX_ARTIST_ID));
artist.setName(results.getString(INDEX_ARTIST_NAME));
artists.add(artist);
}
return artists;
} catch (SQLException e) {
System.out.println("Query failed: " + e.getMessage());
return null;
}
}
下面是我的main.fxml
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0"
fx:controller="com.example.musicui.Controller" xmlns:fx="http://javafx.com/fxml/1">
<center>
<TableView fx:id="artistTable" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn prefWidth="${artistTable.width}" text="Name" >
<cellFactory>
<PropertyValueFactory property="name"/>
</cellFactory>
</TableColumn>
</columns>
<BorderPane.margin>
<Insets right="10.0" />
</BorderPane.margin>
</TableView>
</center>
<right>
<VBox alignment="CENTER" prefHeight="200.0" prefWidth="170.00" spacing="20.0" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets right="10.0"/>
</BorderPane.margin>
<Button maxWidth="Infinity" mnemonicParsing="false" text="List Artists"/>
<Button maxWidth="Infinity" mnemonicParsing="false" text="Show Albums (artist)"/>
<Button maxWidth="Infinity" mnemonicParsing="false" text="Update Artist"/>
</VBox>
</right>
<bottom>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<ProgressBar visible="false" prefWidth="200.0" progress="0.0">
<HBox.margin>
<Insets left="50.0"/>
</HBox.margin>
</ProgressBar>
</HBox>
</bottom>
</BorderPane>
enter image description here
在Controller类中,这行代码new Thread(task).start()
发生错误。我能想到的是问题可能出在fxml文件中。
有人能看看代码并告诉我问题/或如何修复它吗?
谢谢
1条答案
按热度按时间ttp71kqs1#
在FXML中,
PropertyValueFactory
应该定义在cellValueFactory
元素中,而不是cellFactory
元素中。无论如何,FXML应该只用于定义布局,而不是用于通用编程。
在代码中定义工厂,在控制器
initialize
方法中,而不是在FXML中。使用lambda,请参见:
常见问题
你能给我解释一下你说的“FXML应该只用于定义布局,而不是用于通用编程”是什么意思吗?
这只是我的意见。
FXML中的ML代表标记语言。如前所述,在链接的文章中,有不同类型的标记语言(表示性,过程性和描述性)。虽然FXML可以包含所有三种类型的元素,但它主要是一种表示性和描述性标记。
对于过程部分以及UI到模型数据的绑定,最好用代码来完成,特别是Java代码。FXML能够包含脚本(例如JavaScript)。但一般来说,在一个单独的控制器中的Java更好,因为逻辑更好地与标记分离。
此外,FXML还能够定义对象和使用绑定表达式,以及使用PropertyValueFactory等依赖反射来绑定到模型数据的工具。在FXML中定义的所有像这样的过程和绑定函数都只在运行时工作,而不是在编译时工作,而且从好的IDE中获得的智能编辑支持较少。由此产生的运行时错误通常是不直观的,难以理解,并且FXML文档和模型之间有紧密的绑定,这使得在不影响另一个的情况下更改一个变得更加困难。
由于上述所有原因,我认为除了定义UI组件和布局之外,在FXML中做更多的事情并不是一个好主意。即使是样式在CSS中也做得更好。
至于
PropertyValueFactory
,目前有588 questions on the JavaFX tag that refer to it,其中许多是因为PropertyValueFactory
绑定的运行时性质而被询问的。当它失败时,人们不知道发生了什么。PropertyValueFactory
只是一个可怕的遗留设计。它本来就不该被创造出来。最好使用lambda在代码中实现该功能,编译器会告诉你是否有问题,你可以在运行应用程序之前修复它。