torutkのブログ

ソフトウェア・エンジニアのブログ

UIコントロールの背景色を動的に変更する

JavaFXでUIを作成する際、例えばテキストフィールドに入力した文字列に誤りがあった場合にそのテキストフィールドの背景色を変えることで入力誤りをユーザーに通知する方法があります。とくに入力項目が多い場合に有効な手段です。

JavaFXのUIコントロール(例:TextField)は、色などの見栄えについては直接APIで制御するのではなく、CSS(Cascade Style Sheet)を記述して行います。そこで、CSSをどう指定・変更すればよいのか試行錯誤をしてみました。

TextFieldの背景色を変える最初の試み(失敗)

最初に色を変更しようと、TextFieldのsetStyleメソッドにCSSの背景色記述文字列を渡しました。コードのイメージは次のようになります。

  TextField nameField = new TextField();
  ...
  if (isValidName(nameField.getText)) {
      nameField.setStyle("-fx-background-color: white");
  } else {
      nameField.setStyle("-fx-background-color: red");
  }

この結果、背景色だけは意図したとおりになりましたが、TextFieldとしての枠線が消えてしまいました。

TextFieldの背景色を変える次の試み(失敗)

最初の失敗の原因は、setStyleメソッドが既存のCSS定義をすべて消してしまうのかと思い、それではとCSSで背景色を変更したクラスを別途作成し、それを指定してみました。

まず、CSSでテキストフィールドの背景色をエラー用に指定する定義を記述します。

.text-field-error {
  -fx-background-color: red;
}

コードのイメージは次のようになります。

  TextField nameField = new TextField();
  ...
  if (isValidName(nameField.getText)) {
      nameField.getStyleClass().add("text-field");
  } else {
      nameField.getStyleClass().add("text-field-error");
  }
  • CSSのクラス名"text-field"は、TextFieldクラスのデフォルトの定義として存在します。

結果は、一度エラー用の背景色表示になると、次に正しい値を入れてもエラー用背景色表示のままとなっていました。

これは、おそらくgetStyleClassメソッドで取得できるStyleClassのリストにtext-fieldおよびtext-field-errorがある上で、そこにさらにtext-fieldをaddしているため、addが無効なのかと推測します。

TextFieldの背景色を変える次の試み(たぶん成功)

やり方が見えず、いろいろ調べていると次の掲示板(stackoverflow)の記事に行き当たりました。

この記事のやり方を取り入れたのが次のコードイメージです。

  TextField nameField = new TextField();
  ...
  if (isValidName(nameField.getText)) {
      nameField.getStyleClass().removeAll("text-field", "text-field-error");
      nameField.getStyleClass().add("text-field");
  } else {
      nameField.getStyleClass().removeAll("text-field", "text-field-error");
      nameField.getStyleClass().add("text-field-error");
  }

JavaFX 2的に正しいかは分かりませんが、ひとまず意図した動きにはなりました。

最後に

Swingでは、色の変更も全部APIで用意されているので、今回の目的のようにプログラムの中で背景色を変更することが容易です。
JavaFXでは、見栄えとロジックの分離が進み、設計全体としてはよい方向に進んでいるのですが、その分見栄えとロジックが密に絡む記述が一筋縄ではいかなくなっています。