代码之家  ›  专栏  ›  技术社区  ›  Zephyr

具有自定义CellFactory的Multi-select TableView是否添加到选择?

  •  0
  • Zephyr  · 技术社区  · 7 年前

    我有一个 TableView CellFactory ComboBox 进入其中一列。这个 有 SelectionMode.MULTIPLE

    当用户单击 组合框 .

    我不知道如何做到这一点。

    下面是一个完整的示例来演示该问题:

    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);
            }
        }
    }
    

    该示例从一个可预测的UI开始:

    screenshot 1

    在 制造商 列,则选择相应的行。第一行需要这样做,但与另一行交互时不会取消选择 组合框

    screenshot 2


    如何防止后续与客户的交互 组合框 从…起 到所选行?它的行为应该类似于任何其他单击鼠标的行为 TableRow 难道不是吗?


    注: ComboBoxTableCell 类,但我还没有找到任何正确使用的例子;不过,这与我的问题无关,除非 组合箱表细胞 表现不同。

    0 回复  |  直到 7 年前
        1
  •  2
  •   Slaw    7 年前

    因为您需要一个“始终编辑”单元,所以您的实现应该更像 CheckBoxTableCell ComboBoxTableCell . 前者绕过了数据库的正常编辑机制 TableView

    修改您的 ManufactureTableCell 更像 CheckBoxTableCell

    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())));
    

    如前所述,上述实现绕过了正常的编辑机制;它将价值联系在一起 ComboBox 直接指向模型项的属性。该实现还添加了一个 MOUSE_PRESSED 组合框 根据需要选择行(如果使用单元格选择,则选择单元格)。不幸的是,我不太了解如何在需要时实现选择 是向下的,因此只处理“按”和“快捷方式+按”。

    我相信上面的工作方式是您希望的,但我只能使用JavaFX12进行测试。

    推荐文章