我创建了一个小程序,它应该从数据库加载数据并将其显示在JavaFX应用程序的TableView元素中。
问题是,当我启动应用程序时,我看到的只是空行。不显示不同行的数据。但我确信它们是以某种方式处理的,因为显示的空行数与从数据库加载的行数相匹配。
我的System.out.prints for debug打印出来自数据库的正确数据,所以我确定问题不在DBLoader类中。
我从this指南中获取了大部分内容。到目前为止,我所做的工作受本教程前两部分的启发。
编辑:是的,我已将DatabaseOverviewControll.java添加为DatabaseOverview.fxml的控制器类。我已将itemNumberColumn,descriptionColumn和priceColumn添加为各自TableColumn元素的fx:id。
扩展应用程序的我的PrototypeApp类,是可运行的类:
package prototype;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import prototype.util.DBLoader;
import javafx.collections.*;
import prototype.view.DatabaseOverviewController;
import prototype.model.Row;
public class PrototypeApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private ObservableList<Row> databaseData = FXCollections
.observableArrayList();
/**
* The constructor. Creates an dbLoader object and loads the database data
* from that dbLoader into the ObservableArrayList databaseData;
*/
public PrototypeApp() {
//DBLoader dbLoader = new DBLoader();
// databaseData = dbLoader.getData(); //This is used by me, but for the
// sake of testability I added some mock data instead.
// Some mock data for Stack Overflow users.
databaseData.add(new Row("abc", "efg", "hij"));
databaseData.add(new Row("abc2", "efg2", "hij2"));
databaseData.add(new Row("abc3", "efg3", "hij3"));
databaseData.add(new Row("abc4", "efg4", "hij4"));
// For debugging.
for (Row row : databaseData) {
System.out.println(row.getItemNumber() + "\t" + row.getDescription() + "\t" + row.getPrice());
}
}
public ObservableList<Row> getDatabaseData() {
return databaseData;
}
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Prototype");
initRootLayout();
showDatabaseOverview();
}
/**
* Initializes the root layout.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(PrototypeApp.class
.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Shows the database overview inside the root layout.
*/
public void showDatabaseOverview() {
try {
// Load database overview
FXMLLoader loader = new FXMLLoader();
loader.setLocation(PrototypeApp.class
.getResource("view/DatabaseOverview.fxml"));
AnchorPane databaseOverview = (AnchorPane) loader.load();
// Set the database overview into the center of root layout.
rootLayout.setCenter(databaseOverview);
// Give the controller access to the prototype app.
DatabaseOverviewController controller = loader.getController();
controller.setPrototypeApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
*
* @return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
这是我的DatabaseOverviewController类:
package prototype.view;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import prototype.PrototypeApp;
import prototype.model.Row;
public class DatabaseOverviewController {
@FXML
private TableView<Row> databaseTable;
@FXML
private TableColumn<Row, String> itemNumberColumn;
@FXML
private TableColumn<Row, String> descriptionColumn;
@FXML
private TableColumn<Row, String> priceColumn;
@FXML
private Label itemNumberLabel;
@FXML
private Label descriptionLabel;
@FXML
private Label priceLabel;
// Reference to the prototype application
private PrototypeApp prototypeApp;
/**
* The constructor The constructor is called before the initialize() method.
*/
public DatabaseOverviewController() {
}
/**
* Initializes a controller class. This method is automatically called after
* the fxml file has been loaded.
*/
@FXML
private void intialize() {
// Initialize the database table with the three columns.
itemNumberColumn.setCellValueFactory(cellData -> cellData.getValue()
.itemNumberProperty());
descriptionColumn.setCellValueFactory(cellData -> cellData.getValue()
.descriptionProperty());
priceColumn.setCellValueFactory(cellData -> cellData.getValue()
.priceProperty());
}
/**
* A method called by the prototype application to give a reference back to
* itself.
*
* @param prototypeApp
*/
public void setPrototypeApp(PrototypeApp prototypeApp) {
this.prototypeApp = prototypeApp;
// Adds observable list data to the table
databaseTable.setItems(prototypeApp.getDatabaseData());
}
}
这是我的行类,表示SQL表中的一行:
package prototype.model;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/*
* Model class for a SQL row.
*
* @author Jonatan Stenbacka
*/
public class Row {
private final StringProperty itemNumber;
private final StringProperty description;
private final StringProperty price;
/**
* Default constructor
*/
public Row() {
this(null, null, null);
}
/**
* Constructor
* @param itemNumber
* @param description
* @param price
*/
public Row (String itemNumber, String description, String price) {
this.itemNumber = new SimpleStringProperty(itemNumber);
this.description = new SimpleStringProperty(description);
this.price = new SimpleStringProperty(price);
}
public String getItemNumber() {
return itemNumber.get();
}
public void setItemNumber(String itemNumber) {
this.itemNumber.set(itemNumber);
}
public StringProperty itemNumberProperty() {
return itemNumber;
}
public String getDescription() {
return description.get();
}
public void setDescription(String description) {
this.description.set(description);
}
public StringProperty descriptionProperty() {
return description;
}
public String getPrice() {
return price.get();
}
public void setPrice(String price) {
this.price.set(price);
}
public StringProperty priceProperty() {
return price;
}
}
编辑:这是我的FXML文件。如果你只是添加一些模拟行数据,应该足以运行程序。
DatabaseOverview.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="prototype.view.DatabaseOverviewController">
<children>
<BorderPane layoutX="191.0" layoutY="58.0" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<Label text="Tables" BorderPane.alignment="CENTER">
<font>
<Font size="24.0" />
</font>
</Label>
</top>
<bottom>
<Button mnemonicParsing="false" onAction="#handleLoadDatabase" text="Load" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="10.0" />
</BorderPane.margin>
</Button>
</bottom>
<center>
<TableView fx:id="databaseTable" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="itemNumberColumn" prefWidth="200.0" text="Item Number" />
<TableColumn fx:id="descriptionColumn" prefWidth="200.0" text="Description" />
<TableColumn fx:id="priceColumn" prefWidth="200.0" text="Price" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</center>
</BorderPane>
</children>
</AnchorPane>
RootLayout.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
答案 0 :(得分:1)
DatabaseOverviewController
中有一个简单的拼写错误:您有intialize()
作为方法名称,而不是initialize()
。由于FXMLLoader
使用反射来搜索名为initialize
的方法,并且如果找不到该方法就不执行任何操作,因此您的方法无法调用。修正拼写错误可以解决问题。
对于它的价值,这是我如何理解这一点,因为它很难看到。我和你一样,观察到表中存在正确的行数(你可以选择它们),但是没有显示任何内容。这几乎总是通过没有设置cellValueFactory
来调用(或者设置错误,如果你使用PropertyValueFactory
就会发生这种情况,但是当你使用你在这里展示的lambdas的好方法时很少发生) 。
由于initialize()
方法似乎正确设置了这些,我首先添加了日志记录,Row.itemNumberProperty()
,然后当我发现没有调用该方法时(每个{应该调用它)该列中的{1}},TableCell
方法本身。当我发现initialize()
方法未被调用时,我发现了错字。
不确定通用消息是什么,如果有的话?也许最好使用旧的(pre JavaFX 2.1)样式方法来使控制器实现initialize()
,这样编译器就会捕获错误输入的方法名称。我想如果要调用的后FXML加载方法具有特定的注释(Initializable
或其他东西)会更好。