I'm trying to a add a Combo Box
to my Table View
:
Basically I have a class called TableViewTest that stores a name and a description, I can display theses names and descriptions in a Table View
no bother, but what I want to do is add a third column with each cell having a Combo Box
so that the user can select one from a number of options for each person.
So far I have created an ObservableList
of type String
with some values and added them to a ComboBox
object. Does anyone know a way for me to add this Combo Box
to the table?
Also bear in mind this code is pretty rough and I'm just trying to get something working and I'll be refactoring the code at a later date.
ObservableList<TableViewTest> products = FXCollections.observableArrayList();
for(int i = 0; i < b.length; i++){
// random String values
products.add(new TableViewTest(b[i], a[i]));
}
ObservableList<String> options = FXCollections.observableArrayList(
"1",
"2",
"3"
);
final ComboBox comboBox = new ComboBox(options);
TableColumn<TableViewTest, String> nameColumn = new TableColumn<> ("Name");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<TableViewTest, String>("name"));
//price Column
//Stock Column
TableColumn<TableViewTest, String> StockColumn = new TableColumn<> ("Stock");
StockColumn.setMinWidth(150);
StockColumn.setCellValueFactory(new PropertyValueFactory<TableViewTest, String>("description"));
TableColumn<Object,ComboBox> PriceColumn;
PriceColumn = new TableColumn<>("Source");
PriceColumn.setMinWidth(150);
//PriceColumn.setCellValueFactory(new PropertyValueFactory<>
//(options));
//PriceColumn.setCellFactory(ComboBoxTableCell.forTableColumn(new
//DefaultStringConverter(), options));
//PriceColumn.setCellFactory(ComboBoxTableCell.forTableColumn(
//comboBox));
TableView<TableViewTest> table = new TableView<>();
table.setItems(products);
table.getColumns().addAll(nameColumn, StockColumn, PriceColumn);
James_D's answer works well, but requires the user to click on the item to see the ComboBox
. If you want to have ComboBox
es in a column, that are always shown, you have to use a custom cellFactory
:
public class TableViewTest {
...
private final StringProperty option = new SimpleStringProperty();
public String getOption() {
return option.get();
}
public void setOption(String value) {
option.set(value);
}
public StringProperty optionProperty() {
return option;
}
}
TableColumn<TableViewTest, StringProperty> column = new TableColumn<>("option");
column.setCellValueFactory(i -> {
final StringProperty value = i.getValue().optionProperty();
// binding to constant value
return Bindings.createObjectBinding(() -> value);
});
column.setCellFactory(col -> {
TableCell<TableViewTest, StringProperty> c = new TableCell<>();
final ComboBox<String> comboBox = new ComboBox<>(options);
c.itemProperty().addListener((observable, oldValue, newValue) -> {
if (oldValue != null) {
comboBox.valueProperty().unbindBidirectional(oldValue);
}
if (newValue != null) {
comboBox.valueProperty().bindBidirectional(newValue);
}
});
c.graphicProperty().bind(Bindings.when(c.emptyProperty()).then((Node) null).otherwise(comboBox));
return c;
});
The types for your table column are always the type of the item in each row (i.e. the same as the type you use for the table view) for the first type parameter, and the type of the (current) value for each cell in the column for the second parameter. So if your table view has type TableViewTest
, and your combo box is selecting String
s, you should have:
TableColumn<TableViewTest, String> priceColumn ;
The cell value factory should still map to a property in the TableViewTest
class, i.e. assuming you have:
public class TableViewTest {
// ...
public StringProperty priceProperty() {
// ...
}
// ...
}
then you can do:
priceColumn.setCellValueFactory(new PropertyValueFactory<>("price"));
or (much better):
priceColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
Then you can just do:
priceColumn.setCellFactory(ComboBoxTableCell.forTableColumn(options));
Here's a SSCCE:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TableWithComboBoxExample extends Application {
@Override
public void start(Stage primaryStage) {
TableView<Contact> contactTable = new TableView<>();
contactTable.setEditable(true);
TableColumn<Contact, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
nameCol.setCellFactory(TextFieldTableCell.forTableColumn());
contactTable.getColumns().add(nameCol);
TableColumn<Contact, String> categoryCol = new TableColumn<>("Category");
categoryCol.setCellValueFactory(cellData -> cellData.getValue().categoryProperty());
categoryCol.setCellFactory(ComboBoxTableCell.forTableColumn("Friends", "Family", "Work Contacts"));
contactTable.getColumns().add(categoryCol);
contactTable.getItems().addAll(
new Contact("Bill Gates", "Work Contacts"),
new Contact("Barack Obama", "Friends"),
new Contact("Tim Cook", "Work Contacts")
);
Scene scene = new Scene(new BorderPane(contactTable), 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Contact {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty category = new SimpleStringProperty();
public Contact(String name, String category) {
setName(name);
setCategory(category);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final StringProperty categoryProperty() {
return this.category;
}
public final String getCategory() {
return this.categoryProperty().get();
}
public final void setCategory(final String category) {
this.categoryProperty().set(category);
}
}
public static void main(String[] args) {
launch(args);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With