Skip to content

Instantly share code, notes, and snippets.

@opensourcelib
Forked from eckig/TextAreaTableCell.java
Created September 13, 2016 13:54
Show Gist options
  • Save opensourcelib/6d9446787322397d993debe9682bc513 to your computer and use it in GitHub Desktop.
Save opensourcelib/6d9446787322397d993debe9682bc513 to your computer and use it in GitHub Desktop.
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Cell;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.util.Callback;
import javafx.util.StringConverter;
import javafx.util.converter.DefaultStringConverter;
public class TextAreaTableCell<S, T> extends TableCell<S, T> {
public static <S> Callback<TableColumn<S, String>, TableCell<S, String>> forTableColumn() {
return forTableColumn(new DefaultStringConverter());
}
public static <S, T> Callback<TableColumn<S, T>, TableCell<S, T>> forTableColumn(final StringConverter<T> converter) {
return list -> new TextAreaTableCell<>(converter);
}
private static <T> String getItemText(Cell<T> cell, StringConverter<T> converter) {
return converter == null ? cell.getItem() == null ? "" : cell.getItem()
.toString() : converter.toString(cell.getItem());
}
private static <T> TextArea createTextArea(final Cell<T> cell, final StringConverter<T> converter) {
TextArea textArea = new TextArea(getItemText(cell, converter));
textArea.setOnKeyReleased(t -> {
if (t.getCode() == KeyCode.ESCAPE) {
cell.cancelEdit();
t.consume();
}
else if(t.getCode() == KeyCode.ENTER && t.isShiftDown()) {
if (converter == null) {
throw new IllegalStateException(
"Attempting to convert text input into Object, but provided "
+ "StringConverter is null. Be sure to set a StringConverter "
+ "in your cell factory.");
}
cell.commitEdit(converter.fromString(textArea.getText()));
t.consume();
}
});
textArea.prefRowCountProperty().bind(Bindings.size(textArea.getParagraphs()));
return textArea;
}
private void startEdit(final Cell<T> cell, final StringConverter<T> converter) {
textArea.setText(getItemText(cell, converter));
cell.setText(null);
cell.setGraphic(textArea);
textArea.selectAll();
textArea.requestFocus();
}
private static <T> void cancelEdit(Cell<T> cell, final StringConverter<T> converter) {
cell.setText(getItemText(cell, converter));
cell.setGraphic(null);
}
private void updateItem(final Cell<T> cell, final StringConverter<T> converter) {
if (cell.isEmpty()) {
cell.setText(null);
cell.setGraphic(null);
} else {
if (cell.isEditing()) {
if (textArea != null) {
textArea.setText(getItemText(cell, converter));
}
cell.setText(null);
cell.setGraphic(textArea);
} else {
cell.setText(getItemText(cell, converter));
cell.setGraphic(null);
}
}
}
private TextArea textArea;
private ObjectProperty<StringConverter<T>> converter = new SimpleObjectProperty<>(this, "converter");
public TextAreaTableCell() {
this(null);
}
public TextAreaTableCell(StringConverter<T> converter) {
this.getStyleClass().add("text-area-table-cell");
setConverter(converter);
}
public final ObjectProperty<StringConverter<T>> converterProperty() {
return converter;
}
public final void setConverter(StringConverter<T> value) {
converterProperty().set(value);
}
public final StringConverter<T> getConverter() {
return converterProperty().get();
}
@Override
public void startEdit() {
if (!isEditable() || !getTableView().isEditable() || !getTableColumn().isEditable()) {
return;
}
super.startEdit();
if (isEditing()) {
if (textArea == null) {
textArea = createTextArea(this, getConverter());
}
startEdit(this, getConverter());
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
cancelEdit(this, getConverter());
}
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
updateItem(this, getConverter());
}
}
@opensourcelib
Copy link
Author

StackOverFlow Question

Ok, the basic idea is to copy the TextFieldTableColumn and adjust its behavior to create a TextAreaTableColumn. I hacked a small working example implementation together: https://gist.github.com/eckig/30abf0d7d51b7756c2e7

Usage:

TableColumn column = new TableColumn<>();
column.setCellValueFactory(...);
column.setCellFactory(TextAreaTableCell.forTableColumn()); // add StringConverter if neccessary
tableView.getColumns().add(column);

Adjust prefRowCount to show only the necessary amount of rows.
Maybe adjust prefColumnCount?
But hopefully you get the idea ;-)

Commit is now done by Shift+Enter. On focus lost is not a good idea, so I discarded it. Additionally I found a solution for the row count property. It is not working 100% perfect, but it is a good start for now. – eckig Dec 28 '14 at 9:27

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment