3
votes

My TableView consists of several columns and wraps the text with the following cellfactory:

private void setWrapCellFactory(TableColumn<CustomObject, String> table) {
    table.setCellFactory(tablecol -> {
        TableCell<CustomObject, String> cell = new TableCell<>();
        Text text = new Text();
        cell.setGraphic(text);
        text.wrappingWidthProperty().bind(cell.widthProperty());
        text.textProperty().bind(cell.itemProperty());
        return cell;
    });
}

This works perfectly for showing uneditable text.

The last column has to be editable and could span across several rows (not TableView rows). To prevent the ellips I would like to wrap the new edited text.

After hours of trying I still can't seem to get it working. I have the following code to edit my cell and a non-working attempt to wrap it.

Non-working method to wrap my edited text:

private void setWrapCellFactoryEditable(TableColumn<CustomObject, String> table) {
    table.setCellFactory(tablecol -> {
        TableCell<CustomObject, String> cell = new TextFieldTableCell<>(new DefaultStringConverter());
        Text text = new Text();
        text.setText(text.toString());
        text.wrappingWidthProperty().bind(cell.widthProperty());
        return cell;
    });
}

The following code is the column setup:

feedbackCol.setCellValueFactory(ev -> new ReadOnlyStringWrapper(ev.getValue().getLastFeedback()));
    setWrapCellFactoryEditable(feedbackCol);
    feedbackCol.setOnEditCommit((CellEditEvent<CustomObject, String> ev) -> {
        int id = ((CustomObject) ev.getTableView().getItems().get(
                ev.getTablePosition().getRow())).getId();
        dc.addTempFeedback(id, ev.getNewValue());
    });

For the regular non-editable text I'm using a TableCell, for editable text I'm using a TextFieldTableCell. I don't know why the wrapping isn't working with editable cells.

2

2 Answers

3
votes

You need to create your own class extending TextFieldTableCell. It should override cancelEdit() and updateItem() methods to change cell graphic to Text component (equal to one you used for non-editable cells) when editing is finished.

public class WrappingTextFieldTableCell<S> extends TextFieldTableCell<S, String> {

    private final Text cellText;

    public WrappingTextFieldTableCell() {
        super(new DefaultStringConverter());
        this.cellText = createText();
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setGraphic(cellText);
    }

    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (!isEmpty() && !isEditing()) {
            setGraphic(cellText);
        }
    }

    private Text createText() {
        Text text = new Text();
        text.wrappingWidthProperty().bind(widthProperty());
        text.textProperty().bind(itemProperty());
        return text;
    }
}
1
votes
  public static class TextAreaTableCell<S> extends TextFieldTableCell<S, String> {    
    private final IntFunction<ObservableValue<Boolean>> editableExtractor;
    private TextArea textArea;
    private final Text cellText;

    public TextAreaTableCell(IntFunction<ObservableValue<Boolean>> editableExtractor, StringConverter<String> converter) {
        super(converter);
        this.editableExtractor = editableExtractor;
        this.cellText = createText();
    }

    @Override
    public void updateIndex(int i) {
        super.updateIndex(i);
        if (i == -1)  {
            editableProperty().unbind();
        } else {
            editableProperty().bind(editableExtractor.apply(i));
        }
    }

    public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> forTableColumn(IntFunction<ObservableValue<Boolean>> editableExtractor) {
        return forTableColumn(editableExtractor, new DefaultStringConverter());
    }

    public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> forTableColumn(IntFunction<ObservableValue<Boolean>> editableExtractor, 
            final StringConverter<String> converter) {
        return list -> new TextAreaTableCell<>(editableExtractor, converter);
    }

    private void createTextArea() {
        textArea = new TextArea(getString());
        textArea.setWrapText(true);
        textArea.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
        textArea.focusedProperty().addListener(
                (ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
                    if (!newValue) {
                        commitEdit((String)textArea.getText());
                    }
                });
    }

    private String getString() {
        return getItem() == null ? "" : (String) getItem();
    }




    @Override
    public void startEdit() {
        if (!editableProperty().get()) {
            return;
        }
        if (!isEmpty()) {
            super.startEdit();
            createTextArea();
            setText(null);
            setGraphic(textArea);
            textArea.selectAll();
        }
    }


    @Override
    public void cancelEdit() {
        if (!editableProperty().get()) {
            return;
        }
        super.cancelEdit();
        setText((String) getItem());
        setGraphic(cellText);
    }

    @Override
    public void updateItem(String item, boolean empty) {
        if (!editableProperty().get()) {
            return;
        }
        super.updateItem(item, empty);
        if (empty) {
            setText((String)item);
            setGraphic(null);
        } else {
            if (isEditing()) {
                if (textArea != null) {
                    textArea.setText(getString());
                }
                setText(null);
                setGraphic(textArea);
            } else {
                setText(getString());
                setGraphic(cellText);
            }
        }
    }


     private Text createText() {
        Text text = new Text();
        text.wrappingWidthProperty().bind(widthProperty());
        text.textProperty().bind(itemProperty());
        return text;
    }

}

and use:

colDiagnose.setCellFactory(TextAreaTableCell.forTableColumn(i -> Bindings.valueAt(editable, i).isEqualTo(Boolean.TRUE)));