I am working with JavaFx 2.2. I am having a problem that I am not able to place different components in a TableView Column. For example I have two columns
1) Answer
2) AnswerType
If AnswerType contains “Multiple Choice” then the corresponding cell in Answer Column should display a ComboBox else it should display a TextField.
I have a code example below but its displaying either ComboBox or TextField but not both in different cells of same column.
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.scene.control.cell.ComboBoxTableCell;
public class TableCellWithMultipleComponent extends Application {
@SuppressWarnings("rawtypes")
TableColumn answerTypeCol;
@SuppressWarnings("rawtypes")
TableColumn answerCol;
ObservableList<String> namesChoiceList;
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void start(final Stage primaryStage) {
primaryStage.setTitle("Table Cell With Multiple Components");
TableView<Person> table = new TableView<Person>();
table.setEditable(true);
final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("A", "Multiple Choice"),
new Person("JOHN", "Free Text"),
new Person("123", "Free Text"),
new Person("D", "Multiple Choice")
);
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(5));
gridpane.setHgap(5);
gridpane.setVgap(5);
namesChoiceList = FXCollections.observableArrayList("A", "B", "C", "D", "INVALID_ANSWER", "NO_ANSWER");
answerCol = new TableColumn();
answerCol.setText("Answers");
answerCol.setMinWidth(210);
answerCol.setEditable(true);
answerCol.setCellValueFactory(new PropertyValueFactory("answers"));
answerCol.setCellFactory( new Callback<TableColumn<String, String>, TableCell<String, String>>() {
@Override
public TableCell<String, String> call(TableColumn<String, String> arg0) {
return new anyMethod();
}
});
answerTypeCol = new TableColumn();
answerTypeCol.setText("Answers Type");
answerTypeCol.setMinWidth(210);
answerTypeCol.setEditable(true);
answerTypeCol.setCellValueFactory(new PropertyValueFactory("answersType"));
table.setItems(data);
table.getColumns().addAll(answerCol, answerTypeCol);
StackPane root = new StackPane();
Scene scene =new Scene(root, 500, 550);
gridpane.add(table, 1, 5,1,20 );
root.getChildren().addAll(gridpane);
primaryStage.setScene(scene);
primaryStage.show();
}
private class anyMethod extends TableCell <String, String>{
@SuppressWarnings("unchecked")
@Override
protected void updateItem(String item, boolean arg1) {
super.updateItem(item, arg1);
answerCol.setCellFactory(ComboBoxTableCell.<String, String>forTableColumn(namesChoiceList));
/**** I have to execute this commented code so that if the column cell has text "Multiple Choice" then
* it displays the comboBox otherwise it displays the text field in the Table View cell
if (item.equalsIgnoreCase("Multiple Choice")){
answerCol.setCellFactory(ComboBoxTableCell.<String, String>forTableColumn(namesChoiceList));
}
else{
//answerCol.setCellFactory(TextFieldTableCell.<String>forTableColumn());
}
****/
}
}
public static class Person {
private final SimpleStringProperty answers;
private final SimpleStringProperty answersType;
private Person(String answers, String answersType) {
this.answers = new SimpleStringProperty(answers);
this.answersType = new SimpleStringProperty(answersType);
}
public String getAnswers() {
return answers.get();
}
public void setAnswers(String answers) {
this.answers.set(answers);
}
public String getAnswersType() {
return answersType.get();
}
public void setAnswersType(String answersType) {
this.answersType.set(answersType);
}
}
}
Here is a sample for an EditingCell which renders a different control in the cell (TextEdit field or Checkbox) depending on the type of data represented by the Cell's backing field (String or Boolean). Complete executable code is available as a gist.
For your particular example, use the same concept except query the type for either a String => TextField or ObservableList => combobox. Also, for your particular sample, ChoiceBox may be a simpler control to use than ComboBox.
class EditingCell extends TableCell<NamedProperty, Object> {
private TextField textField;
private CheckBox checkBox;
public EditingCell() {}
@Override public void startEdit() {
if (!isEmpty()) {
super.startEdit();
if (getItem() instanceof Boolean) {
createCheckBox();
setText(null);
setGraphic(checkBox);
} else {
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
}
@Override public void cancelEdit() {
super.cancelEdit();
if (getItem() instanceof Boolean) {
setText(getItem().toString());
} else {
setText((String) getItem());
}
setGraphic(null);
}
@Override public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (getItem() instanceof Boolean) {
if (checkBox != null) {
checkBox.setSelected(getBoolean());
}
setText(null);
setGraphic(checkBox);
} else {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
}
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (!newValue) {
commitEdit(textField.getText());
}
}
});
}
private void createCheckBox() {
checkBox = new CheckBox();
checkBox.setSelected(getBoolean());
checkBox.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
checkBox.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (!newValue) {
commitEdit(checkBox.isSelected());
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
private Boolean getBoolean() {
return getItem() == null ? false : (Boolean) getItem();
}
}