JavaFX更新ComboBox项目列表以根据可更改的输入禁用某些项目

时间:2017-03-13 13:31:55

标签: java javafx combobox

我正在开发预订系统的界面。在一个窗口中,我需要获取预订的开始时间和所需的预订结束时间,以便检查数据库是否有可用的插槽。 (只有......:感兴趣,我在其他地方得到了一天)。 组合框看起来像这样:

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

2 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

并不复杂但不禁用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);
    }
});