Исключение при выводе таблицы из базы данных в TableView Java FX
Решил перенести функционал программы из Java Swing на Java FX. И вот уже несколько дней пытаюсь совершить элементарное действие - вывести данные в TableView. Подскажите, пожалуйста.
Вот такое исключение получаю:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1071)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: javafx.fxml.LoadException:
/D:/1/out/production/1/sample/sample.fxml
at javafx.fxml/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2625)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2603)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3237)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3194)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3163)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3136)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3113)
at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3106)
at sample.Main.start(Main.java:13)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
... 1 more
Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.control.TableColumn.setCellValueFactory(javafx.util.Callback)" because "this.meal_id" is null
at sample.Controller.populateTableView(Controller.java:69)
at sample.Controller.initialize(Controller.java:49)
at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
... 17 more
Exception running application sample.Main
Process finished with exit code 1
Вот код FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:controller="sample.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="1000.0" prefHeight="800.0" prefWidth="1000.0" style="-fx-pref-width: 1000; -fx-min-width: 1000; -fx-max-width: 1000; -fx-pref-height: 800; -fx-min-height: 800; -fx-max-height: 800;" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TableView id="main_table" editable="true" fixedCellSize="1.0" layoutX="100.0" layoutY="14.0" prefHeight="200.0" prefWidth="200.0" style="-fx-pref-width: 800;">
<columns>
<TableColumn id="meal_id" prefWidth="150.0" text="Ідентифікатор страви" />
<TableColumn id="meal_name" prefWidth="75.0" text="Назва страви" />
<TableColumn id="meal_price" prefWidth="75.0" text="Ціна за 1 порцію" />
<TableColumn id="meal_category" prefWidth="75.0" text="Категорія" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</children>
</AnchorPane>
Это код контролёра:
package sample;
import com.sun.marlin.DDasher;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.TableColumn;
import java.sql.*;
public class Controller implements Initializable {
@FXML
private URL location;
@FXML
private ResourceBundle resources;
@FXML
private TableView<MealTableModel> main_table;
@FXML
private TableColumn<MealTableModel, Integer> meal_id;
@FXML
private TableColumn<MealTableModel, String> meal_name;
@FXML
private TableColumn<MealTableModel, Float> meal_price;
@FXML
private TableColumn<MealTableModel, String> meal_category;
private Connection connection;
private ObservableList<MealTableModel> observableList;
private ConnectDB connectDB;
@Override
public void initialize(URL location, ResourceBundle resources) {
connectDB = new ConnectDB();
try {
populateTableView();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public void populateTableView() throws SQLException {
observableList = FXCollections.observableArrayList();
String query ="SELECT * FROM Meals;";
connection = connectDB.getConnection();
ResultSet resultSet = connection.createStatement().executeQuery(query);
while (resultSet.next()) {
MealTableModel mealTableModel = new MealTableModel();
mealTableModel.setId(resultSet.getInt("id"));
mealTableModel.setMealName(resultSet.getString("mealName"));
mealTableModel.setMealPrice(resultSet.getFloat("MealPrice"));
mealTableModel.setMealType(resultSet.getString("mealType"));
observableList.add(mealTableModel);
}
meal_id.setCellValueFactory(new PropertyValueFactory<>("id"));
meal_name.setCellValueFactory(new PropertyValueFactory<>("mealName"));
meal_price.setCellValueFactory(new PropertyValueFactory<>("mealPrice"));
meal_category.setCellValueFactory(new PropertyValueFactory<>("mealType"));
main_table.setItems(observableList);
}
}
Это код модели:
package sample;
import javafx.beans.property.*;
public class MealTableModel {
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty mealName = new SimpleStringProperty();
private final FloatProperty mealPrice = new SimpleFloatProperty();
private final StringProperty mealCategory = new SimpleStringProperty();
public int getId() {
return id.get();
}
public void setId(int value) {
id.set(value);
}
public IntegerProperty idProperty() {
return id;
}
public String getMealName() {
return mealName.get();
}
public void setMealName(String value) {
mealName.set(value);
}
public StringProperty mealNameProperty() {
return mealName;
}
public float getMealPrice() {
return mealPrice.get();
}
public void setMealPrice(float value) {
mealPrice.set(value);
}
public FloatProperty mealPriceProperty() {
return mealPrice;
}
public String getMealType() {
return mealCategory.get();
}
public void setMealType(String value) {
mealCategory.set(value);
}
public StringProperty MealCategoryProperty() {
return mealCategory;
}
}
Ответы (1 шт):
Автор решения: Владимир
→ Ссылка
Всем спасибо! Проблему решил. Дело было в том, что я не понял, что просто id и fx:id - разные понятия.
Это подключение к базе данных:
package sample;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ConnectDB {
protected Connection connection;
public Connection getConnection() {
final String connectionString = "jdbc:sqlite:Restaurant.db";
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
Logger.getLogger(ConnectDB.class.getName()).log(Level.SEVERE, null, e);
}
try {
connection = DriverManager.getConnection(connectionString);
System.out.println("OK!");
} catch (SQLException e) {
Logger.getLogger(ConnectDB.class.getName()).log(Level.SEVERE, null, e);
}
return connection;
}
}
Это модель таблицы:
package sample;
import javafx.beans.property.*;
public class MealTableModel {
private SimpleIntegerProperty id = new SimpleIntegerProperty();
private SimpleStringProperty mealName = new SimpleStringProperty();
private SimpleFloatProperty mealPrice = new SimpleFloatProperty();
private SimpleStringProperty mealCategory = new SimpleStringProperty();
public int getId() {
return id.get();
}
public void setId(int value) {
id.set(value);
}
public IntegerProperty idProperty() {
return id;
}
public String getMealName() {
return mealName.get();
}
public void setMealName(String value) {
mealName.set(value);
}
public StringProperty mealNameProperty() {
return mealName;
}
public float getMealPrice() {
return mealPrice.get();
}
public void setMealPrice(float value) {
mealPrice.set(value);
}
public FloatProperty mealPriceProperty() {
return mealPrice;
}
public String getMealType() {
return mealCategory.get();
}
public void setMealType(String value) {
mealCategory.set(value);
}
public StringProperty MealCategoryProperty() {
return mealCategory;
}
}
Это FXML. Как раз здесь была ошибка, о которой писал выше:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/15.0.1" fx:controller="sample.Controller">
<columnConstraints>
<ColumnConstraints />
<ColumnConstraints />
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
</rowConstraints>
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-max-width: 1000; -fx-min-width: 1000; -fx-pref-width: 1000; -fx-max-height: 800; -fx-min-height: 800; -fx-pref-height: 800;" GridPane.columnIndex="2" GridPane.rowIndex="1">
<children>
<TableView fx:id="myTable" id="myTable" layoutX="125.0" layoutY="14.0" prefHeight="200.0" prefWidth="200.0" style="-fx-max-width: 750; -fx-min-width: 750; -fx-pref-width: 750;">
<columns>
<TableColumn fx:id="mealID" prefWidth="75.0" text="ідентифікатор страви" />
<TableColumn fx:id="mealName" prefWidth="75.0" text="Назва страви" />
<TableColumn fx:id="mealPrice" prefWidth="75.0" text="Ціна за 1 порцію" />
<TableColumn fx:id="mealType" prefWidth="75.0" text="Категорія" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</children>
</AnchorPane>
</children>
</GridPane>
Это контролёр:
package sample;
import com.sun.marlin.DDasher;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.TableColumn;
import java.sql.*;
public class Controller implements Initializable {
@FXML
private URL location;
@FXML
private ResourceBundle resources;
@FXML
private TableView<MealTableModel> myTable;
@FXML
private TableColumn<MealTableModel, Integer> mealID;
@FXML
private TableColumn<MealTableModel, String> mealName;
@FXML
private TableColumn<MealTableModel, Float> mealPrice;
@FXML
private TableColumn<MealTableModel, String> mealType;
private Connection connection;
private ObservableList<MealTableModel> observableList;
private ConnectDB connectDB;
@Override
public void initialize(URL location, ResourceBundle resources) {
connectDB = new ConnectDB();
try {
populateTableView();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public void populateTableView() throws SQLException {
observableList = FXCollections.observableArrayList();
String query ="SELECT * FROM Meals;";
connection = connectDB.getConnection();
ResultSet resultSet = connection.createStatement().executeQuery(query);
while (resultSet.next()) {
MealTableModel mealTableModel = new MealTableModel();
mealTableModel.setId(resultSet.getInt("id"));
mealTableModel.setMealName(resultSet.getString("mealName"));
mealTableModel.setMealPrice(resultSet.getFloat("MealPrice"));
mealTableModel.setMealType(resultSet.getString("mealType"));
observableList.add(mealTableModel);
}
mealID.setCellValueFactory(new PropertyValueFactory<>("id"));
mealName.setCellValueFactory(new PropertyValueFactory<>("mealName"));
mealPrice.setCellValueFactory(new PropertyValueFactory<>("mealPrice"));
mealType.setCellValueFactory(new PropertyValueFactory<>("mealType"));
myTable.setItems(observableList);
}
}