JavaFX Spinner禁用空编辑器上的按钮

问题描述 投票:0回答:2

好吧,继承我的情况。当编辑器为空时,我需要禁用两个微调按钮,这是我需要完成这个“自定义”组件的最后一块。继承我的SSCCE。

焦点丢失时:默认值设置为零,文本更新。

它只接受带有2位小数的十进制值,它只接受货币或百分比值。

没有别的东西可以补充。

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class test extends Application{

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox v = new VBox();
        v.setPadding(new Insets(20));
        Spinner<Double> spinner = new Spinner<>();
        spinner.setEditable(true);
        Button dummy = new Button("dummy focus");
        v.getChildren().addAll(spinner,dummy);


        //----------------------------------HERE IS EVERYTHING RELATED TO THE SPINNER---------------------------------------------
        spinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, 100));
        spinner.getValueFactory().setValue(0.0);
        spinner.getEditor().textProperty().addListener((obs,old,gnu)->{

            if(gnu.isEmpty()) {
                System.out.println("empty, buttons should be disabled here, they will be disabled after this ");
                spinner.getValueFactory().setValue(0.0);
                return;
            }
            System.out.println("enabling buttons");
            if(!gnu.matches("^\\d*\\.?\\d*$")) {
                try {
                    spinner.getEditor().setText(old);
                    spinner.getValueFactory().setValue(Double.parseDouble(old));
                }catch (NumberFormatException e) {
                    System.out.println("invalid string, previous value was empty, no biggie you are safe: Current value : "+spinner.getValueFactory().getValue());
                }
            } else {
                if((Double.parseDouble(gnu)*100)%1!=0) {
                    spinner.getEditor().setText(old);
                    spinner.getValueFactory().setValue(Double.parseDouble(old));                    
                }
                /*
                 * You can use this to validate inside a range, for example. PERCENTAGES : 0 ~ 100
                 *
                double val = Double.parseDouble(gnu)*100;
                if(val%1!=0 || val>10000 || val<0) {
                    spinner.getEditor().setText(old);
                    spinner.getValueFactory().setValue(Double.parseDouble(old));                    
                }
                */
            }
        });
        spinner.getEditor().setOnKeyPressed(e->{            
            switch (e.getCode()) {
                case UP:
                    spinner.increment(1);
                    break;
                case DOWN:
                    spinner.decrement(1);
                    break;

                default:
                    break;
            }
        });
        spinner.setOnScroll(e->{
            if(e.getDeltaY()>0)
                spinner.increment(1);
            else
                spinner.decrement(1);
        });
        spinner.getEditor().focusedProperty().addListener((obs,old,niu)->{
            if(!niu && spinner.getEditor().getText().isEmpty()) {
                spinner.getEditor().setText("0");
                spinner.getValueFactory().setValue(0.0);
            }
        });     
        //-----------------------------------------------------------------------------------------------------------------------------------------




        Scene sc = new Scene(v);
        primaryStage.setScene(sc);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

编辑:

它也会发生在按键和滚动事件中。

javafx spinner
2个回答
1
投票

我担心你不能只禁用微调器的按钮。但是在Editor(实际上是TextField)之后设置值是空的呢?通过使用这样的解决方案,您在单击按钮后不会出现任何异常 - 值仅从0增加。我修改了你的gnu.isEmpty()代码。

if(gnu.isEmpty()) {
  System.out.println("empty, buttons should be disabled here, they will be disabled after this ");
  double valueToSet = 0.0;
  spinner.getValueFactory().setValue(valueToSet);
  Platform.runLater(() -> spinner.getEditor().setText(Double.toString(valueToSet)));
  return;
}

另一件事是,你的代码允许将'0'作为第一个数字,即使之后还有另一个数字。检查代码,应该解决问题(用if(!gnu.matches("^\\d*\\.?\\d*$"))开头的整个if / else语句交换):

if (!isDouble(gnu)) {
    gnu = old;
}
spinner.getEditor().setText(gnu);

isDouble是一种方法:

private boolean isDouble(String string) {
    boolean startsWithZero =
            string.startsWith("0") &&
                    (string.length() > 1) &&
                    (!string.startsWith("0."));
    boolean minusZeroCondition =
            string.startsWith("-0") &&
                    (string.length() > 2) &&
                    (!string.startsWith("-0."));
    boolean containsTypeSpecificLetters =
            Pattern.matches(".*[a-zA-Z].*", string);
    boolean isEmpty = string.equals("");
    boolean isMinus = string.equals("-");
    try {
        Double.parseDouble(string);
        return !(startsWithZero || minusZeroCondition || containsTypeSpecificLetters);
    } catch (IllegalArgumentException exception) {
        return isEmpty || isMinus;
    }
}

1
投票

我也在寻找一种只禁用按钮的方法。我需要禁用更改Spinner的值,同时仍然允许复制/粘贴,所以我做了一些挖掘源代码。

我发现,虽然按钮实际上不是Spinner对象本身的一部分,但它们是SpinnerSpinnerSkin(它们也不是Buttons,但是StackPanes)的一部分,所以我设法禁用以下按钮(在Kotlin):

val editing = SimpleBooleanProperty(false)
val spinner = Spinner<Int>()
spinner.skinProperty().addListener { observable, oldValue, newValue ->
    // only bind if the skin is an instance of `SpinnerSkin`
    if (newValue != null && newValue is SpinnerSkin<*>) {
        (skin as SpinnerSkin<*>).children
            // only select the children that are `StackPane`s (the buttons)
            .filter { it is StackPane }
            // bind the `disableProperty` of the buttons to our property for whether we're editing
            .forEach { disableProperty().bind(editing.not()) }
    } 
}

我不得不听取属性更改,因为skinProperty未在初始化时设置,但仅在CSS处理完毕后才设置。如果你完全确定你的微调器已经显示并且设置了皮肤,你可以改为调用getSkin

© www.soinside.com 2019 - 2024. All rights reserved.