I have a JavaFX application whose main job is to display different tables containing data loaded from CSV files. I can read CSV files into TableViews with no problems, and export them to CSVs as well. My problem is displaying the different TableViews.
When I load from a CSV into a TableView, I want to save that TableView for future processing. I also want to display a table showing the newly loaded data. My strategy is to have a global TableView, call it table, that is added to the main VBox, and update its contents to contain (and hence display) the elements of whichever TableView I just created by reading a file.
Is this a bad idea? It seems like a simple concept to me, but I can't find a way to easily "clone" the chosen TableView - i.e. transfer its contents to my displayed TableView called table.
My simple attempt at cloning TableViews is shown here. I also tried writing an extensive equateTable() method, which went nowhere.
//WHY DOESN'T THIS WORK?
table.setItems(reqTable.getItems());
Here's the rest of the code. Thanks to anyone who answers!
package FLOOR;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Callback;
// --- Main Class
public class Main extends Application {
// --- All Tables
TableView<ObservableList<StringProperty>> reqTable = new TableView<>();
TableView<ObservableList<StringProperty>> tempTable = new TableView<>();
TableView<ObservableList<StringProperty>> ontTable = new TableView<>();
// --- Display Table
TableView<ObservableList<StringProperty>> table = new TableView<>();
// --- Main
public static void main(String[] args) {
launch(args);
}
// --- Start
@Override
public void start(Stage stage) {
// --- Stage & Scene
stage.setTitle("FLOOR");
Scene scene = new Scene(new VBox(), 900, 500);
MenuBar menuBar = new MenuBar();
// --- VBox
final VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER);
vbox.setSpacing(10);
vbox.setPadding(new Insets(0, 10, 0, 10));
vbox.getChildren().addAll(table);
table.setVisible(false);
// --- Menus
// --- File Menu
// --- Import Submenu
Menu menuFile = new Menu("File");
Menu importMenu = new Menu("Import");
MenuItem reqOption = new MenuItem("Requirements");
MenuItem tempOption = new MenuItem("Templates");
MenuItem ontOption = new MenuItem("Ontologies");
importMenu.getItems().addAll(reqOption, tempOption, ontOption);
//Import Requirements
reqOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Select Requirements CSV");
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
populateTable(reqTable, file.getAbsolutePath());
}
getRequirementsPage();
}
});
//Import Templates
tempOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Select Templates CSV");
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
populateTable(tempTable, file.getAbsolutePath());
}
getTemplatesPage();
}
});
//Import Ontologies
ontOption.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Select Ontology CSV");
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
populateTable(ontTable, file.getAbsolutePath());
}
getOntologiesPage();
}
});
//Export
MenuItem export = new MenuItem("Export");
export.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save Requirements CSV");
File file = fileChooser.showSaveDialog(stage);
if (file != null) {
exportTable(reqTable, file.getAbsolutePath());
}
}
});
//Exit
MenuItem exit = new MenuItem("Exit");
exit.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
System.exit(0);
}
});
menuFile.getItems().addAll(importMenu, export, new SeparatorMenuItem(), exit);
// --- Menu Bar
menuBar.getMenus().addAll(menuFile);
// --- Show FLOOR
((VBox) scene.getRoot()).getChildren().addAll(menuBar, vbox);
stage.setScene(scene);
stage.show();
}
// --- Methods
// Table Getters
private void getRequirementsPage() {
table.getItems().clear();
//WHY DOESN'T THIS WORK?
table.setItems(reqTable.getItems());
table.setVisible(true);
}
private void getTemplatesPage() {
table.getItems().clear();
table.setItems(tempTable.getItems());
table.setVisible(true);
}
private void getOntologiesPage() {
table.getItems().clear();
table.setItems(ontTable.getItems());
table.setVisible(true);
}
//populateTable
private void populateTable(
final TableView<ObservableList<StringProperty>> table,
final String filename) {
table.getItems().clear();
table.getColumns().clear();
table.setPlaceholder(new Label("Loading..."));
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
CSVReader reader = new CSVReader(new FileReader(filename));
String [] nextLine;
int count = 1;
while ((nextLine = reader.readNext()) != null) {
if (count == 1) {
final String[] headers = nextLine;
Platform.runLater(new Runnable() {
@Override
public void run() {
for (int column = 0; column < headers.length; column++) {
table.getColumns().add(
createColumn(column, headers[column]));
}
}
});
} else {
final String[] dataValues = nextLine;
Platform.runLater(new Runnable() {
@Override
public void run() {
// Add additional columns if necessary:
for (int columnIndex = table.getColumns().size(); columnIndex < dataValues.length; columnIndex++) {
table.getColumns().add(createColumn(columnIndex, ""));
}
// Add data to table:
ObservableList<StringProperty> data = FXCollections
.observableArrayList();
for (String value : dataValues) {
data.add(new SimpleStringProperty(value));
}
table.getItems().add(data);
}
});
}
count++;
}
reader.close();
return null;
}
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
}
//exportTable
private void exportTable(
final TableView<ObservableList<StringProperty>> table,
final String filename) {
Task<Void> task = new Task<Void>() {
@Override
protected Void call() throws Exception {
CSVWriter writer = null;
try {
writer = new CSVWriter(new FileWriter(filename), ',');
} catch (IOException e) {
e.printStackTrace();
}
int numRows = table.getItems().size();
int numCols = table.getColumns().size();
String[] dataWrite = new String[numCols];
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
dataWrite[j] = table.getItems().get(i).get(j).getValue();
}
writer.writeNext(dataWrite);
}
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
}
//createColumn
private TableColumn<ObservableList<StringProperty>, String> createColumn(
final int columnIndex, String columnTitle) {
TableColumn<ObservableList<StringProperty>, String> column = new TableColumn<>();
String title;
if (columnTitle == null || columnTitle.trim().length() == 0) {
title = "Column " + (columnIndex + 1);
} else {
title = columnTitle;
}
column.setText(title);
column
.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList<StringProperty>, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(
CellDataFeatures<ObservableList<StringProperty>, String> cellDataFeatures) {
ObservableList<StringProperty> values = cellDataFeatures.getValue();
if (columnIndex >= values.size()) {
return new SimpleStringProperty("");
} else {
return cellDataFeatures.getValue().get(columnIndex);
}
}
});
return column;
}
}