This discussion is archived
4 Replies Latest reply: Dec 11, 2012 12:46 PM by eno g. - oracle RSS

Help with tableview/column strategy

eno g. - oracle Newbie
Currently Being Moderated
I'm greener than a newbie at this so bare with me :)

I somehow had the following scenario working in Swing, but decided to play with JavaFX instead. With that said, here's the scenario:

I have a delimited text files that I want to display on a table. The file may have a different number of columns as below. As you can see some of the fields are empty so I can't just put the fields in a list/array just by splitting the line,
as the values would end up in the wrong columns. Anyhow, I have a class that will figure out what goes where and build a String[] with the correct values and create an object <RowLine> that contains this array.


Column1 Column2 Column3 Column4 Column5
row1 value1 value2 value3 value4 value5
row2 value1 value2 NULL value4 value5
row3 value1 NULL value3 NULL value5


in Swing I was able to just add a new row to the JTable by extracting the Array elements of RowLine object.

In JavaFX I'm confused as to what I should use as an ObservableList<Something> data to display in the table.

Should I create an ObservableList<RowLine> and use that? I'm not sure how I would create the TableColumn and assign it the correct String value from inside the RowLine object?
  • 1. Re: Help with tableview/column strategy
    James_D Guru
    Currently Being Moderated
    In your example, every row has five columns; it's just that some rows have missing values in some of their columns. If this is always true, then it should be pretty easy. Even if not, it's only a little more complex.

    If you have a class (RowLine) that represents a single row (i.e. each row is represented by an instance of that class), then that's good. I'm assuming RowLine has either a method
    public String getValue(int column);
    returning the value for the specified column, or at least a
    public String[] getValues();
    method (so you can call rowline.getValues()[index] to get the same effect).

    So if all these conditions hold, you can make the your table view with RowLine as its data type:
    final TableView<RowLine> table = new TableView<RowLine>();
    and then create the columns:
    final int numCols = 5 ; // or compute it however you need
    for (int colIndex = 0 ; colIndex < numCols ; colIndex++) {
      table.getColumns().add(createColumn(colIndex));
    }
    The createColumn(int index) method can be defined as follows:
    private TableColumn<RowLine, String> createColumn(final int index) {
      TableColumn<RowLine, String> column = new TableColumn<RowLine, String>("Column "+(index+1));
      column.setCellValueFactory(new Callback<CellDataFeatures<RowLine, String>, ObservableValue<String>>() {
        @Override
        public ObservableValue<String> call(CellDataFeatures<RowLine, String> cellDataFeatures) {
          RowLine line = cellDataFeatures.getValue(); // the RowLine instance for a given row
          String value = line.getValue(index); // retrieve the value for this column from the row line
          // String value = line.getValues()[index]; // depending on the methods defined in RowLine
          if (value==null) value = "" ;
          return new SimpleStringProperty(value);
        }
      });
      return column ;
    }
    To populate the table with your data, you presumably have a method which reads your file and creates a List<RowLine> or something similar.
    Then you can do
    List<RowLine> data = readFile();
    table.setItems(FXCollections.observableArrayList(data));
    If you want to add each row to the table as you read it from the file, you can do something like
    BufferedReader in = // create the BufferedReader to read from your file
    String line ;
    while ((line = in.readLine()) !=null) {
      final RowLine rowLine = processLine(line);
      table.getItems().add(rowLine);
    }
    ...
    but you should think a bit about whether you really want to be reading a potentially large file in the JavaFX Application Thread. (I'm assuming a method processLine(String line) here that reads the line and creates the RowLine object from it.) If you execute that loop in an application thread you should replace table.getItems().add(rowLine) with
    Platform.runLater(new Runnable() {
      @Override
      public void run() {
        table.getItems().add(rowLine);
      }
    });
    Now, if your data really does have a variable number of columns, you'll need to add additional columns to the table when you read a line that has more data than the current number of columns. I'll assume RowLine has a getValueCount() method that just returns the size of the String array it wraps, and also that you're reading the file in a separate thread. Then remove the for loop above which calls table.getColumns().add(...) and do this when you read the data:
    BufferedReader in = // create the BufferedReader to read from your file
    String line ;
    while ((line = in.readLine()) !=null) {
      final RowLine rowLine = processLine(line);
      Platform.runLater(new Runnable() {
        @Override
        public void run() {
          for (int index = table.getColumns().size(); index < rowLine.getValueCount(); index++) {
            table.getColumns().add(createColumn(index));
          }
          table.getItems().add(rowLine);
        }
      });
    }
    ...
    In this scenario, you must make sure that RowLine.getValue(int index) returns null if index is greater than or equal to the length of the array of values it wraps (else you'll get ArrayIndexOutOfBoundsExceptions all over the place).

    You could also read the lines into a list, and keep track of the largest line as you do, then build the columns in a simple for loop as before.


    Caveat: this code was not even run through a compiler, so there's likely typos in here which will need fixing; but you did just ask for a strategy :).
  • 2. Re: Help with tableview/column strategy
    eno g. - oracle Newbie
    Currently Being Moderated
    Thanks again sir!

    Yes all of the above were true. I just couldn't figure out how to createColumn and assign value from my Row object.
  • 3. Re: Help with tableview/column strategy
    twasyl Newbie
    Currently Being Moderated
    Hi there,

    I've written a blog post that may be help you: http://thierrywasyl.wordpress.com/2012/11/30/tableview-display-tables-in-javafx/

    Cheers.
  • 4. Re: Help with tableview/column strategy
    eno g. - oracle Newbie
    Currently Being Moderated
    Thanks Thierry, that's useful info!

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points