首页 > 解决方案 > JavaFX Spinner 在警报后继续旋转

问题描述

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

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

这是我使用以下抽象类实现微调器的方式...

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

...然后由我的具体微调器类扩展,就像这样...

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

}

如果我在这篇文章中包含了比必要更多的代码,我深表歉意。

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

感谢您的任何建议!

2021-01-20 更新:我已将微调器简化为整数微调器。此外,根据下面麦迪逊的建议(感谢麦迪逊!),我尝试将微调器逻辑放入警报的结果函数中。

这样做时,我发现问题似乎是当显示警报时,逻辑的行为就像用户按住递增/递减按钮一样。对递增/递减函数的调用将永远继续。

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

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 上被按住,我想以某种方式将其关闭。当然,我愿意接受有关如何解决此问题的任何其他建议。

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

标签: javafx

解决方案


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

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

为了防止由此产生的无休止的旋转,必须跳过递增/递减逻辑,直到警报关闭并再次单击鼠标递增或递减按钮。

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

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

...并且微调器中的 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);
        }
    }

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


推荐阅读