JavaFX Spinner 在 Alert 后继续旋转

JavaFX Spinner keeps spinning after Alert

我有一个关于 JavaFX 微调器的有趣问题 (javafx.scene.control.Spinner)...

对于我的 Spinner,我想在用户首次单击递增或递减按钮时显示“警告”警报。问题在于警报显示得很好,但是一旦显示,微调器就会继续自行 increment/decrement。它会永远“旋转”。

以下是我如何实现微调器的摘要 class...

public abstract class TimeSpinner extends Spinner<LocalTime> {
    protected abstract void displayPopUpOrNot();
    
    @Override
    public void decrement(int steps) {
        displayPopUpOrNot();
        try {
            getValueFactory().setValue(LocalTime.parse(getEditor().getText(), DateTimeFormatter.ofPattern(UtilitiesBean.FORMAT_TIMEONLY_12HR, Locale.ENGLISH)));
            super.decrement(steps);
        }
        catch (DateTimeParseException e) {
            getEditor().setText(UtilitiesBean.INSTANCE.formatLocalTime(LocalTime.now(), UtilitiesBean.FORMAT_TIMEONLY_12HR));
            getValueFactory().setValue(LocalTime.now());
        }
    }
    
    @Override
    public void increment(int steps) {
        displayPopUpOrNot();
        try {
            getValueFactory().setValue(LocalTime.parse(getEditor().getText(), DateTimeFormatter.ofPattern(UtilitiesBean.FORMAT_TIMEONLY_12HR, Locale.ENGLISH)));
            super.increment(steps);
        }
        catch (DateTimeParseException e) {
            getEditor().setText(UtilitiesBean.INSTANCE.formatLocalTime(LocalTime.now(), UtilitiesBean.FORMAT_TIMEONLY_12HR));
            getValueFactory().setValue(LocalTime.now());
        }
    }
    
}

...然后由我的混凝土微调器 classes 扩展,就像这样...

public class Spinner1 extends TimeSpinner {
    private boolean warningDisplayed = false;

    protected void displayPopUpOrNot() {
        if (!warningDisplayed) {
            warningDisplayed = true;
            Alert alert = new Alert(AlertType.WARNING, SPINNER_1_MESSAGE);
            alert.setHeaderText(null);
            alert.showAndWait();
        }
    }

}

“displayPopUpOrNot”方法包含显示警报的代码。它仅在用户首次单击递增或递减微调器按钮时执行,因为之后它会设置 warningDisplayed 标志以防止进一步执行。

我的微调器初始化代码包括以下...

timeSpinner.setValueFactory(new TimeSpinnerValueFactory());

...我的 TimeSpinnerValueFactory 定义如下...

public class TimeSpinnerValueFactory extends SpinnerValueFactory<LocalTime> {
    {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(UtilitiesBean.FORMAT_TIMEONLY_12HR, Locale.ENGLISH);
        setConverter(new LocalTimeStringConverter(formatter, null));
    }
    
    @Override
    public void decrement(int steps) {
        if (getValue() == null)
            setValue(LocalTime.now());
        else {
            try {
                LocalTime time = getValue();
                setValue(time.minusMinutes(steps));
            }
            catch (DateTimeParseException e) {
                setValue(LocalTime.now());
            }
        }
    }

    @Override
    public void increment(int steps) {
        if (this.getValue() == null)
            setValue(LocalTime.now());
        else {
            try {
                LocalTime time = getValue();
                setValue(time.plusMinutes(steps));
            }
            catch (DateTimeParseException e) {
                setValue(LocalTime.now());
            }
        }
    }

}

如果我在此 post.post.

中包含了过多的代码,我们深表歉意

有谁知道为什么在显示警报后微调器继续旋转以及如何防止这种情况发生?如果需要更多信息,请告诉我。

感谢任何建议!

2021-01-20 更新:我已将我的微调器简化为一个整数微调器。此外,我已尝试按照 Madison 的以下建议(感谢 Madison!)将微调器逻辑放入 Alert 的结果函数中。

在这样做的过程中,我发现问题似乎是当显示警报时,逻辑的行为就像用户按住 increment/decrement 按钮一样。对 increment/decrement 函数的调用将永远持续下去。

如果有帮助,这是我的(希望是最小的)微调器逻辑,它应该显示这种行为...

public class IntegerSpinner extends Spinner<Integer> {
    private boolean popupDisplayed = false;
    private boolean popupClosed = false;
    
    @Override
    public void decrement(int steps) {
        System.out.print("Decrement method called. ");
        displayPopUpOrNot(false, steps);
    }
    
    @Override
    public void increment(int steps) {
        System.out.print("Increment method called. ");
        displayPopUpOrNot(true, steps);
    }
    
    private void incrementDecrement(boolean increment, int steps) {
        System.out.print("Popup is now closed. ");
        if (increment) {
            super.increment(steps);
            System.out.println("Increment operation executed.");
        }
        else {
            super.decrement(steps);
            System.out.println("Decrement operation executed");
        }
    }
    
    protected void displayPopUpOrNot(boolean increment, int steps) {
        if (!popupDisplayed) {
            System.out.println("Popup is being prepared for display.");
            popupDisplayed = true;
            Alert alert = new Alert(AlertType.WARNING, "My spinner message");
            alert.setHeaderText(null);
            Optional<ButtonType> option = alert.showAndWait();
            if (option.get() == ButtonType.OK) {
                popupClosed = true;
                incrementDecrement(increment, steps);
            }
        }
        else if (popupClosed) {
            incrementDecrement(increment, steps);
        }
        else {
            System.out.println("Popup is open. Increment/decrement operation skipped.");
        }
    }
    
}

我创建微调器的代码包括以下...

IntegerSpinner integerSpinner = new IntegerSpinner();
integerSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 600, 300));

这是我对这个问题的后续问题 - 有没有办法“以编程方式”关闭 Spinner 的鼠标点击?同样,逻辑表现得好像鼠标被按住在 Spinner 上一样,我想以某种方式将其关闭。当然,对于如何解决这个问题,我愿意接受任何其他建议。

我希望我的问题是有道理的。再次感谢到目前为止所有回复的人!

您可能需要考虑将微调器逻辑放在警报弹出窗口的结果函数中。例如,如果用户按下 OK 然后旋转,否则不旋转。这将允许程序仅在用户关闭警报时旋转。

我设法找到了这个问题的解决方案,我希望分享它以防其他人遇到这个问题。

事实证明,当显示警报以响应单击微调器上的递增或递减按钮时,会处理鼠标单击事件而不是鼠标释放事件。这意味着,实际上,就所涉及的逻辑而言,在显示警报时将鼠标按住 increment/decrement 按钮。

为了防止无限旋转,必须跳过 increment/decrement 逻辑,直到警报关闭并且鼠标再次单击递增或递减按钮。

为此,可以将鼠标处理程序添加到包含以下代码的微调器...

    public void handle(MouseEvent mouseEvent) {
        if (mouseEvent.getButton() == MouseButton.PRIMARY) {
            if (integerSpinner.isPopupClosed()) {
                integerSpinner.setMouseClickedPostPopup(true);
            }
        }
    }

...而spinner中的displayPopUpOrNot方法可以修改如下...

    protected void displayPopUpOrNot(boolean increment, int steps) {
        if (!popupDisplayed) {
            popupDisplayed = true;
            Alert alert = new Alert(AlertType.WARNING, "My spinner message");
            alert.setHeaderText(null);
            Optional<ButtonType> option = alert.showAndWait();
            if (option.get() == ButtonType.OK) {
                popupClosed = true;
            }
        }
        else if (popupClosed && mouseClickedPostPopup) {
            incrementDecrement(increment, steps);
        }
    }

我已经在我原来的应用程序中实现了这个逻辑,现在一切正常。再次感谢之前的建议。