2015-03-08

CSV ファイルを読み込んで JavaFX の TableView に表示する(改)

CSV ファイルを読み込んで TableView に表示させるサンプルを前回紹介しましたが、サンプルの完成度が低かったので、手直しをしたものを掲載しました。

動作環境は次の通りです。

  • OS: WIndows 8.1 (64bit)
  • Java: Java SE 1.8.0_40-b25
  • IDE: NetBeans IDE 8.0.2
リスト:TableViewSample.java 
package tableviewsample;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TableViewSample extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    ObservableList<String> headers = FXCollections.observableArrayList();
    ObservableList<ObservableList> data = FXCollections.observableArrayList();

    TableView<ObservableList> table;

    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group(), 600, 400);
        stage.setTitle("CSV Read Sample");

        MenuBar menuBar = new MenuBar();
        generateMenu(menuBar, stage);

        table = new TableView();

        VBox vbox = new VBox();
        vbox.getChildren().addAll(menuBar, table);
        vbox.prefWidthProperty().bind(scene.widthProperty());
        vbox.prefHeightProperty().bind(scene.heightProperty());
        table.prefHeightProperty().bind(vbox.heightProperty());
        ((Group) scene.getRoot()).getChildren().addAll(vbox);

        stage.setScene(scene);
        stage.show();
    }

    private void generateMenu(MenuBar menuBar, Stage stage) {
        // Menu File
        Menu menuFile = new Menu("File");
        menuBar.getMenus().addAll(menuFile);

        // MenuItem Exit
        MenuItem open = new MenuItem("Open");
        open.setOnAction((ActionEvent t) -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Open CSV File");
            fileChooser.getExtensionFilters().addAll(
                    new FileChooser.ExtensionFilter("CSV", "*.csv"),
                    new FileChooser.ExtensionFilter("All", "*.*")
            );
            
            File file = fileChooser.showOpenDialog(stage);
            if (file != null) {
                readCSV(file);
                open.setDisable(true);
            }
        });

        // MenuItem Exit
        MenuItem exit = new MenuItem("Exit");
        exit.setOnAction((ActionEvent t) -> {
            System.exit(0);
        });

        menuFile.getItems().addAll(open, new SeparatorMenuItem(), exit);
    }

    void readCSV(File file) {
        try {
            if (checkBeforeReadfile(file)) {
                FileInputStream in = new FileInputStream(file);
//                InputStreamReader sr = new InputStreamReader(in, "UTF-8");
                InputStreamReader sr = new InputStreamReader(in, "Shift_JIS");
                BufferedReader br = new BufferedReader(sr);

                String line;
                boolean isHeader = true;
                while ((line = br.readLine()) != null) {
                    StringTokenizer token = new StringTokenizer(line, ",");
                    ObservableList<String> lineList = FXCollections.observableArrayList();

                    if (isHeader) {
                        while (token.hasMoreTokens()) {
                            headers.add(token.nextToken());
                        }
                        isHeader = false;
                    } else {
                        while (token.hasMoreTokens()) {
                            lineList.add(token.nextToken());
                        }
                        data.add(lineList);
                    }
                }
            } else {
                System.out.println("No file exists or can't open.");
            }
        } catch (FileNotFoundException e) {
            System.out.println("FileNotFoundException : " + e.getMessage());
        } catch (IOException e) {
            System.out.println("IOException : " + e.getMessage());
        }

        generateTable();

    }

    private void generateTable() {
        int idx = 0;
        TableColumn[] column = new TableColumn[headers.size()];
        for (String colName : headers) {
            column[idx] = new TableColumn(colName);
            column[idx].setCellValueFactory(new SetCellProperty(idx));
            idx++;
        }
        table.getColumns().addAll(column);

        table.setItems(data); // finally add data to tableview
    }

    boolean checkBeforeReadfile(File file) {
        if (file.exists()) {
            if (file.isFile() && file.canRead()) {
                return true;
            }
        }
        return false;
    }

    private static class SetCellProperty implements Callback<CellDataFeatures<ObservableList, String>, ObservableValue<String>> {

        private final int i;

        public SetCellProperty(int i) {
            this.i = i;
        }

        @Override
        public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
            return new SimpleStringProperty(param.getValue().get(i).toString());
        }
    }
}

実行例を以下に示しました。郵便番号データダウンロード 住所の郵便番号(ローマ字) zip形式 - 日本郵便 からダウンロードした CSV ファイルにヘッダー情報をつけるなどの加工をしておいて読み込んでみました。

参考サイト

  1. Updated: Dynamic TableView Data From Database « Java and FX

 

0 件のコメント: