JavaFX 动态 TableView 不显示数据库中的数据
JavaFX dynamic TableView is not showing data from the database
我使用 Scene Builder 创建了一个 TableView,如下所示 -
这是FXML代码-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="508.0" prefWidth="483.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="imran.jfx.application.Controller">
<children>
<TableView fx:id="tableview" layoutX="19.0" layoutY="94.0" prefHeight="402.0" prefWidth="443.0">
<columns>
<TableColumn fx:id="id" prefWidth="75.0" text="ID" />
<TableColumn fx:id="english" prefWidth="170.0" text="English" />
<TableColumn fx:id="bangla" prefWidth="197.0" text="Bangla" />
</columns>
</TableView>
<Button fx:id="showTableview" layoutX="188.0" layoutY="52.0" mnemonicParsing="false" onAction="#showTableData" text="Show Tables" />
</children>
</Pane>
我尝试连接数据库并尝试将数据库中的数据显示到表视图中。我试图将这些东西实现到 Controller Class 中,如下所示-
package imran.jfx.application;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.util.Callback;
public class Controller implements Initializable{
private ObservableList<ObservableList> data;
@FXML
private TableView<?> tableview;
@FXML
private TableColumn<?, ?> id;
@FXML
private TableColumn<?, ?> english;
@FXML
private TableColumn<?, ?> bangla;
@FXML
private Button showTableview;
ResultSet result;
PreparedStatement doQuery;
Connection conn;
String query;
@Override
public void initialize(URL location, ResourceBundle resources)
{
try
{
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
String url="jdbc:sqlite::resource:database/bn_words.db";
try
{
conn = DriverManager.getConnection(url);
}
catch (SQLException e) {
e.printStackTrace();
}
}
public void buildData()
{
data = FXCollections.observableArrayList();
try{
Class.forName("org.sqlite.JDBC");
String url="jdbc:sqlite::resource:database/bn_words.db";
conn = DriverManager.getConnection(url);
String SQL = "SELECT _id,en_word,bn_word from words";
ResultSet rs = conn.createStatement().executeQuery(SQL);
for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++)
{
final int j = i;
TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1));
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableview.getColumns().addAll(col);
System.out.println("Column ["+i+"] ");
}
while(rs.next()){
ObservableList<String> row = FXCollections.observableArrayList();
for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++){
row.add(rs.getString(i));
}
System.out.println("Row [1] added "+row );
data.add(row);
}
tableview.setItems(data);
}catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data");
}
}
@FXML
void showTableData(ActionEvent event) {
tableview = new TableView();
buildData();
}
}
问题是,tableview.setItems(data);
行显示错误。我不知道这个错误的原因。如果我将 private TableView<?> tableview;
行编辑为 private TableView tableview;
,那么它不会显示 tableview.setItems(data);
行的任何错误。然后应用程序运行良好。但是,当我单击“显示表”按钮时,它不会将数据显示到 TableView 中,而是将数据显示到控制台中。
还有很多警告如下-
我应该忽略这些错误吗?我该如何解决我的问题?
不,不要忽略警告。这些警告是因为您正在对 "generic" 的类型使用 原始类型 ,即参数化。如果这样做,您最终可能会遇到编译器未捕获到的类型不匹配。使用正确声明的类型并使它们正确将使您的程序更加健壮。
例如TableView
,是一个泛型类型:声明为TableView<T>
。这里 T
是一个 类型参数 :您可以(松散地说)将 T
视为代表 类型的变量table 的每一行。当您创建一个实际的 TableView
时,您必须指定该特定 TableView
将包含的类型。在您的示例中,每一行都由 ObservableList
表示。现在,ObservableList
也是一个泛型类型:它被声明为 ObservableList<E>
,其中 E
表示列表中每个元素的类型。在您的情况下,在 buildData()
方法中,您为每一行创建一个 ObservableList<String>
。因此,您的 table 类型是 ObservableList<String>
,因此您应该替换
@FXML
private TableView<?> tableView ;
和
@FXML
private TableView<ObservableList<String>> tableView ;
属于TableView<T>
的items
表示为ObservableList<T>
。因为,对于你的 table,T
是 ObservableList<String>
,你需要你的项目是 ObservableList<ObservableList<String>>
(读作 "an observable list of observable lists of strings")。所以你应该更换
private ObservableList<ObservableList> data;
和
private ObservableList<ObservableList<String>> data ;
这些更改应该会消除 tableView.setItems(data);
中的编译错误。
您还应该修复 TableColumn
的声明。 TableColumn
定义为 TableColumn<S,T>
。这里 S
是 table 的类型(即 table 中代表一行的每个项目的类型:它与 TableView
中的 T
相同定义),T
是列中单元格中每个值的类型。在所有列中,单元格中的每个值都是 String
,因此在 buildData()
中,您应该具有:
TableColumn<ObservableList<String>, String> col = new TableColumn<>(rs.getMetaData().getColumnName(i+1));
(请注意,因为这些是您要添加到 table 的列,所以不清楚为什么您还在 FXML 中定义了列;这对于您提出的问题有点离题虽然问。)
当您使用通用列表作为 table 的数据类型时,所有这些都会变得相当复杂。由于在此您知道数据库中有多少列,以及这些列代表什么,我非常强烈鼓励table 通过定义一个 class 来表示每一行中的数据来更具体。我不知道你的应用程序是什么,所以我会(可能不正确)猜测它正在做一些翻译。所以我会做
public class TranslatedWord {
private final StringProperty id = new SimpleStringProperty();
public StringProperty idProperty() {
return id ;
}
public final String getId() {
return idProperty().get();
}
public final void setId(String id) {
idProperty().set(id);
}
private final StringProperty english = new SimpleStringProperty();
public StringProperty englishProperty() {
return english ;
}
public final String getEnglish() {
return englishProperty().get();
}
public final void setEnglish(String english) {
englishProperty().set(english);
}
private final StringProperty bangla = new SimpleStringProperty();
public StringProperty banglaProperty() {
return bangla ;
}
public final String getBangla() {
return banglaProperty().get();
}
public final void setId(String bangla) {
banglaProperty().set(bangla);
}
}
现在你做了一个TableView<TranslatedWord>
和TableColumn<TranslatedWord, String>
,等等。你的data
变成了一个ObservableList<TranslatedWord>
,你的buildData()
方法有这样的代码
while(rs.next()){
TranslatedWord word = new TranslatedWord();
word.setId(rs.getString("id"));
word.setEnglish(rs.getString("english"));
word.setBangla(rs.getString("bangla"));
System.out.println("Row [1] added "+row );
data.add(row);
}
一旦您习惯了这种结构,您会发现这种风格更易于维护,因为类型指定了它们所代表的内容。
你在这段代码中还有很多其他错误:正如我之前所说,你在 FXML 中创建了 TableView
和 TableColumn
,但是你在控制器中创建了新的并操纵那些。因此,即使您解决了您实际询问的问题,您也可能会发现除非您也解决了这些问题,否则它不会按您希望的方式工作。但是摆脱编译错误和警告将是一个开始...
我使用 Scene Builder 创建了一个 TableView,如下所示 -
这是FXML代码-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="508.0" prefWidth="483.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="imran.jfx.application.Controller">
<children>
<TableView fx:id="tableview" layoutX="19.0" layoutY="94.0" prefHeight="402.0" prefWidth="443.0">
<columns>
<TableColumn fx:id="id" prefWidth="75.0" text="ID" />
<TableColumn fx:id="english" prefWidth="170.0" text="English" />
<TableColumn fx:id="bangla" prefWidth="197.0" text="Bangla" />
</columns>
</TableView>
<Button fx:id="showTableview" layoutX="188.0" layoutY="52.0" mnemonicParsing="false" onAction="#showTableData" text="Show Tables" />
</children>
</Pane>
我尝试连接数据库并尝试将数据库中的数据显示到表视图中。我试图将这些东西实现到 Controller Class 中,如下所示-
package imran.jfx.application;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.util.Callback;
public class Controller implements Initializable{
private ObservableList<ObservableList> data;
@FXML
private TableView<?> tableview;
@FXML
private TableColumn<?, ?> id;
@FXML
private TableColumn<?, ?> english;
@FXML
private TableColumn<?, ?> bangla;
@FXML
private Button showTableview;
ResultSet result;
PreparedStatement doQuery;
Connection conn;
String query;
@Override
public void initialize(URL location, ResourceBundle resources)
{
try
{
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
String url="jdbc:sqlite::resource:database/bn_words.db";
try
{
conn = DriverManager.getConnection(url);
}
catch (SQLException e) {
e.printStackTrace();
}
}
public void buildData()
{
data = FXCollections.observableArrayList();
try{
Class.forName("org.sqlite.JDBC");
String url="jdbc:sqlite::resource:database/bn_words.db";
conn = DriverManager.getConnection(url);
String SQL = "SELECT _id,en_word,bn_word from words";
ResultSet rs = conn.createStatement().executeQuery(SQL);
for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++)
{
final int j = i;
TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1));
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableview.getColumns().addAll(col);
System.out.println("Column ["+i+"] ");
}
while(rs.next()){
ObservableList<String> row = FXCollections.observableArrayList();
for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++){
row.add(rs.getString(i));
}
System.out.println("Row [1] added "+row );
data.add(row);
}
tableview.setItems(data);
}catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data");
}
}
@FXML
void showTableData(ActionEvent event) {
tableview = new TableView();
buildData();
}
}
问题是,tableview.setItems(data);
行显示错误。我不知道这个错误的原因。如果我将 private TableView<?> tableview;
行编辑为 private TableView tableview;
,那么它不会显示 tableview.setItems(data);
行的任何错误。然后应用程序运行良好。但是,当我单击“显示表”按钮时,它不会将数据显示到 TableView 中,而是将数据显示到控制台中。
还有很多警告如下-
我应该忽略这些错误吗?我该如何解决我的问题?
不,不要忽略警告。这些警告是因为您正在对 "generic" 的类型使用 原始类型 ,即参数化。如果这样做,您最终可能会遇到编译器未捕获到的类型不匹配。使用正确声明的类型并使它们正确将使您的程序更加健壮。
例如TableView
,是一个泛型类型:声明为TableView<T>
。这里 T
是一个 类型参数 :您可以(松散地说)将 T
视为代表 类型的变量table 的每一行。当您创建一个实际的 TableView
时,您必须指定该特定 TableView
将包含的类型。在您的示例中,每一行都由 ObservableList
表示。现在,ObservableList
也是一个泛型类型:它被声明为 ObservableList<E>
,其中 E
表示列表中每个元素的类型。在您的情况下,在 buildData()
方法中,您为每一行创建一个 ObservableList<String>
。因此,您的 table 类型是 ObservableList<String>
,因此您应该替换
@FXML
private TableView<?> tableView ;
和
@FXML
private TableView<ObservableList<String>> tableView ;
属于TableView<T>
的items
表示为ObservableList<T>
。因为,对于你的 table,T
是 ObservableList<String>
,你需要你的项目是 ObservableList<ObservableList<String>>
(读作 "an observable list of observable lists of strings")。所以你应该更换
private ObservableList<ObservableList> data;
和
private ObservableList<ObservableList<String>> data ;
这些更改应该会消除 tableView.setItems(data);
中的编译错误。
您还应该修复 TableColumn
的声明。 TableColumn
定义为 TableColumn<S,T>
。这里 S
是 table 的类型(即 table 中代表一行的每个项目的类型:它与 TableView
中的 T
相同定义),T
是列中单元格中每个值的类型。在所有列中,单元格中的每个值都是 String
,因此在 buildData()
中,您应该具有:
TableColumn<ObservableList<String>, String> col = new TableColumn<>(rs.getMetaData().getColumnName(i+1));
(请注意,因为这些是您要添加到 table 的列,所以不清楚为什么您还在 FXML 中定义了列;这对于您提出的问题有点离题虽然问。)
当您使用通用列表作为 table 的数据类型时,所有这些都会变得相当复杂。由于在此您知道数据库中有多少列,以及这些列代表什么,我非常强烈鼓励table 通过定义一个 class 来表示每一行中的数据来更具体。我不知道你的应用程序是什么,所以我会(可能不正确)猜测它正在做一些翻译。所以我会做
public class TranslatedWord {
private final StringProperty id = new SimpleStringProperty();
public StringProperty idProperty() {
return id ;
}
public final String getId() {
return idProperty().get();
}
public final void setId(String id) {
idProperty().set(id);
}
private final StringProperty english = new SimpleStringProperty();
public StringProperty englishProperty() {
return english ;
}
public final String getEnglish() {
return englishProperty().get();
}
public final void setEnglish(String english) {
englishProperty().set(english);
}
private final StringProperty bangla = new SimpleStringProperty();
public StringProperty banglaProperty() {
return bangla ;
}
public final String getBangla() {
return banglaProperty().get();
}
public final void setId(String bangla) {
banglaProperty().set(bangla);
}
}
现在你做了一个TableView<TranslatedWord>
和TableColumn<TranslatedWord, String>
,等等。你的data
变成了一个ObservableList<TranslatedWord>
,你的buildData()
方法有这样的代码
while(rs.next()){
TranslatedWord word = new TranslatedWord();
word.setId(rs.getString("id"));
word.setEnglish(rs.getString("english"));
word.setBangla(rs.getString("bangla"));
System.out.println("Row [1] added "+row );
data.add(row);
}
一旦您习惯了这种结构,您会发现这种风格更易于维护,因为类型指定了它们所代表的内容。
你在这段代码中还有很多其他错误:正如我之前所说,你在 FXML 中创建了 TableView
和 TableColumn
,但是你在控制器中创建了新的并操纵那些。因此,即使您解决了您实际询问的问题,您也可能会发现除非您也解决了这些问题,否则它不会按您希望的方式工作。但是摆脱编译错误和警告将是一个开始...