Wrap text in JFXTreeTableView cells

1.1k Views Asked by At

How can I wrap the text in JFXTreeTableView cells?

My JFoenix TableTreeView column cell factory is created as shown below.

    // Set column cell factories and width preference
    for (JFXTreeTableColumn<LogEntry, String> column : columnList) {
        column.setCellFactory(param -> 
                new GenericEditableTreeTableCell<>(new TextFieldEditorBuilder()));
        column.setPrefWidth(100);
    }

After hours of searching, I can't figure out how to get the cells in the tree table to wrap text. I even tried to set the wrap text value for every GenericEditableTreeTableCell to true, but I think I'm also supposed to call the setWrappingWidth() method on something. I tried the following block of code, but I ended up getting a NullPointerException.

    // Set column cell factories and width preference
    for (JFXTreeTableColumn<LogEntry, String> column : columnList) {
        column.setCellFactory(param -> {
            GenericEditableTreeTableCell<LogEntry, String> cell =
                  new GenericEditableTreeTableCell<>(new TextFieldEditorBuilder());
            Text text = (Text) cell.getGraphic();
            text.setWrappingWidth(1); //null pointer exception
            cell.setWrapText(true);
            return cell;
        });
        column.setPrefWidth(100);
    }

So, I'm left with the following block of code which runs perfectly fine and displays the table, but the cells do not wrap text.

    // Set column cell factories and width preference
    for (JFXTreeTableColumn<LogEntry, String> column : columnList) {
        column.setCellFactory(param -> {
            GenericEditableTreeTableCell<LogEntry, String> cell =
                  new GenericEditableTreeTableCell<>(new TextFieldEditorBuilder());
            // I think I should call setWrappingWidth() on some object here
            // but I don't know what object
            cell.setWrapText(true);
            return cell;
        });
        column.setPrefWidth(100);
    }

The documentation for setting up a JFXTreeTableView can be found here. It doesn't seem to mention anything about wrapping cell text.

Edit: I tried doing it with CSS, but didn't get any results. In fact, the cell.isWrapText() returned false after using this CSS code - meaning that it didn't event set the value to true. I know the block of CSS is working correctly because I can change every element's text fill color with it.

* {
    -fx-wrap-text: true;
}

Edit 2: Some people said on other semi-related posts that a scroll pane can cause a Node to think it has a much larger width than what is shown to the user. Since a JavaFX TreeTableView uses a scroll bar when the table is too large, I figured I'd try their solutions. I tried setting the preferred width of the cell - still no results.

cell.setWrapText(true);
cell.setPrefWidth(100);
//cell.setMaxWidth(100); doing this too made no difference
//cell.setMinWidth(100); doing this too made no difference

Edit 3: I think I know the problem! It seems that the row height refuses to let the cell wrap text. If I set the rows minimum height to a large enough value, the cell wraps its text! Now I just need to know how to make the row height adjust dynamically to accommodate the cell when it wants to wrap text.

Edit 4: It appears that the row doesn't allow line breaks which may be the cause of the cell failing to wrap text. It can't wrap the text because the new lines it creates are chomped.

1

There are 1 best solutions below

2
On

I have used one of your approaches, but also made custom EditorBuilder which has JFXTextArea instead of JFXTextField.

The custom TextAreaEditorBuilder is the following:

public class TextAreaEditorBuilder  implements EditorNodeBuilder<String> {

private JFXTextArea textArea;

@Override
public void startEdit() {
    Platform.runLater(() -> {
        textArea.selectAll();
    });
}

@Override
public void cancelEdit() {

}

@Override
public void updateItem(String s, boolean isEmpty) {

    Platform.runLater(() -> {
        textArea.selectAll();
        textArea.requestFocus();
    });
}

@Override
public Region createNode(
        String value,
        DoubleBinding minWidthBinding,
        EventHandler<KeyEvent> keyEventsHandler,
        ChangeListener<Boolean> focusChangeListener) {

    StackPane pane = new StackPane();
    pane.setStyle("-fx-padding:-10 0 -10 0");
    textArea = new JFXTextArea(value);
    textArea.setPrefRowCount(4);
    textArea.setWrapText(true);
    textArea.minWidthProperty().bind(minWidthBinding.subtract(10));
    textArea.setOnKeyPressed(keyEventsHandler);
    textArea.focusedProperty().addListener(focusChangeListener);
    pane.getChildren().add(textArea);

    return ControlUtil.styleNodeWithPadding(pane);
}

@Override
public void setValue(String s) {
    textArea.setText(s);
}

@Override
public String getValue() {
    return textArea.getText();
}

@Override
public void validateValue() throws Exception {

}
}

and then the configuration for your column goes something like this:

negativeCasingColumn.setCellFactory(param -> {
        TextAreaEditorBuilder textAreaEditorBuilder = new TextAreaEditorBuilder();
        GenericEditableTreeTableCell<DiagnosticMethodFX, String> cell
                = new GenericEditableTreeTableCell<>(textAreaEditorBuilder);
        cell.setWrapText(true);
        return cell;
    });

So basically I'm wrapping the cell, but making sure I use TextArea as editing field. For me this works just fine, but if you want more elegant solution maybe you can check the cancelEdit() method in GenericEditableTreeTableCell, where it sets the content display to text only: setContentDisplay(ContentDisplay.TEXT_ONLY) which is setting of content property in the abstract class Labeled, where the text wrap is set to false. I didn't dig too deep into it, but some workaround can be made for sure.