Javafx 与自定义CellFactory节点交互是否将行添加到TableView选择列表?
我有一个Javafx 与自定义CellFactory节点交互是否将行添加到TableView选择列表?,javafx,Javafx,我有一个TableView和一个CellFactory,它将一个组合框放在其中一列中。TableView具有SelectionMode。启用了多个,但它在组合框单元格中的行为异常 当用户单击组合框选择一个值时,该行将添加到所选行的列表中。相反,单击组合框应该选择该行并取消选择所有其他行(除非按住CTRL键),或者根本不选择该行,而只允许与组合框交互 我不知道如何做到这一点 下面是一个完整的示例来演示该问题: import javafx.application.Application; impor
TableView
和一个CellFactory
,它将一个组合框
放在其中一列中。TableView
具有SelectionMode。启用了多个
,但它在组合框单元格中的行为异常
当用户单击组合框选择一个值时,该行将添加到所选行的列表中。相反,单击组合框
应该选择该行并取消选择所有其他行(除非按住CTRL键),或者根本不选择该行,而只允许与组合框
交互
我不知道如何做到这一点
下面是一个完整的示例来演示该问题:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
enum Manufacturer {
HP, DELL, LENOVO, ASUS, ACER;
}
public class TableViewSelectionIssue extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Simple TableView
TableView<ComputerPart> tableView = new TableView<>();
TableColumn<ComputerPart, Manufacturer> colManufacturer = new TableColumn<>("Manufacturer");
TableColumn<ComputerPart, String> colItem = new TableColumn<>("Item");
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
colManufacturer.setCellValueFactory(t -> t.getValue().manufacturerProperty());
colItem.setCellValueFactory(t -> t.getValue().itemNameProperty());
tableView.getColumns().addAll(colManufacturer, colItem);
// CellFactory to display ComboBox in colManufacturer
colManufacturer.setCellFactory(param -> new ManufacturerTableCell(colManufacturer, FXCollections.observableArrayList(Manufacturer.values())));
// Add sample items
tableView.getItems().addAll(
new ComputerPart("Keyboard"),
new ComputerPart("Mouse"),
new ComputerPart("Monitor"),
new ComputerPart("Motherboard"),
new ComputerPart("Hard Drive")
);
root.getChildren().add(tableView);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
}
class ComputerPart {
private final ObjectProperty<Manufacturer> manufacturer = new SimpleObjectProperty<>();
private final StringProperty itemName = new SimpleStringProperty();
public ComputerPart(String itemName) {
this.itemName.set(itemName);
}
public Manufacturer getManufacturer() {
return manufacturer.get();
}
public void setManufacturer(Manufacturer manufacturer) {
this.manufacturer.set(manufacturer);
}
public ObjectProperty<Manufacturer> manufacturerProperty() {
return manufacturer;
}
public String getItemName() {
return itemName.get();
}
public void setItemName(String itemName) {
this.itemName.set(itemName);
}
public StringProperty itemNameProperty() {
return itemName;
}
}
class ManufacturerTableCell extends TableCell<ComputerPart, Manufacturer> {
private final ComboBox<Manufacturer> cboStatus;
ManufacturerTableCell(TableColumn<ComputerPart, Manufacturer> column, ObservableList<Manufacturer> items) {
this.cboStatus = new ComboBox<>();
this.cboStatus.setItems(items);
this.cboStatus.setConverter(new StringConverter<Manufacturer>() {
@Override
public String toString(Manufacturer object) {
return object.name();
}
@Override
public Manufacturer fromString(String string) {
return null;
}
});
this.cboStatus.disableProperty().bind(column.editableProperty().not());
this.cboStatus.setOnShowing(event -> {
final TableView<ComputerPart> tableView = getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column);
});
this.cboStatus.valueProperty().addListener((observable, oldValue, newValue) -> {
if (isEditing()) {
commitEdit(newValue);
column.getTableView().refresh();
}
});
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
protected void updateItem(Manufacturer item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (empty) {
setGraphic(null);
} else {
this.cboStatus.setValue(item);
this.setGraphic(this.cboStatus);
}
}
}
导入javafx.application.application;
导入javafx.beans.property.ObjectProperty;
导入javafx.beans.property.SimpleObject属性;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.*;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
导入javafx.util.StringConverter;
枚举制造商{
惠普、戴尔、联想、华硕、宏碁;
}
公共类TableViewSelectionSue扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
//简单接口
VBox根=新的VBox(10);
根部设置对齐(位置中心);
根。设置填充(新插图(10));
//简单桌面视图
TableView TableView=新建TableView();
TableColumn colManufacturer=新的TableColumn(“制造商”);
TableColumn colItem=新的TableColumn(“项目”);
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
colManufacturer.setCellValueFactory(t->t.getValue().manufacturerProperty());
colItem.setCellValueFactory(t->t.getValue().itemNameProperty());
tableView.getColumns().addAll(colManufacturer,colItem);
//CellFactory在colManufacturer中显示组合框
colManufacturer.setCellFactory(参数->新建ManufacturerTableCell(colManufacturer,FXCollections.observableArrayList(Manufacturer.values()));
//添加示例项
tableView.getItems().addAll(
新电脑零件(“键盘”),
新电脑零件(“鼠标”),
新电脑零件(“显示器”),
新计算机部件(“主板”),
新计算机部件(“硬盘驱动器”)
);
root.getChildren().add(tableView);
//上台
primaryStage.setScene(新场景(根));
初级阶段。设置标题(“样本”);
primaryStage.show();
}
}
类计算机部件{
私有最终ObjectProperty制造商=新的SimpleObjectProperty();
private final StringProperty itemName=新SimpleStringProperty();
公共计算机部件(字符串项名称){
this.itemName.set(itemName);
}
公共制造商getManufacturer(){
返回manufacturer.get();
}
公共制造商(制造商){
此.manufacturer.set(制造商);
}
公共对象属性manufacturerProperty(){
退货制造商;
}
公共字符串getItemName(){
返回itemName.get();
}
public void setItemName(字符串itemName){
this.itemName.set(itemName);
}
公共StringProperty itemNameProperty(){
返回itemName;
}
}
类ManufacturerTableCell扩展了TableCell{
专用最终组合框cboStatus;
ManufacturerTableCell(表列、可观察列表项){
this.cboStatus=新组合框();
此.cboStatus.setItems(项目);
this.cboStatus.setConverter(新的StringConverter(){
@凌驾
公共字符串toString(制造商对象){
返回object.name();
}
@凌驾
公共制造商fromString(字符串){
返回null;
}
});
this.cboStatus.disableProperty().bind(column.editableProperty().not());
this.cboStatus.setOnShowing(事件->{
final TableView TableView=getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
编辑(tableView.getSelectionModel().getSelectedIndex(),列);
});
this.cboStatus.valueProperty().addListener((可观察、旧值、新值)->{
if(isEditing()){
承诺IT(新价值);
column.getTableView().refresh();
}
});
setContentDisplay(仅限ContentDisplay.GRAPHIC_);
}
@凌驾
受保护的无效更新项(制造商项,布尔值为空){
super.updateItem(项,空);
setText(空);
if(空){
设置图形(空);
}否则{
此.cboStatus.setValue(项);
这个.setGraphic(这个.cboStatus);
}
}
}
该示例从一个可预测的UI开始: 但是,当与制造商列中的
组合框
交互时,会选择相应的行。第一行需要这样做,但与另一个组合框
交互时不会取消选择
如何防止与组合框的后续交互
将添加到所选行?它的行为应该类似于在表格行上的任何其他单击,不是吗
我使用的是JDK 8u161
注意:我知道有一个ComboBoxTableCell
类可用,但我还没有找到任何关于如何使用一个道具的示例
class ManufacturerTableCell extends TableCell<ComputerPart, Manufacturer> {
private final ComboBox<Manufacturer> cboStatus;
private final IntFunction<Property<Manufacturer>> extractor;
private Property<Manufacturer> property;
ManufacturerTableCell(IntFunction<Property<Manufacturer>> extractor, ObservableList<Manufacturer> items) {
this.extractor = extractor;
this.cboStatus = new ComboBox<>();
this.cboStatus.setItems(items);
// removed StringConverter for brevity (accidentally)
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
cboStatus.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
if (event.isShortcutDown()) {
getTableView().getSelectionModel().select(getIndex(), getTableColumn());
} else {
getTableView().getSelectionModel().clearAndSelect(getIndex(), getTableColumn());
}
event.consume();
});
}
@Override
protected void updateItem(Manufacturer item, boolean empty) {
super.updateItem(item, empty);
setText(null);
clearProperty();
if (empty) {
setGraphic(null);
} else {
property = extractor.apply(getIndex());
Bindings.bindBidirectional(cboStatus.valueProperty(), property);
setGraphic(cboStatus);
}
}
private void clearProperty() {
setGraphic(null);
if (property != null) {
Bindings.unbindBidirectional(cboStatus.valueProperty(), property);
}
}
}
// note you could probably share the same ObservableList between all cells
colManufacturer.setCellFactory(param ->
new ManufacturerTableCell(i -> tableView.getItems().get(i).manufacturerProperty(),
FXCollections.observableArrayList(Manufacturer.values())));