2 Replies Latest reply on Nov 11, 2016 9:37 PM by eno g. - oracle

    Creating columns dynamically

    eno g. - oracle

      I'm trying to write an app which contains a table to display data from a file. I want to figure out the number of columns from the data in the file as it may vary. However, it seems like I might have a problem with creating the setter/getter methods for column properties as I wouldn't know before hand how many columns and what they're called so I make use of PropertyValueFactory convenience class as it uses a set string for a parameter.

      Any suggestions?

      Thanks in advance
        • 1. Re: Creating columns dynamically
          You can use a List<> or ObservableList<> as the data type for each row of the table (so table.getItems() will give something like ObservableList<ObservableList<String>>. You won't be able to use a PropertyValueFactory: you will need to set a custom CellValueFactory on the columns to index into the correct column.

          Here's an example which reads a tab-delimited text file and populates the table on the fly. It optionally reads the first line as "header values" (i.e. column titles) and then each row. If a row has more columns than are currently in the table, it adds additional columns. The tab-delimited parsing is not intended to be production-quality (no quoted tabs are supported, etc).

          Enter the URL of a tab-delimited text file and press enter to see it work. (If you have a suitable file on your filesystem, use file:///absolute.path.to.file.txt.)
          import java.io.BufferedReader;
          import java.io.InputStream;
          import java.io.InputStreamReader;
          import java.net.URL;
          import java.net.URLConnection;
          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.scene.Scene;
          import javafx.scene.control.CheckBox;
          import javafx.scene.control.Label;
          import javafx.scene.control.TableColumn;
          import javafx.scene.control.TableView;
          import javafx.scene.control.TextField;
          import javafx.scene.control.TableColumn.CellDataFeatures;
          import javafx.scene.layout.BorderPane;
          import javafx.scene.layout.HBox;
          import javafx.scene.layout.Priority;
          import javafx.stage.Stage;
          import javafx.util.Callback;
          public class DynamicTable extends Application {
            public void start(Stage primaryStage) {
              final BorderPane root = new BorderPane();
              final TableView<ObservableList<StringProperty>> table = new TableView<>();
              final TextField urlTextEntry = new TextField();
              urlTextEntry.setPromptText("Enter URL of tab delimited file");
              final CheckBox headerCheckBox = new CheckBox("Data has header line");
              urlTextEntry.setOnAction(new EventHandler<ActionEvent>() {
                public void handle(ActionEvent event) {
                  populateTable(table, urlTextEntry.getText(),
              HBox controls = new HBox();
              controls.getChildren().addAll(urlTextEntry, headerCheckBox);
              HBox.setHgrow(urlTextEntry, Priority.ALWAYS);
              HBox.setHgrow(headerCheckBox, Priority.NEVER);
              Scene scene = new Scene(root, 600, 400);
            private void populateTable(
                final TableView<ObservableList<StringProperty>> table,
                final String urlSpec, final boolean hasHeader) {
              table.setPlaceholder(new Label("Loading..."));
              Task<Void> task = new Task<Void>() {
                protected Void call() throws Exception {
                  BufferedReader in = getReaderFromUrl(urlSpec);
                  // Header line
                  if (hasHeader) {
                    final String headerLine = in.readLine();
                    final String[] headerValues = headerLine.split("\t");
                    Platform.runLater(new Runnable() {
                      public void run() {
                        for (int column = 0; column < headerValues.length; column++) {
                              createColumn(column, headerValues[column]));
                  // Data:
                  String dataLine;
                  while ((dataLine = in.readLine()) != null) {
                    final String[] dataValues = dataLine.split("\t");
                    Platform.runLater(new Runnable() {
                      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
                        for (String value : dataValues) {
                          data.add(new SimpleStringProperty(value));
                  return null;
              Thread thread = new Thread(task);
            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;
                  .setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList<StringProperty>, String>, ObservableValue<String>>() {
                    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;
            private BufferedReader getReaderFromUrl(String urlSpec) throws Exception {
              URL url = new URL(urlSpec);
              URLConnection connection = url.openConnection();
              InputStream in = connection.getInputStream();
              return new BufferedReader(new InputStreamReader(in));
            public static void main(String[] args) {
          • 2. Re: Creating columns dynamically
            eno g. - oracle
            That's way more than a suggestion! Thank you!!!