1. ホーム
  2. java

[解決済み] JavaFX TextFieldのTextFormatterからSimpleDoublePropertyにvaluePropertyをバインドする。

2022-02-26 13:07:15

質問

TextFormatterは、テキストフィールドの入力を受け取り、それがdoubleフォーマットであることを確認するフィルタを持っています。そして、DoubleStringConverter を使用して、フィルタリングされたテキストを double 値に変換しています。これはカスタムFXMLコンポーネントの中にあります。最小限の例については以下を参照してください。

public SomeComponent implements Initializable {
    @FXML
    public TextField inputField;

    public int min;

    public void initialize(URL location, ResourceBundle resources) {
        UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
            String newText = change.getControlNewText();
            if (newText.matches("-?[0-9]{1,13}(\\.[0-9]*)?")) { 
                return change;
            }
            return null;
        };

        inputField.setTextFormatter(new TextFormatter<>(new DoubleStringConverter(), min, doubleFilter)); 
    }
}

このコンポーネントを使用した別のFXMLコンポーネント ...

public SomeView implements Initializable {
    @FXML
    SomeComponent comp;
    public void initialize(URL location, ResourceBundle resources) {
        comp.inputField.getTextFormatter().valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
    }
}

bindBidirectional() は、TextField の変換後の値を SimpleDoubleProperty が存在します。しかし、これは次のようなエラーを返します。

method Property.bindBidirectional(Property<CAP#1>) is not applicable
(argument mismatch; SimpleDoubleProperty cannot be converted to Property<CAP#1>)

本来はTextFieldの値を利用したいのですが、( getText() 他のプロパティにバインドするために、変換された値を使用します。

TextFormatterで取り込まれた型推論がおかしいのはわかるのですが、JavaDocsのどこにもTextFormatterのdouble値を利用する方法を示しているところが見当たりません。TextFieldからそのdouble値を抽出する簡単な方法がない場合、DoubleStringConverterを使用して値を変換することに何の意味があるのでしょうか?私は Double.parseDouble(inputField.getText()) しかし、このフィールドのためにわざわざ素敵な TextFormatter をセットアップしているのであれば、これは無意味なことのように思えます。

TextFormatter の valueProperty を SomeComponent の外部で利用するにはどうしたらよいでしょうか?

どのように解決するのですか?

その textFormatter プロパティは ObjectProperty<TextFormatter<?>> . このため TextInputControl クラスがジェネリックでない場合、このクラスを適切にパラメータ化する方法はありません。 textFormatter プロパティにワイルドカードを使用しています。つまり、このプロパティを照会すると、常に TextFormatter<?> に設定されていても、たとえば TextFormatter<Double> . これを解決するには、いくつかの方法があります。

  1. 結果を期待通りの汎用型にキャストします。

    var formatter = (TextFormatter<Number>) comp.inputField.getTextFormatter();
    formatter.valueProperty().bindBidirectional(SomeDataManagerClass.SomeSimpleDoubleProperty());
    
    

    もちろん、この場合、チェックされていないキャストの警告が発生します。この警告を抑制したい場合は @SuppressWarnings("unchecked") アノテーションを使用しますが、安全でないことに変わりはありません。

  2. を参照しておいてください。 TextFormatter<Number> で、他のコードがそれを取得するためのメソッドを提供します。

    public SomeComponent implements Initializable {
    
        @FXML
        public TextField inputField;
    
        // maintain generic information
        private TextFormatter<Number> inputFieldFormatter;
    
        public int min;
    
        public void initialize(URL location, ResourceBundle resources) {
            UnaryOperator<TextFormatter.Change> doubleFilter = change -> {
                String newText = change.getControlNewText();
                if (newText.matches("-?[0-9]{1,13}(\\.[0-9]*)?")) { 
                    return change;
                }
                return null;
            };
    
            inputFieldFormatter = new TextFormatter<>(new NumberStringConverter(), min, doubleFilter);
            inputField.setTextFormatter(inputFieldFormatter)); 
        }
    
        // use this method in your other controller
        public TextFormatter<Number> getInputFieldFormatter() {
            return inputFieldFormatter;
        }
    }
    
    

それぞれのケースで、私は TextFormatter<Number> . これは DoublePropertyProperty<Number> と、その bindBidirectional とは異なり、完全なジェネリックマッチを期待します。 bind メソッドは上限が決められています。これはまた NumberStringConverter を使わなければならなかった。