Knut Arne Vedaa February 2016

JavaFX TableView: copy text as rendered in cell

I want to implement copy functionality in a TableView. The text to be copied should be the actual text that is rendered in the cell, not the .toString version of the data model to be rendered, that is, it should be the .getText of the cell.

There are several ways of getting the data from a cell. However to get the rendered cell text contents, the procedure seems to be like this:

  • Get the cell data.
  • Get the cell factory.
  • Use the factory to create a cell.
  • Use the cell's updateItem method to render the data, then getText to get the rendered text.

The last step is not possible due to updateItem being protected.

How can I access the rendered text of any given cell in a TableView?

Answers


James_D February 2016

The process you outline involves getting the text (i.e. data) from the view (the cell), which violates the principles behind the MVC/MVP design. From a practical perspective, it involves creating UI elements (which are expensive to create) to essentially manipulate data (which is typically much less expensive to create and process). Additionally, depending on exactly what you're doing, the UI elements may impose additional threading constraints on your code (as they are essentially single-threaded).

If you need to use the "formatting text" functionality outside of the cell, you should factor it out elsewhere and reuse it in both the "copy" functionality you need and in the cell. At a minimum, this could be done by making the "format text" functionality part of the cell factory:

import java.util.function.Function;

import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

public class FormattingTableCellFactory<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> {

    private final Function<T, String> formatter ;

    public FormattingTableCellFactory(Function<T, String> formatter) {
        this.formatter = formatter ;
    }

    public FormattingTableCellFactory() {
        this(T::toString);
    }

    public final Function<T, String> getFormatter() {
        return formatter ;
    }

    @Override
    public TableCell<S,T> call(TableColumn<S,T> col) {
        return new TableCell<S,T>() {
            @Override
            protected void updateItem(T item, boolean empty) {
                super.updateItem(item, empty);
                setText(item == null ? null : formatter.apply(item));
            }
        };
    }
}

(Obviously you could extend this to produce more sophisticated cells with graphical content, etc.)

And now your copy functionality can simply apply the formatter to the data,

Post Status

Asked in February 2016
Viewed 2,026 times
Voted 12
Answered 1 times

Search




Leave an answer