I have a TableView in my UI, it displays an user list from the database. One of the column of this table is editable, when editing is enabled the cell of this particular column becomes a treeview, listing various options which can be chosen.
Just to clarify, I am trying to implement a Datepicker or a colorpicker like functionality on a table cell, but with my own list of items as a tree.
The table is defined like this
private TableView<User> userTable;
The particular column which displays a tree view is defined like this
private TableColumn<User, TreeView> col4;
I set a setcellFactory method like this to display the tree
col4.setCellFactory(new Callback<TableColumn<User,TreeView>, TableCell<User,TreeView>>() {
@Override
public TableCell<User, TreeView> call(
TableColumn<User, TreeView> param)
{
returns a comboboxtablecell which is filled with a tree
}
});
In the table, in the corresponding column, when I click the cell, the cell shows a combo box and the combobox on opening up shows the tree value.
However when the cell is in non-editable state, I am not sure how I should set the setcellValuefactory with a string value
col4.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<User,TreeView>, ObservableValue<TreeView>>() {
@Override
public ObservableValue<TreeView> call(
CellDataFeatures< User,TreeView> param)
{
}
}
I want to display a value which is inside the treeview as a string when the cell is in a non editable state. I am at a loss as to how to return an observablevalue of type treeview as per the method signature and still display a string.
You need to distinguish between the data that your TableView
(and it's TableColumn
s) is presenting, and the cells that are used to present those data. The cellValueFactory
is an object that determines how to get the value (i.e. data) for a particular column from the value for the entire row. The cellFactory
is an object that determines how to get the cell that presents the data to the user.
Any time you write something like TableColumn<User, TreeView<...>>
it is (almost always) a mistake. The first type in the type parameters is the type of the object in each row of the table - this is fine here - and the second is the type of the data that is displayed. TreeView
is not a data type: it's the type of a UI element, i.e. the type of something that is used to display the data.
So you want something along these lines. (You haven't been too specific in explaining your data model - which is fine - but this might not be quite right; it will give you the idea though.)
TableView<User> userTable ;
TableColumn<User, Options> optionsCol ;
The User
class will have an ObjectProperty<Options>
:
public class User {
private final ObjectProperty<Options> options = new SimpleObjectProperty<>(this, "options", new Options());
public final Options getOptions() {
return options.get();
}
public final void setOptions(Options options) {
this.options.set(options);
}
public ObjectProperty<Options> optionsProperty() {
return options ;
}
// other properties, etc...
}
And obviously this depends on an Options class encapsulating the data displayed in that column:
public class Options {
// properties etc
}
Now you just use the default cell value factory:
optionsCol.setCellValueFactory(new PropertyValueFactory("options"));
(or in JavaFX 8, I prefer
optionsCol.setCellValueFactory((TableColumn.cellDataFeatures<User, Options> data) ->
data.getValue() // this is the User object
.optionsProperty() // this is an ObjectProperty<Options>, which is an ObservableValue<Options>
);
which is somewhat more efficient as it avoids the reflection that the PropertyValueFactory
uses, and is not much more code, especially if you omit the type on the parameter to the lambda expression).
(You don't have to set it up like this. If the Options
are not an intrinsic part of the User
, then you could, for example, have a Map<User, ObjectProperty<Options>>
defined and use that to return the ObjectProperty<Options>
associated with each user. The way I showed is just the most common and probably easiest way.)
I don't really understand where your ComboBox
fits in, but this answer should give you enough to work that in as you need it. The cellFactory
now just has to return a TableCell
that uses a TreeView
to display the Options
object:
optionsCol.setCellFactory( col -> new TableCell<User, Options>() {
private TreeView<...> treeView ;
{
treeView = new TreeView<>(...);
// configure tree view, etc
}
@Override
public void updateItem(Options options, boolean empty) {
super.updateItem(options, empty) ;
if (empty) {
setGraphic(null);
} else {
// configure treeView with data from options, etc
setGraphic(treeView);
}
}
});
You mentioned the cell was editable, so you need to wire up all the editing stuff for the cell too (and you'll probably want to use a named [inner] class as it's going to get a bit verbose, instead of the anonymous inner class I have here). But this should give you the basic structure.