javafx:如何以编程方式更改 TableCell 中 ComboBox 的项目?
javafx : how to programmatically change items of ComboBox in TableCell?
如您所见,我有一个 TableView,其中有两列 ComboBoxTableCell。
这些是祖先值
ObservableList<String> ancestors = FXCollections.observableArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
ancestorColumn.setCellFactory(ComboBoxTableCell.forTableColumn(ancestors));
descendantColumn.setCellFactory(ComboBoxTableCell.forTableColumn());
Map<String, List<String>> descendantMap = new HashMap();
descendantMap.put("1", Arrays.asList("A", "B", "C"));
descendantMap.put("2", Arrays.asList("Z", "L", "C"));
descendantMap.put("3", Arrays.asList("A", "B", "R"));
descendantMap.put("4", Arrays.asList("C", "B", "E"));
descendantMap.put("5", Arrays.asList("A", "E", "C"));
descendantMap.put("6", Arrays.asList("M", "V", "T"));
descendantMap.put("7", Arrays.asList("A", "G", "F"));
descendantMap.put("8", Arrays.asList("J", "O", "N"));
descendantMap.put("9", Arrays.asList("X", "G", "E"));
descendantMap.put("10", Arrays.asList("H", "I", "J"));
现在,当我更改祖先组合框的选择时,相应的后代组合框应该填充该键映射中的项目。即,如果我在 table 行上将祖先更改为“1”,则同一行上的后代组合框应该填充 ("A"、"B"、“C”。如何实现这个?
编辑:
嗨,我已经做到了并且有效。但我不确定这样做是否正确。谁能告诉我这样做是否正确?
descendantColumn.setCellFactory(param -> {
return new TableCell() {
ComboBox box = new ComboBox();
@Override
public void updateItem(String item, boolean empty) {
if(!empty) {
setGraphic(box);
ancestorColumn.getCellObservableValue(getIndex()).addListener((o, ov, nv) -> {
if(nv != null) {
box.setItems(descendantMap.get(nv));
}
});
} else {
setGraphic(null);
}
}
};
});
我已经创建了一个示例来说明我将如何做到这一点。但是请注意:我在半小时左右的时间内构建了这个 - 代码远非完美,好吗?
这是完整的代码...
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Do not edit this file it is generated by e(fx)clipse from ../src/application/TableTest.fxgraph
-->
<?import java.lang.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="application.TableTestController">
<center>
<TableView fx:id="tableView">
<columns>
<TableColumn fx:id="tableColumnText" text="Text" prefWidth="150"/>
<TableColumn fx:id="tableColumnFlag" text="Flag" prefWidth="50"/>
<TableColumn fx:id="tableColumnAncestor" text="Ancestor" prefWidth="75"/>
<TableColumn fx:id="tableColumnDescendant" text="Descendant" prefWidth="100"/>
<TableColumn fx:id="tableColumnPoints" text="Points" prefWidth="75"/>
</columns>
<BorderPane.margin>
<Insets top="5" left="5" right="5" bottom="5"/>
</BorderPane.margin>
</TableView>
</center>
</BorderPane>
模型数据class(表示 TableView 中的一行):
package application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class TableTestObject {
private StringProperty text = new SimpleStringProperty("");
private BooleanProperty flag = new SimpleBooleanProperty(false);
private StringProperty ancestor = new SimpleStringProperty("");
private StringProperty descendant = new SimpleStringProperty("");
private IntegerProperty points = new SimpleIntegerProperty(0);
public final StringProperty textProperty() {
return this.text;
}
public final String getText() {
return this.textProperty().get();
}
public final void setText(final String text) {
this.textProperty().set(text);
}
public final BooleanProperty flagProperty() {
return this.flag;
}
public final boolean isFlag() {
return this.flagProperty().get();
}
public final void setFlag(final boolean flag) {
this.flagProperty().set(flag);
}
public final StringProperty ancestorProperty() {
return this.ancestor;
}
public final String getAncestor() {
return this.ancestorProperty().get();
}
public final void setAncestor(final String ancestor) {
this.ancestorProperty().set(ancestor);
}
public final StringProperty descendantProperty() {
return this.descendant;
}
public final String getDescendant() {
return this.descendantProperty().get();
}
public final void setDescendant(final String descendant) {
this.descendantProperty().set(descendant);
}
public final IntegerProperty pointsProperty() {
return this.points;
}
public final int getPoints() {
return this.pointsProperty().get();
}
public final void setPoints(final int points) {
this.pointsProperty().set(points);
}
}
主要class:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("TableTest.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root, 1200, 800);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TableTestController(做绑定的那个):
package application;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class TableTestController {
@FXML
private TableView<TableTestObject> tableView;
@FXML
private TableColumn<TableTestObject, String> tableColumnText;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnFlag;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnAncestor;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnDescendant;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnPoints;
private Map<String, List<String>> descendantMap;
private ObservableList<String> ancestorList;
@FXML
protected void initialize() {
descendantMap = new HashMap<>();
descendantMap.put("1", Arrays.asList("A", "B", "C"));
descendantMap.put("2", Arrays.asList("Z", "L", "C"));
descendantMap.put("3", Arrays.asList("A", "B", "R"));
descendantMap.put("4", Arrays.asList("C", "B", "E"));
descendantMap.put("5", Arrays.asList("A", "E", "C"));
descendantMap.put("6", Arrays.asList("M", "V", "T"));
descendantMap.put("7", Arrays.asList("A", "G", "F"));
descendantMap.put("8", Arrays.asList("J", "O", "N"));
descendantMap.put("9", Arrays.asList("X", "G", "E"));
descendantMap.put("10", Arrays.asList("H", "I", "J"));
ancestorList = FXCollections.observableArrayList(descendantMap.keySet());
ObservableList<TableTestObject> data = FXCollections.observableArrayList();
TableTestObject test = new TableTestObject();
test.setText("Test");
test.setFlag(true);
test.setPoints(1);
data.add(test);
tableView.setItems(data);
tableColumnText.setCellValueFactory(new PropertyValueFactory<>("text"));
tableColumnFlag.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnAncestor.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnDescendant.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnPoints.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnFlag.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
CheckBox cb = new CheckBox();
cb.selectedProperty().bindBidirectional(item.flagProperty());
setGraphic(cb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
tableColumnAncestor.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
ComboBox<String> cb = new ComboBox<>(ancestorList);
cb.getSelectionModel().selectedItemProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
item.ancestorProperty().set(newValue);
System.out.println(item.descendantProperty().get());
});
setGraphic(cb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
tableColumnDescendant.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
ComboBox<String> cb = new ComboBox<>();
item.ancestorProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
item.descendantProperty().set("");
cb.setItems(FXCollections.observableArrayList(descendantMap.get(newValue)));
});
cb.getSelectionModel().selectedItemProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
item.descendantProperty().set(newValue);
System.out.println(item.descendantProperty().get());
});
setGraphic(cb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
tableColumnPoints.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
Spinner<Integer> spinner = new Spinner<>();
spinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(-5, +5, item.getPoints()));
spinner.valueProperty().addListener((ChangeListener<Integer>) (observable, oldValue, newValue) -> {
item.pointsProperty().set(newValue);
System.out.println(item.pointsProperty().get());
});
setGraphic(spinner);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
}
}
再说一次:控制器就是执行绑定的那个。使用 Lambdas,代码几乎是可读的,但无论如何您都应该考虑重新编写它。
干杯,丹尼尔
如您所见,我有一个 TableView,其中有两列 ComboBoxTableCell。
这些是祖先值
ObservableList<String> ancestors = FXCollections.observableArrayList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
ancestorColumn.setCellFactory(ComboBoxTableCell.forTableColumn(ancestors));
descendantColumn.setCellFactory(ComboBoxTableCell.forTableColumn());
Map<String, List<String>> descendantMap = new HashMap();
descendantMap.put("1", Arrays.asList("A", "B", "C"));
descendantMap.put("2", Arrays.asList("Z", "L", "C"));
descendantMap.put("3", Arrays.asList("A", "B", "R"));
descendantMap.put("4", Arrays.asList("C", "B", "E"));
descendantMap.put("5", Arrays.asList("A", "E", "C"));
descendantMap.put("6", Arrays.asList("M", "V", "T"));
descendantMap.put("7", Arrays.asList("A", "G", "F"));
descendantMap.put("8", Arrays.asList("J", "O", "N"));
descendantMap.put("9", Arrays.asList("X", "G", "E"));
descendantMap.put("10", Arrays.asList("H", "I", "J"));
现在,当我更改祖先组合框的选择时,相应的后代组合框应该填充该键映射中的项目。即,如果我在 table 行上将祖先更改为“1”,则同一行上的后代组合框应该填充 ("A"、"B"、“C”。如何实现这个?
编辑: 嗨,我已经做到了并且有效。但我不确定这样做是否正确。谁能告诉我这样做是否正确?
descendantColumn.setCellFactory(param -> {
return new TableCell() {
ComboBox box = new ComboBox();
@Override
public void updateItem(String item, boolean empty) {
if(!empty) {
setGraphic(box);
ancestorColumn.getCellObservableValue(getIndex()).addListener((o, ov, nv) -> {
if(nv != null) {
box.setItems(descendantMap.get(nv));
}
});
} else {
setGraphic(null);
}
}
};
});
我已经创建了一个示例来说明我将如何做到这一点。但是请注意:我在半小时左右的时间内构建了这个 - 代码远非完美,好吗?
这是完整的代码...
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Do not edit this file it is generated by e(fx)clipse from ../src/application/TableTest.fxgraph
-->
<?import java.lang.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="application.TableTestController">
<center>
<TableView fx:id="tableView">
<columns>
<TableColumn fx:id="tableColumnText" text="Text" prefWidth="150"/>
<TableColumn fx:id="tableColumnFlag" text="Flag" prefWidth="50"/>
<TableColumn fx:id="tableColumnAncestor" text="Ancestor" prefWidth="75"/>
<TableColumn fx:id="tableColumnDescendant" text="Descendant" prefWidth="100"/>
<TableColumn fx:id="tableColumnPoints" text="Points" prefWidth="75"/>
</columns>
<BorderPane.margin>
<Insets top="5" left="5" right="5" bottom="5"/>
</BorderPane.margin>
</TableView>
</center>
</BorderPane>
模型数据class(表示 TableView 中的一行):
package application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class TableTestObject {
private StringProperty text = new SimpleStringProperty("");
private BooleanProperty flag = new SimpleBooleanProperty(false);
private StringProperty ancestor = new SimpleStringProperty("");
private StringProperty descendant = new SimpleStringProperty("");
private IntegerProperty points = new SimpleIntegerProperty(0);
public final StringProperty textProperty() {
return this.text;
}
public final String getText() {
return this.textProperty().get();
}
public final void setText(final String text) {
this.textProperty().set(text);
}
public final BooleanProperty flagProperty() {
return this.flag;
}
public final boolean isFlag() {
return this.flagProperty().get();
}
public final void setFlag(final boolean flag) {
this.flagProperty().set(flag);
}
public final StringProperty ancestorProperty() {
return this.ancestor;
}
public final String getAncestor() {
return this.ancestorProperty().get();
}
public final void setAncestor(final String ancestor) {
this.ancestorProperty().set(ancestor);
}
public final StringProperty descendantProperty() {
return this.descendant;
}
public final String getDescendant() {
return this.descendantProperty().get();
}
public final void setDescendant(final String descendant) {
this.descendantProperty().set(descendant);
}
public final IntegerProperty pointsProperty() {
return this.points;
}
public final int getPoints() {
return this.pointsProperty().get();
}
public final void setPoints(final int points) {
this.pointsProperty().set(points);
}
}
主要class:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("TableTest.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root, 1200, 800);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TableTestController(做绑定的那个):
package application;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class TableTestController {
@FXML
private TableView<TableTestObject> tableView;
@FXML
private TableColumn<TableTestObject, String> tableColumnText;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnFlag;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnAncestor;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnDescendant;
@FXML
private TableColumn<TableTestObject, TableTestObject> tableColumnPoints;
private Map<String, List<String>> descendantMap;
private ObservableList<String> ancestorList;
@FXML
protected void initialize() {
descendantMap = new HashMap<>();
descendantMap.put("1", Arrays.asList("A", "B", "C"));
descendantMap.put("2", Arrays.asList("Z", "L", "C"));
descendantMap.put("3", Arrays.asList("A", "B", "R"));
descendantMap.put("4", Arrays.asList("C", "B", "E"));
descendantMap.put("5", Arrays.asList("A", "E", "C"));
descendantMap.put("6", Arrays.asList("M", "V", "T"));
descendantMap.put("7", Arrays.asList("A", "G", "F"));
descendantMap.put("8", Arrays.asList("J", "O", "N"));
descendantMap.put("9", Arrays.asList("X", "G", "E"));
descendantMap.put("10", Arrays.asList("H", "I", "J"));
ancestorList = FXCollections.observableArrayList(descendantMap.keySet());
ObservableList<TableTestObject> data = FXCollections.observableArrayList();
TableTestObject test = new TableTestObject();
test.setText("Test");
test.setFlag(true);
test.setPoints(1);
data.add(test);
tableView.setItems(data);
tableColumnText.setCellValueFactory(new PropertyValueFactory<>("text"));
tableColumnFlag.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnAncestor.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnDescendant.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnPoints.setCellValueFactory(param -> new SimpleObjectProperty<TableTestObject>(param.getValue()));
tableColumnFlag.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
CheckBox cb = new CheckBox();
cb.selectedProperty().bindBidirectional(item.flagProperty());
setGraphic(cb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
tableColumnAncestor.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
ComboBox<String> cb = new ComboBox<>(ancestorList);
cb.getSelectionModel().selectedItemProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
item.ancestorProperty().set(newValue);
System.out.println(item.descendantProperty().get());
});
setGraphic(cb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
tableColumnDescendant.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
ComboBox<String> cb = new ComboBox<>();
item.ancestorProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
item.descendantProperty().set("");
cb.setItems(FXCollections.observableArrayList(descendantMap.get(newValue)));
});
cb.getSelectionModel().selectedItemProperty().addListener((ChangeListener<String>) (observable, oldValue, newValue) -> {
item.descendantProperty().set(newValue);
System.out.println(item.descendantProperty().get());
});
setGraphic(cb);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
tableColumnPoints.setCellFactory(param -> new TableCell<TableTestObject, TableTestObject>() {
@Override
protected void updateItem(TableTestObject item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
Spinner<Integer> spinner = new Spinner<>();
spinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(-5, +5, item.getPoints()));
spinner.valueProperty().addListener((ChangeListener<Integer>) (observable, oldValue, newValue) -> {
item.pointsProperty().set(newValue);
System.out.println(item.pointsProperty().get());
});
setGraphic(spinner);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
});
}
}
再说一次:控制器就是执行绑定的那个。使用 Lambdas,代码几乎是可读的,但无论如何您都应该考虑重新编写它。
干杯,丹尼尔