表格中的通用(非依赖)组合框选择
此答案基于对 James 对以下问题的回答的修改:
因此,您可以参考该解决方案以获取更多上下文信息。
本例说明
在示例中,我们有第一个下拉菜单,用于选择与指定人员的关系。还有第二个下拉菜单,用于提供给指定人员的礼物。
可用礼物的选择取决于关系,关系越密切,可用礼物的价值越高。
下图显示了在“关系”列中编辑值时可供选择的选项。这些选择是固定的,不会改变:
下图显示了在礼品列中编辑值时可供选择的选项,用于选定的家庭关系:
下图显示了在编辑礼物列中的值时可供选择的选项,用于所选的 ACQUAINTANCE 关系:
工作原理
ComboBoxTableCell 用于生成用于编辑选择的单元工厂。
枚举用于表示关系和礼物的不同选择类型。但是如果你想要一个更动态的设置和更少的静态类型,你可以只使用字符串而不是枚举。
public enum GiftType {
TOY, COFFEE, DINNER, VACATION
}
public enum RelationshipType {
FAMILY, FRIEND, ACQUAINTANCE;
}
关系的选择,只有一个静态的选择列表,使用CombBoxTableCell,不做任何修改:
TableColumn<Contact, Contact.RelationshipType> relationshipCol =
new TableColumn<>("Relationship");
relationshipCol.setCellValueFactory(cellData ->
cellData.getValue().relationshipProperty()
);
relationshipCol.setCellFactory(
ComboBoxTableCell.forTableColumn(
Contact.RelationshipType.values()
)
);
礼物的选择取决于选择的关系,因此需要更多的工作来实现:
TableColumn<Contact, Contact.GiftType> giftCol =
new TableColumn<>("Gift");
giftCol.setCellValueFactory(cellData ->
cellData.getValue().giftProperty()
);
giftCol.setCellFactory(this::giftCellFactory);
giftCellFactory 在哪里:
private TableCell<Contact, Contact.GiftType> giftCellFactory(
TableColumn<Contact, Contact.GiftType> list
) {
return new ComboBoxTableCell<>() {
@Override
public void startEdit() {
getItems().setAll(
getTableRow().getItem().getAvailableGifts()
);
super.startEdit();
}
};
}
礼品单元工厂正在做的是监听礼品单元编辑事件的开始。当编辑开始时,它会更新可供选择的可用礼物值列表,以将它们限制为仅可用于项目的所选关系类型的可用礼物。这样,当编辑 ComboBox 出现时,它只会显示给定关系的有效选择。
关系和礼物的显示只是依靠枚举类型的标准toString值。但是,如果您想自定义值(例如更改大小写,或将所选代码映射到值),则可以将 StringConverter 提供给 constructor of the CombBoxTableCell。
为了让这个功能发挥作用,在模型类(在本例中是一个名为 Contact 的类)中,我们提供了许多工具。
-
我们将所有值表示为具有 getter/setter 和属性访问器的属性。
-
我们为关系属性提供了一个监听器。
在侦听器中,如果关系发生变化并且这将导致该关系类型的礼物值无效,则该联系人的当前礼物设置为 null。
relationshipProperty().addListener((observable, oldValue, newValue) -> {
if (availableGifts.get(newValue) == null || !availableGifts.get(newValue).contains(getGift())) {
setGift(null);
}
});
-
我们提供与可用礼物类型的关系映射。
为了允许为给定联系人选择不礼物,我们在每个可用的礼物选择列表中放置一个空值。如果我们想要一份礼物,而不是让它成为可选项,那么我们就不会在礼物选项列表中提供空值供选择。
对于这个映射,我们有访问器允许:
- 检索任何给定关系类型的所有礼物,以及
- 为此联系人选择的当前关系可用的礼物。
此示例中的映射位于 Contact 模型类中,但如果您愿意,您可以在其他地方管理映射(例如,在单独的数据库关系中)。
private static final Map<RelationshipType, List<GiftType>> availableGifts = Map.of(
RelationshipType.FAMILY, Arrays.asList(null, GiftType.TOY, GiftType.DINNER, GiftType.VACATION),
RelationshipType.FRIEND, Arrays.asList(null, GiftType.TOY, GiftType.COFFEE, GiftType.DINNER),
RelationshipType.ACQUAINTANCE, Arrays.asList(null, GiftType.COFFEE)
);
public static List<GiftType> listAvailableGiftsForRelationshipType(RelationshipType relationshipType) {
return availableGifts.get(relationshipType);
}
public List<GiftType> getAvailableGifts() {
return availableGifts.get(getRelationship());
}
示例代码
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.util.*;
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, Contact.RelationshipType> relationshipCol = new TableColumn<>("Relationship");
relationshipCol.setCellValueFactory(cellData -> cellData.getValue().relationshipProperty());
relationshipCol.setCellFactory(ComboBoxTableCell.forTableColumn(Contact.RelationshipType.values()));
relationshipCol.setPrefWidth(150);
contactTable.getColumns().add(relationshipCol);
TableColumn<Contact, Contact.GiftType> giftCol = new TableColumn<>("Gift");
giftCol.setCellValueFactory(cellData -> cellData.getValue().giftProperty());
giftCol.setCellFactory(this::giftCellFactory);
giftCol.setPrefWidth(120);
contactTable.getColumns().add(giftCol);
contactTable.getItems().addAll(
new Contact("Braxton Walls", Contact.RelationshipType.FAMILY, Contact.GiftType.VACATION),
new Contact("Zainab Berger", Contact.RelationshipType.ACQUAINTANCE, null),
new Contact("Safiyah Hail", Contact.RelationshipType.FRIEND, Contact.GiftType.DINNER),
new Contact("Akbar Storey", Contact.RelationshipType.ACQUAINTANCE, null)
);
contactTable.setPrefSize(400, 200);
Scene scene = new Scene(new BorderPane(contactTable));
primaryStage.setScene(scene);
primaryStage.show();
}
private TableCell<Contact, Contact.GiftType> giftCellFactory(TableColumn<Contact, Contact.GiftType> list) {
return new ComboBoxTableCell<>() {
@Override
public void startEdit() {
getItems().setAll(
getTableRow().getItem().getAvailableGifts()
);
super.startEdit();
}
};
}
public static class Contact {
public enum GiftType {
TOY, COFFEE, DINNER, VACATION
}
public enum RelationshipType {
FAMILY, FRIEND, ACQUAINTANCE;
}
private static final Map<RelationshipType, List<GiftType>> availableGifts = Map.of(
RelationshipType.FAMILY, Arrays.asList(null, GiftType.TOY, GiftType.DINNER, GiftType.VACATION),
RelationshipType.FRIEND, Arrays.asList(null, GiftType.TOY, GiftType.COFFEE, GiftType.DINNER),
RelationshipType.ACQUAINTANCE, Arrays.asList(null, GiftType.COFFEE)
);
private final StringProperty name = new SimpleStringProperty();
private final ObjectProperty<RelationshipType> relationship = new SimpleObjectProperty<>();
private final ObjectProperty<GiftType> gift = new SimpleObjectProperty<>();
public Contact(String name, RelationshipType relationship, GiftType gift) {
setName(name);
setRelationship(relationship);
relationshipProperty().addListener((observable, oldValue, newValue) -> {
if (availableGifts.get(newValue) == null || !availableGifts.get(newValue).contains(getGift())) {
setGift(null);
}
});
setGift(gift);
}
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 ObjectProperty<RelationshipType> relationshipProperty() {
return this.relationship;
}
public final RelationshipType getRelationship() {
return this.relationshipProperty().get();
}
public final void setRelationship(final RelationshipType relationship) {
this.relationshipProperty().set(relationship);
}
public final ObjectProperty<GiftType> giftProperty() {
return this.gift;
}
public final GiftType getGift() {
return this.giftProperty().get();
}
public final void setGift(final GiftType gift) {
this.giftProperty().set(gift);
}
public static List<GiftType> listAvailableGiftsForRelationshipType(RelationshipType relationshipType) {
return availableGifts.get(relationshipType);
}
public List<GiftType> getAvailableGifts() {
return availableGifts.get(getRelationship());
}
}
public static void main(String[] args) {
launch(args);
}
}