JavaFX: заполнить таблицу, используя карту

Я начинаю изучать 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, чтобы при выборе базы данных данные заполняли табличное представление.

1 ответ

Решение

Вы создаете TableView в инициализаторе класса контроллера. это TableView заполнен данными, но экземпляр никогда не будет отображаться в сцене, так как FXMLLoader создает тот из fxml.

Сделайте инициализацию, как это в initialize() метод. Этот метод управляется FXMLLoader после того, как все объекты были введены, делая tableView экземпляр отображается на экране доступны.

Дополнительные примечания:

  • Вы передаете key который всегда 1 к стоимости завода. Вместо этого вы должны использовать i,
  • Вы запрашиваете БД для каждого столбца, всегда выбирая каждую строку в таблице. Это очень неэффективно. Просто выполните запрос один раз. Попробуйте использовать результат для инициализации строк и столбцов.
  • Рассмотрим разделение доступа к данным и просмотра. Это можно сделать, передав данные в контроллер, см. Раздел "Передача параметров 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 больше.

Другие вопросы по тегам