绑定数据时出错- JavaFx和SQLite

3pvhb19x  于 2023-06-06  发布在  SQLite
关注(0)|答案(1)|浏览(158)

我正在做一个小项目,试图将数据库中的数据绑定到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文件中。
有人能看看代码并告诉我问题/或如何修复它吗?
谢谢

ttp71kqs

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在代码中实现该功能,编译器会告诉你是否有问题,你可以在运行应用程序之前修复它。

相关问题