16 コンボ・ボックス
この章では、JavaFXアプリケーションでコンボ・ボックスを使用する方法について説明します。ここでは編集可能、および編集不可のコンボ・ボックスについて説明し、編集可能なコンボ・ボックスでの変更の追跡方法とそのイベントの処理方法について学習し、コンボ・ボックスのデフォルトの実装に代わるセル・ファクトリの使用方法について説明します。
コンボ・ボックスは、ユーザーが複数のオプションから1つを選択できるユーザー・インタフェースの一般的な要素です。コンボ・ボックスは選択ボックスとは異なり、ドロップダウン・リストにスクロールを追加できるため、表示する項目の数が一定の制限を超える場合に役立ちます。項目の数が特定の制限を超えていない場合、開発者はコンボ・ボックスと選択ボックスのどちらがニーズに一致するかを判断する必要があります。
JavaFXアプリケーションでコンボ・ボックスを作成するには、JavaFX APIのComboBox
クラスを使用します。図16-1に、2つのコンボ・ボックスのあるアプリケーションを示します。
コンボ・ボックスの作成
コンボ・ボックスを作成する場合、ChoiceBox
、ListView
、およびTableView
など、他のUIコントロールと同様に、ComboBox
クラスをインスタンス化し、項目を監視可能リストとして定義する必要があります。例16-1では、コンストラクタ内に項目を設定します。
例16-1 監視可能なリストを使用したコンボ・ボックスの作成
ObservableList<String> options = FXCollections.observableArrayList( "Option 1", "Option 2", "Option 3" ); final ComboBox comboBox = new ComboBox(options);
その他の選択肢としては、空のコンストラクタを使用して、それにsetItems
メソッドをcomboBox.setItems(options);
のようにコールしてコンボ・ボックスを作成します。
コンボ・ボックスがアプリケーション・シーンに追加されると、図16-2に示すようにユーザー・インタフェースに表示されます。
項目のリストには、常に新しい値を追加できます。例16-2では、3つの項目をcomboBoxコントロールに追加してこのタスクを実装しています。
ComboBox
クラスはこのコンボ・ボックスで使用できる簡単なプロパティとメソッドを提供します。
setValue
メソッドを使用すると、コンボ・ボックスで選択された項目を指定できます。ComboBox
オブジェクトにsetValue
メソッドをコールすると、selectionModel
プロパティで選択された項目は、値がコンボ・ボックス項目のリストになくても、その値に変更されます。次に、この値を含むよう項目リストが変更されると、該当する項目が選択されます。
同様に、getValue
メソッドをコールすると、選択された項目の値を取得できます。ユーザーが項目を選択すると、selectionModel
プロパティの選択された項目とコンボ・ボックスのvalue
プロパティの両方が新しい値に更新されます。
行を表示する場合は、ComboBox
ドロップダウン・リストに表示可能な行数を制限することもできます。comboBoxコントロールで3つの項目の表示を可能にするには、次のコード行comboBox.setVisibleRowCount(3)
を使用します。このメソッドをコールした結果、図16-3に示すように、表示可能な行は3行に制限され、スクロール・バーが表示されます。
ComboBox
クラスには一般的な表記法があり、様々なタイプの項目へのユーザーによるデータ移入を有効にできますが、Node
、またはその他のサブクラスはタイプとして使用しないでください。シーン・グラフの概念では、アプリケーション・シーンの1つの場所に配置できるNode
オブジェクトは1つのみであるとされているため、選択された項目は、項目のComboBox
リストから削除されます。選択を変更すると、最初に選択していた項目がリストに戻され、新しい選択が削除されます。この状況を防止するには、セル・ファクトリ・メカニズムとAPIドキュメントに記載されているソリューションを使用します。セル・ファクトリのメカニズムは、ComboBox
オブジェクトの初期の動作または外観を変更する必要がある場合に特に役立ちます。
ComboBoxSampleアプリケーションは、一般的な電子メール・インタフェースでコンボ・ボックスを使用する方法を示すよう設計されています。例16-3では、このようなインタフェースを作成し、2つのコンボ・ボックスを使用して電子メールの受信者とメッセージの優先度を選択できるようにします。
例16-3 コンボ・ボックスの作成およびシーンへの追加
import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.stage.Stage; public class ComboBoxSample extends Application { public static void main(String[] args) { launch(args); } final Button button = new Button ("Send"); final Label notification = new Label (); final TextField subject = new TextField(""); final TextArea text = new TextArea (""); String address = " "; @Override public void start(Stage stage) { stage.setTitle("ComboBoxSample"); Scene scene = new Scene(new Group(), 500, 270); final ComboBox emailComboBox = new ComboBox(); emailComboBox.getItems().addAll( "jacob.smith@example.com", "isabella.johnson@example.com", "ethan.williams@example.com", "emma.jones@example.com", "michael.brown@example.com" ); final ComboBox priorityComboBox = new ComboBox(); priorityComboBox.getItems().addAll( "Highest", "High", "Normal", "Low", "Lowest" ); priorityComboBox.setValue("Normal"); GridPane grid = new GridPane(); grid.setVgap(4); grid.setHgap(10); grid.setPadding(new Insets(5, 5, 5, 5)); grid.add(new Label("To: "), 0, 0); grid.add(emailComboBox, 1, 0); grid.add(new Label("Priority: "), 2, 0); grid.add(priorityComboBox, 3, 0); grid.add(new Label("Subject: "), 0, 1); grid.add(subject, 1, 1, 3, 1); grid.add(text, 0, 2, 4, 1); grid.add(button, 0, 3); grid.add (notification, 1, 3, 3, 1); Group root = (Group)scene.getRoot(); root.getChildren().add(grid); stage.setScene(scene); stage.show(); } }
例16-3に示すコンボ・ボックスは、どちらもgetItems
メソッドとaddAll
メソッドを使用して項目を追加します。このコードをコンパイルして実行すると、図16-4に示すアプリケーション・ウィンドウが作成されます。
編集可能なコンボ・ボックス
通常、電子メール・クライアント・アプリケーションでは、ユーザーはアドレス帳からの受信者の選択、および新しいアドレスの入力が可能です。このようなタスクには、編集可能なコンボ・ボックスが最も適しています。ComboBox
クラスのsetEditable(true)
メソッドを使用して、コンボ・ボックスを編集可能にします。setPromptText
メソッドでは、何も選択されていないときにコンボ・ボックスの編集領域に表示するテキストを指定できます。例16-4では、アプリケーションの変更コードを確認します。太字の行が例16-3に追加された部分です。
例16-4 編集可能コンボ・ボックスに新たに入力された値の処理
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.stage.Stage; public class ComboBoxSample extends Application { public static void main(String[] args) { launch(args); } final Button button = new Button ("Send"); final Label notification = new Label (); final TextField subject = new TextField(""); final TextArea text = new TextArea (""); String address = " "; @Override public void start(Stage stage) { stage.setTitle("ComboBoxSample"); Scene scene = new Scene(new Group(), 500, 270); final ComboBox emailComboBox = new ComboBox(); emailComboBox.getItems().addAll( "jacob.smith@example.com", "isabella.johnson@example.com", "ethan.williams@example.com", "emma.jones@example.com", "michael.brown@example.com" ); emailComboBox.setPromptText("Email address"); emailComboBox.setEditable(true); emailComboBox.setOnAction((Event ev) -> { address = emailComboBox.getSelectionModel().getSelectedItem().toString(); }); final ComboBox priorityComboBox = new ComboBox(); priorityComboBox.getItems().addAll( "Highest", "High", "Normal", "Low", "Lowest" ); priorityComboBox.setValue("Normal"); button.setOnAction((ActionEvent e) -> { if (emailComboBox.getValue() != null && !emailComboBox.getValue().toString().isEmpty()){ notification.setText("Your message was successfully sent" + " to " + address); emailComboBox.setValue(null); if (priorityComboBox.getValue() != null && !priorityComboBox.getValue().toString().isEmpty()){ priorityComboBox.setValue(null); } subject.clear(); text.clear(); } else { notification.setText("You have not selected a recipient!"); } }); GridPane grid = new GridPane(); grid.setVgap(4); grid.setHgap(10); grid.setPadding(new Insets(5, 5, 5, 5)); grid.add(new Label("To: "), 0, 0); grid.add(emailComboBox, 1, 0); grid.add(new Label("Priority: "), 2, 0); grid.add(priorityComboBox, 3, 0); grid.add(new Label("Subject: "), 0, 1); grid.add(subject, 1, 1, 3, 1); grid.add(text, 0, 2, 4, 1); grid.add(button, 0, 3); grid.add (notification, 1, 3, 3, 1); Group root = (Group)scene.getRoot(); root.getChildren().add(grid); stage.setScene(scene); stage.show(); } }
emailComboBox
を編集できる他に、このコード・フラグメントはこのコントロールのイベント処理を実装します。新たに入力、または選択した値はaddress
変数に格納されます。ユーザーが「Send」ボタンを押すと、電子メール・アドレスを含む通知が表示されます。
図16-5は、ユーザーがJacob Smithの電子メール・アドレスを編集し、これをgreg.smith@example.comに変更した瞬間のキャプチャを示します。
「Send」ボタンを押すと、すべてのコントロールがデフォルトの状態に戻ります。TextField
オブジェクトとTextArea
オブジェクトに対してclear
メソッドがコールされ、コンボ・ボックスの選択された項目にnull
値が設定されます。図16-6に、「Send」ボタンを押した後の瞬間を示します。
コンボ・ボックスへのセル・ファクトリの適用
セル・ファクトリのメカニズムを使用すると、コンボ・ボックスのデフォルトの動作または外観を変更できます。例16-5では、セル・ファクトリを作成し、それを「Priority」コンボ・ボックスに適用して、優先度タイプを特別な色で強調表示します。
例16-5 「Priority」コンボ・ボックスへのセル・ファクトリの実装
import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.Callback; public class ComboBoxSample extends Application { public static void main(String[] args) { launch(args); } final Button button = new Button ("Send"); final Label notification = new Label (); final TextField subject = new TextField(""); final TextArea text = new TextArea (""); String address = " "; @Override public void start(Stage stage) { stage.setTitle("ComboBoxSample"); Scene scene = new Scene(new Group(), 500, 270); final ComboBox emailComboBox = new ComboBox(); emailComboBox.getItems().addAll( "jacob.smith@example.com", "isabella.johnson@example.com", "ethan.williams@example.com", "emma.jones@example.com", "michael.brown@example.com" ); emailComboBox.setPromptText("Email address"); emailComboBox.setEditable(true); emailComboBox.setOnAction((Event ev) -> { address = emailComboBox.getSelectionModel().getSelectedItem().toString(); }); final ComboBox priorityComboBox = new ComboBox(); priorityComboBox.getItems().addAll( "Highest", "High", "Normal", "Low", "Lowest" ); priorityComboBox.setValue("Normal"); priorityComboBox.setCellFactory( new Callback<ListView<String>, ListCell<String>>() { @Override public ListCell<String> call(ListView<String> param) { final ListCell<String> cell = new ListCell<String>() { { super.setPrefWidth(100); } @Override public void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (item != null) { setText(item); if (item.contains("High")) { setTextFill(Color.RED); } else if (item.contains("Low")){ setTextFill(Color.GREEN); } else { setTextFill(Color.BLACK); } } else { setText(null); } } }; return cell; } }); button.setOnAction((ActionEvent e) -> { if (emailComboBox.getValue() != null && !emailComboBox.getValue().toString().isEmpty()){ notification.setText("Your message was successfully sent" + " to " + address); emailComboBox.setValue(null); if (priorityComboBox.getValue() != null && !priorityComboBox.getValue().toString().isEmpty()){ priorityComboBox.setValue(null); } subject.clear(); text.clear(); } else { notification.setText("You have not selected a recipient!"); } }) GridPane grid = new GridPane(); grid.setVgap(4); grid.setHgap(10); grid.setPadding(new Insets(5, 5, 5, 5)); grid.add(new Label("To: "), 0, 0); grid.add(emailComboBox, 1, 0); grid.add(new Label("Priority: "), 2, 0); grid.add(priorityComboBox, 3, 0); grid.add(new Label("Subject: "), 0, 1); grid.add(subject, 1, 1, 3, 1); grid.add(text, 0, 2, 4, 1); grid.add(button, 0, 3); grid.add (notification, 1, 3, 3, 1); Group root = (Group)scene.getRoot(); root.getChildren().add(grid); stage.setScene(scene); stage.show(); } }
セル・ファクトリはListCell
オブジェクトを作成します。すべてのセルが単一のコンボ・ボックス項目と関連付けられます。各コンボ・ボックス項目の幅は、setPrefWidth
メソッドを使用して設定します。updateItem
メソッドは、「High」および「Highest」の項目に対しては赤、「Low」および「Lowest」の項目に対しては緑に設定し、「Normal」の項目に対しては黒のままで設定を変更しません。
図16-7 は、例16-5を適用した後の「Priority」コンボ・ボックスの項目を示しています。
ComboBox
コントロールの外観は、CSSスタイルや視覚効果を適用してさらに拡張できます。
関連APIドキュメント