来自ObservableArrayList的内容被加载(可能)但未显示

时间:2015-05-07 12:31:16

标签: java javafx tableview

我创建了一个小程序,它应该从数据库加载数据并将其显示在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>

1 个答案:

答案 0 :(得分:1)

DatabaseOverviewController中有一个简单的拼写错误:您有intialize()作为方法名称,而不是initialize()。由于FXMLLoader使用反射来搜索名为initialize的方法,并且如果找不到该方法就不执行任何操作,因此您的方法无法调用。修正拼写错误可以解决问题。

对于它的价值,这是我如何理解这一点,因为它很难看到。我和你一样,观察到表中存在正确的行数(你可以选择它们),但是没有显示任何内容。这几乎总是通过没有设置cellValueFactory来调用(或者设置错误,如果你使用PropertyValueFactory就会发生这种情况,但是当你使用你在这里展示的lambdas的好方法时很少发生) 。

由于initialize()方法似乎正确设置了这些,我首先添加了日志记录,Row.itemNumberProperty(),然后当我发现没有调用该方法时(每个{应该调用它)该列中的{1}},TableCell方法本身。当我发现initialize()方法未被调用时,我发现了错字。

不确定通用消息是什么,如果有的话?也许最好使用旧的(pre JavaFX 2.1)样式方法来使控制器实现initialize(),这样编译器就会捕获错误输入的方法名称。我想如果要调用的后FXML加载方法具有特定的注释(Initializable或其他东西)会更好。