JavaFX:使用地图填充表格视图
JavaFX: Populate a tableview using map
我开始学习 JavaFX,我想用我的数据库中的数据填充我的表视图。我了解到我可以使用地图来构建数据,但它没有用。表格视图只显示列的名称但没有行。
这是我的代码:
Main.java
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
MainWindowControl.java
package application;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
public class MainWindowController {
@FXML
private TableView<Map<Integer, String>> tableView = new TableView<>(generateDataInMap());
final static Integer first = 1;
public void openDatabase() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement();
ResultSet rSet = statement.executeQuery("select * from myTable");
int col = rSet.getMetaData().getColumnCount();
for (int i = 1; i <= col; i++) {
rSet = statement.executeQuery("select * from myTable");
Integer key = 1;
String name = rSet.getMetaData().getColumnName(i);
TableColumn<Map<Integer, String>, String> tableColumn = new TableColumn<>(name);
tableColumn.setCellValueFactory(new MapValueFactory(key));
tableView.getColumns().add(tableColumn);
}
}
private ObservableList<Map<Integer, String>> generateDataInMap(){
Connection connection = null;
ObservableList<Map<Integer, String>> alldata = FXCollections.observableArrayList();
try {
connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement();
ResultSet rSet = statement.executeQuery("select * from myTable");
int col = rSet.getMetaData().getColumnCount();
while(rSet.next()) {
Map<Integer, String> dataRow = new HashMap<>();
for (int i = 1; i <= col; i++) {
String value = rSet.getString(i);
dataRow.put(i, value);
}
alldata.add(dataRow);
}
connection.close();
return alldata;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
MainWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="255.0" prefWidth="427.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainWindowController">
<children>
<TableView fx:id="tableView" layoutX="34.0" layoutY="41.0" prefHeight="200.0" prefWidth="359.0" />
<Button layoutX="186.0" layoutY="14.0" mnemonicParsing="false" onAction="#openDatabase" text="Load Data" />
</children>
</AnchorPane>
你知道我代码中的错误在哪里吗?我正在尝试模拟 SQLiteStudio 的功能,当我选择一个数据库时,数据将填充到表视图中。
您正在控制器 class 的初始化程序中创建 TableView
。此 TableView
充满了数据,但实例永远不会显示在场景中,因为 FXMLLoader
从 fxml 创建实例。
在 initialize()
方法中进行这样的初始化。此方法由 FXMLLoader
运行 在注入所有对象后使屏幕上显示的 tableView
实例可访问。
补充说明:
- 您将始终为
1
的 key
传递给值工厂。相反,您应该使用 i
.
- 您为每一列重新查询数据库,总是获取 table 中的每一行。这是非常低效的。只需执行一次查询。考虑使用结果来初始化行和列。
- 考虑分离数据访问和查看。您可以通过将数据传递给控制器来完成此操作,请参阅 Passing Parameters JavaFX FXML
@FXML
private TableView<Map<Integer, String>> tableView;
@FXML
private void initialize() throws Exception {
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement()) {
ResultSet rSet = statement.executeQuery("select * from myTable");
openDatabase(rSet);
tableView.setItems(generateDataInMap(rSet));
}
// TODO: Exception handling???
}
private void openDatabase(ResultSet rSet) throws SQLException {
final ResultSetMetaData metadata = rSet.getMetaData();
final int col = metadata.getColumnCount();
for (int i = 1; i <= col; i++) {
String name = metadata.getColumnName(i);
TableColumn<Map<Integer, String>, String> tableColumn = new TableColumn<>(name);
tableColumn.setCellValueFactory(new MapValueFactory(i));
tableView.getColumns().add(tableColumn);
}
}
private ObservableList<Map<Integer, String>> generateDataInMap(ResultSet rSet) {
ObservableList<Map<Integer, String>> alldata = FXCollections.observableArrayList();
final int col = rSet.getMetaData().getColumnCount();
while(rSet.next()) {
Map<Integer, String> dataRow = new HashMap<>();
for (int i = 1; i <= col; i++) {
String value = rSet.getString(i);
dataRow.put(i, value);
}
alldata.add(dataRow);
}
return alldata;
}
请注意,上述修改后的代码版本要求您删除 onAction
事件处理程序,但由于添加行但不初始化列没有什么意义,我将调用移至 initialize
方法并以不允许您再将其用作 EventHandler
的方式修改签名。
我开始学习 JavaFX,我想用我的数据库中的数据填充我的表视图。我了解到我可以使用地图来构建数据,但它没有用。表格视图只显示列的名称但没有行。
这是我的代码:
Main.java
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
MainWindowControl.java
package application;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
public class MainWindowController {
@FXML
private TableView<Map<Integer, String>> tableView = new TableView<>(generateDataInMap());
final static Integer first = 1;
public void openDatabase() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement();
ResultSet rSet = statement.executeQuery("select * from myTable");
int col = rSet.getMetaData().getColumnCount();
for (int i = 1; i <= col; i++) {
rSet = statement.executeQuery("select * from myTable");
Integer key = 1;
String name = rSet.getMetaData().getColumnName(i);
TableColumn<Map<Integer, String>, String> tableColumn = new TableColumn<>(name);
tableColumn.setCellValueFactory(new MapValueFactory(key));
tableView.getColumns().add(tableColumn);
}
}
private ObservableList<Map<Integer, String>> generateDataInMap(){
Connection connection = null;
ObservableList<Map<Integer, String>> alldata = FXCollections.observableArrayList();
try {
connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement();
ResultSet rSet = statement.executeQuery("select * from myTable");
int col = rSet.getMetaData().getColumnCount();
while(rSet.next()) {
Map<Integer, String> dataRow = new HashMap<>();
for (int i = 1; i <= col; i++) {
String value = rSet.getString(i);
dataRow.put(i, value);
}
alldata.add(dataRow);
}
connection.close();
return alldata;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
MainWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="255.0" prefWidth="427.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainWindowController">
<children>
<TableView fx:id="tableView" layoutX="34.0" layoutY="41.0" prefHeight="200.0" prefWidth="359.0" />
<Button layoutX="186.0" layoutY="14.0" mnemonicParsing="false" onAction="#openDatabase" text="Load Data" />
</children>
</AnchorPane>
你知道我代码中的错误在哪里吗?我正在尝试模拟 SQLiteStudio 的功能,当我选择一个数据库时,数据将填充到表视图中。
您正在控制器 class 的初始化程序中创建 TableView
。此 TableView
充满了数据,但实例永远不会显示在场景中,因为 FXMLLoader
从 fxml 创建实例。
在 initialize()
方法中进行这样的初始化。此方法由 FXMLLoader
运行 在注入所有对象后使屏幕上显示的 tableView
实例可访问。
补充说明:
- 您将始终为
1
的key
传递给值工厂。相反,您应该使用i
. - 您为每一列重新查询数据库,总是获取 table 中的每一行。这是非常低效的。只需执行一次查询。考虑使用结果来初始化行和列。
- 考虑分离数据访问和查看。您可以通过将数据传递给控制器来完成此操作,请参阅 Passing Parameters JavaFX FXML
@FXML
private TableView<Map<Integer, String>> tableView;
@FXML
private void initialize() throws Exception {
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement()) {
ResultSet rSet = statement.executeQuery("select * from myTable");
openDatabase(rSet);
tableView.setItems(generateDataInMap(rSet));
}
// TODO: Exception handling???
}
private void openDatabase(ResultSet rSet) throws SQLException {
final ResultSetMetaData metadata = rSet.getMetaData();
final int col = metadata.getColumnCount();
for (int i = 1; i <= col; i++) {
String name = metadata.getColumnName(i);
TableColumn<Map<Integer, String>, String> tableColumn = new TableColumn<>(name);
tableColumn.setCellValueFactory(new MapValueFactory(i));
tableView.getColumns().add(tableColumn);
}
}
private ObservableList<Map<Integer, String>> generateDataInMap(ResultSet rSet) {
ObservableList<Map<Integer, String>> alldata = FXCollections.observableArrayList();
final int col = rSet.getMetaData().getColumnCount();
while(rSet.next()) {
Map<Integer, String> dataRow = new HashMap<>();
for (int i = 1; i <= col; i++) {
String value = rSet.getString(i);
dataRow.put(i, value);
}
alldata.add(dataRow);
}
return alldata;
}
请注意,上述修改后的代码版本要求您删除 onAction
事件处理程序,但由于添加行但不初始化列没有什么意义,我将调用移至 initialize
方法并以不允许您再将其用作 EventHandler
的方式修改签名。