【问题标题】:JavaFX update a ComboBox item list to disable some items based on a changeable inputJavaFX 更新 ComboBox 项目列表以禁用基于可变输入的某些项目
【发布时间】:2017-03-13 13:31:55
【问题描述】:

我正在开发预订系统的界面。在一个窗口中,我需要获取预订的开始时间和所需预订的结束时间,以便检查数据库是否可用。 (只有 hh:mm 感兴趣,我在其他地方度过了一天)。 组合框如下所示:

//startTime HBox
    HBox startTime = new HBox();
    startTime.setSpacing(5);
    final ComboBox startHours = new ComboBox(hours);
    final ComboBox startMinutes = new ComboBox(minutes);
    final Label colon = new Label(":");
    startTime.getChildren().addAll(startHours,colon,startMinutes);

endTime 也是一样的(一个 HBox 有相同的组件只是改变了变量名

我希望我的 startTime 小时组合框自动禁用那些高于当前 endTime 组合框小时的项目,反之亦然,我希望禁用低于 startTime 小时组合框的 endTime 小时项目。 我尝试制作一个单元格工厂,但是如果我在编辑另一个组合框之前打开组合框,它就不起作用。

startHours.setCellFactory(
    new Callback<ListView<String>, ListCell<String>>() {
            @Override 
            public ListCell<String> call(ListView<String> param) {
                final ListCell<String> cell = new ListCell<String>() {

                    @Override public void updateItem(String item, 
                        boolean empty) {
                            super.updateItem(item, empty);
                            if (item!=null){
                                setText(item);
                            }
                            if ((endHours.getValue()!=null) && (endHours.getValue().toString().compareTo(item)<0)){
                                setDisable(true);
                                setStyle("-fx-background-color: #ffc0cb");
                            }
                        }
            };
            return cell;
        }
    });

【问题讨论】:

    标签: java javafx combobox


    【解决方案1】:

    您的单元格需要观察另一个组合框中的值,以便它知道如果那里的值发生更改则更新其禁用状态。

    请注意,您在单元实现中还有其他错误:您必须在 updateItem() 方法中考虑所有可能性:例如您没有正确处理项目为空(单元格为空),或者在需要时将禁用状态设置回 false。最后,在这里使用字符串作为数据类型既不方便(您可能必须在某些时候转换回 int 才能使用这些值)并且搞乱了逻辑(例如,因为“10”小于“2”)。你应该在这里使用ComboBox&lt;Integer&gt;

    这是一个只有两个“小时”组合框的实现:

    import java.util.function.BiPredicate;
    
    import javafx.application.Application;
    import javafx.beans.value.ObservableValue;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.ComboBox;
    import javafx.scene.control.Label;
    import javafx.scene.control.ListCell;
    import javafx.scene.layout.GridPane;
    import javafx.stage.Stage;
    
    
    public class DependentComboBoxes extends Application {
    
        private ComboBox<Integer> startHours ;
        private ComboBox<Integer> endHours ;
    
        @Override
        public void start(Stage primaryStage) {
            startHours = new ComboBox<>();
            endHours = new ComboBox<>();
            startHours.setCellFactory(lv -> new StartHoursCell());
            endHours.setCellFactory(lv -> new EndHoursCell());
            for (int i = 0; i < 24 ; i++) {
                startHours.getItems().add(i);
                endHours.getItems().add(i);
            }
    
            GridPane root = new GridPane();
            root.setHgap(5);
            root.setVgap(5);
            root.addRow(0, new Label("Start hours:"), startHours);
            root.addRow(1, new Label("End hours:"), endHours);
    
            root.setAlignment(Pos.CENTER);
            root.setPadding(new Insets(20));
            primaryStage.setScene(new Scene(root));
            primaryStage.show();
        }
    
        private class StartHoursCell extends ListCell<Integer> {
    
            StartHoursCell() {
                endHours.valueProperty().addListener((obs, oldEndHours, newEndHours) -> updateDisableState());
            }
    
            @Override
            protected void updateItem(Integer hours, boolean empty) {
                super.updateItem(hours, empty);
                if (empty) {
                    setText(null);
                } else {
                    setText(hours.toString());
                    updateDisableState();
                }
            }
    
            private void updateDisableState() {
                boolean disable = getItem() != null && endHours.getValue() != null && 
                        getItem().intValue() > endHours.getValue();
                setDisable(disable) ;
                setOpacity(disable ? 0.5 : 1);
            }
        }
    
        private class EndHoursCell extends ListCell<Integer> {
    
            EndHoursCell() {
                startHours.valueProperty().addListener((obs, oldEndHours, newEndHours) -> updateDisableState());
            }
    
            @Override
            protected void updateItem(Integer hours, boolean empty) {
                super.updateItem(hours, empty);
                if (empty) {
                    setText(null);
                } else {
                    setText(hours.toString());
                    updateDisableState();
                }
            }
    
            private void updateDisableState() {
                boolean disable = getItem() != null && startHours.getValue() != null && 
                        getItem().intValue() < startHours.getValue();
                setDisable(disable) ;
                setOpacity(disable ? 0.5 : 1);
    
            }
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 非常棒的答案 James_D .. 这对我有很大帮助...与此同时,我在我的“提交”按钮 onAction 事件中进行了一些错误检查,因为我认为这种方式也是复杂。但是,您的回答证明这并不难。只是希望我旁边有人解释听众和事件之间的区别:d 同时,非常感谢
    【解决方案2】:

    不那么复杂但不会禁用 ComboBox 中的项目的方法是将 startHours 单独放置并使用所选值来确定 endHours 中显示的内容。当startHours 值更改时,它将填充endHours 从开始到23 的所有时间。如果已经选择endHours 并且您将startHours 更改为更高的值,它不会显示任何内容并且必须重新选择。 startHours 中的值无需更改,只需更改 endHours 中的值即可。

    ComboBox<Integer> start = new ComboBox<Integer>();
    ComboBox<Integer> end = new ComboBox<Integer>();
    for(int i : IntStream.range(1, 24).toArray()) {
        start.getItems().add(i);
        end.getItems().add(i);
    }
    start.setOnAction(ae -> {
        Integer selected = end.getSelectionModel().getSelectedItem();
        end.getItems().clear();
        for(int i : IntStream.range(start.getSelectionModel().getSelectedItem(), 24).toArray()) {
            end.getItems().add(i);
        }
        if(end.getItems().contains(selected)) {
            end.getSelectionModel().select(selected);
        }
    });
    

    【讨论】:

      猜你喜欢
      • 2012-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 2018-09-06
      • 1970-01-01
      相关资源
      最近更新 更多