質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.52%

javafx8でテキストフィールドの入力値バリデーションをプロパティバインドで実現したい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 3,196

AlnairBright

score 32

概要

例えば、社員コードを入力するテキストフィールドがあり、バリデーションのルールが以下の場合

  • 入力は数値のみ
  • 入力中に数値以外が入力されれば、即時にエラーメッセージをメッセージ表示用ラベルに反映
  • エラーメッセージ表示と同時に確認ボタンをdisableにする

どのようにbindすればいいのかよくわかりません。
もしかすると、こういった場合はプロパティバインドでは実現できない??

EmployeeView.fxmlには、

  • id:txtEmployeeCodeのTextField
  • id:lblErrorMessageのLabel
  • id:btnConfirmのButton
    があります。

EmployeeView.fxmlのcontroller、EmployeeViewPresenter.javaは
以下の通りに書きました。

public class EmployeeViewPresenter implements Initializable {

    @FXML
    private TextField txtEmployeeCode;

    @FXML
    private Label lblErrorMessage;

    @FXML
    private Button btnConfirm;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        //未入力チェック
        btnConfirm.disableProperty().bind(txtEmployeeCode.textProperty().isEmpty());
        //数値チェックはどうやれば。。。
        //エラーメッセージ表示は??

    }


    //ちなみに以下の処理であれば正しくバリデーションできた
    @FXML
    void keyTypedValidateEmployeeCode(KeyEvent keyEvent) {
//        String input = txtEmployeeCode.getText().concat(keyEvent.getCharacter());
//        try {
//            Integer.parseInt(input);
//            btnConfirm.setDisable(false);
//            lblErrorMessage.setText("");
//        } catch(NumberFormatException nfe) {
//            btnConfirm.setDisable(true);
//            if(input.trim().length() > 0) {
//                lblErrorMessage.setText("数字のみ入力してください");
//            } else {
//                lblErrorMessage.setText("");
//            }
//        }
    }


    @FXML
    public void actionConfirm (ActionEvent event) {
        //確認画面へ遷移する処理
    }

できたこと

  • 未入力時にボタンを無効に、入力時はボタンを有効にすることはできる
  • txtEmployeeCodeのKeyTypedイベント処理では実現可能

できなかったこと

プロパティバインドでの

  • 入力時に数値でないときのチェックの方法がわからない
  • エラー時に即時エラーメッセージを表示する方法がわからない

よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

ご質問のようなことも可能です。またbindを使うと依存する値が変化すると即座にbindしたプロパティに反映されます。例えば確認ボタンをdisableにすべき条件が(1)、エラーメッセージを表示すべき状態が(2)でこれ以外の状態はない場合だとすると、

(1)社員コードに正しい数値が入力されているとき以外(未入力も)
(2)社員コードが空でなくかつ数値以外がが入力されている場合

BooleanBinding codeIsInvalid = Bindings.createBooleanBinding(
  () -> {
    String s = txtEmployeeCode.getText();
    try {
      int employeeCode = Integer.parseInt(s);
      return false;
    } catch (NumberFormatException e) { //必要ならNPEなども補足
      return true;
    }
  },
  txtEmployeeCode.textProperty());
btnConfirm.disableProperty().bind(codeIsInvalid);
BooleanBinding codeNotEmptyAndInvalid =
  codeIsInvalid.and(txtEmployeeCode.textProperty().isEmpty().not()); 
StringBinding message = new When(codeNotEmptyAndInvalid)
  .then("コードが正しくありません").otherwise(""));
lblErrorMessage.textProperty().bind(message);

ご存知かも知れませんが通常の片方向バインドは一つのプロパティへは只一つのバインドしかできませんし、一時的に他の値を設定したくてもできなくなります。プロパティの値はバインドした値に支配されてしまうからです。Bindingはいくらでも複雑に作れますが却ってわかりにくくなるようだとイベントによる処理の方がいいかも知れませんね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/25 01:14

    ご回答誠にありがとうございました。

    複雑なバリデーションルールをつくるのも可能ということですね。
    とても参考になりました。
    最終的には、BindingsUtilクラスを作って
    こんな感じになりました。

    ```java
    public class EmployeeViewPresenter implements Initializable {

    @FXML
    private TextField txtEmployeeCode;

    @FXML
    private Label lblErrorMessage;

    @FXML
    private Button btnConfirm;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

    btnConfirm.setDisable(true);
    lblErrorMessage.setText("");

    BooleanBinding isNotNumber =
    BindingUtil.createIsNotNumberBinding(txtEmployeeCode);

    btnConfirm.disableProperty().bind(isNotNumber);

    BooleanBinding isNotEmptyAndCodeInvalid =
    isNotNumber.and(
    txtEmployeeCode.textProperty().isNotEmpty().not());

    StringBinding message =
    BindingUtil.createMessageBinding(
    isNotEmptyAndCodeInvalid, "コードは数字のみ入力してください。");

    lblErrorMessage.textProperty().bind(message);
    }

    @FXML
    public void actionConfirm (ActionEvent event) {
    //確認画面へ遷移する処理
    }
    }
    ```

    ```java
    public class BindingUtil {

    public static BooleanBinding createIsNotNumberBinding(TextField textField) {

    BooleanBinding bl = Bindings.createBooleanBinding(
    () -> {
    String code =textField.getText();
    try {
    Integer.parseInt(code);
    return false;
    } catch (NumberFormatException nfe) {
    return true;
    }
    },
    textField.textProperty());
    return bl;
    }

    public static StringBinding createMessageBinding(
    BooleanBinding condition, String msgTrue) {

    return new When(condition).then(msgTrue).otherwise("");
    }
    }
    ```

    キャンセル

  • 2016/09/25 01:18

    コメントにはソースのマークダウン使えないんですね。
    見づらいコメントになってしまってすみません。。。

    キャンセル

  • 2016/09/25 01:25

    訂正です。

    BooleanBinding isNotEmptyAndCodeInvalid =
    isNotNumber.and(txtEmployeeCode.textProperty().isNotEmpty().not());

    の部分ですが、.not()をつけてしまうと反対の動きになってしまったので
    .not()を外し、以下のようになりました。

    BooleanBinding isNotEmptyAndCodeInvalid =
    isNotNumber.and(txtEmployeeCode.textProperty().isNotEmpty());

    確認不足ですみません。。。

    キャンセル

  • 2016/09/25 01:30

    ごちゃごちゃしたコードサンプルからすっきりとした分かりやすいコードが生まれていて自分も参考になりました(w;

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る