HOWTO · Java

從 JavaFX 中的選擇框中獲取所選項目

本教程演示瞭如何從 JavaFX 中的選擇框中獲取選定的項目。

本頁內容

ChoiceBox 是一種 JavaFX 控制項,會以下拉式清單呈現項目,讓使用者從中挑選其中一項。本教學示範如何取得 ChoiceBox 中選取的項目:使用 getValue() 隨需讀取目前的值、使用 selectedItemProperty() 回應之後的選擇,以及處理使用者尚未選取任何項目的情況。

使用 getValue() 讀取目前的值

當程式碼需要「此刻」選取的項目時——例如在按鈕處理常式中,或是在對話方塊送出時——請對 ChoiceBox 呼叫 getValue(),例如 String selected = choiceBox.getValue();。

對於 ChoiceBox<String>,此方法會傳回 String,因此不需要轉型,也不會有索引計算可能出錯的問題。getValue() 是 choiceBox.getSelectionModel().getSelectedItem() 的簡寫;若要以程式方式選取項目,則可反向使用 setValue(T) 或 getSelectionModel().select(item)。

由於 getValue() 回報的是快照,它適合在單一時間點詢問選取結果的程式碼;當使用者改選其他項目時,它不會主動通知你。

使用 selectedItemProperty() 回應之後的選擇

若要在每次選擇變更時執行程式碼——例如更新標籤、啟用按鈕或載入相關資料——請將 ChangeListener 附加到 selectedItemProperty(),也就是選取模型中被選取項目背後的可觀察屬性:choiceBox.getSelectionModel().selectedItemProperty().addListener((observable, oldItem, newItem) -> statusLabel.setText(newItem + " is selected"));。

監聽器會同時收到先前的項目與新項目,且已具備正確型別,因此處理常式可直接使用該值。較舊的範例常改為監聽 selectedIndexProperty(),再用索引回頭存取當初填入清單的陣列;這種做法在索引為 -1 時會出錯,也讓處理常式與原始陣列產生耦合。直接監聽被選取的項目本身,即可同時避免這兩個問題。

處理未選取任何項目的情況

ChoiceBox 不一定保有選取項目。在使用者開啟清單之前,以及在 getSelectionModel().clearSelection() 或 setValue(null) 之後,getValue() 會傳回 null——不是空字串,也不是預留位置項目。讀取選取結果的程式碼應先檢查結果再使用:String selected = choiceBox.getValue();,接著 if (selected == null) { statusLabel.setText("No choice selected"); } 即可涵蓋這種狀態。

在 selectedItemProperty() 監聽器中加入相同的檢查,可讓你在選取被清除時還原預設標籤或停用控制項,而不是印出 null 或之後觸發 NullPointerException。

完整的 JavaFX 範例

真正的 ChoiceBox 視窗需要 JavaFX 模組與顯示環境,因此該 GUI 程式無法在單純的 JDK 工具鏈下編譯。下面的程式以純 Java 模擬相同的三項操作——可透過類似 getValue() 的方法讀取的選取項目、在每次後續選擇時觸發的監聽器,以及清除後會以 null 傳回的選取狀態——讓你能在任何環境中執行此選取流程。在實際應用程式中,相同的呼叫會在 start(Stage) 內對 javafx.scene.control.ChoiceBox 進行。

執行此範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

class ChoiceBoxDemo {

  // A minimal stand-in with the same selection API a JavaFX ChoiceBox
  // exposes through getValue(), select(item), and a change listener.
  static class ChoiceBox<T> {
    private final List<T> items;
    private T value;
    private final List<Consumer<T>> listeners = new ArrayList<>();

    ChoiceBox(List<T> items) {
      this.items = items;
    }

    T getValue() {
      return value;
    }

    void select(T item) {
      value = item;
      for (Consumer<T> listener : listeners) {
        listener.accept(item);
      }
    }

    void clearSelection() {
      select(null);
    }

    void addSelectionListener(Consumer<T> listener) {
      listeners.add(listener);
    }
  }

  public static void main(String[] args) {
    ChoiceBox<String> choiceBox = new ChoiceBox<>(Arrays.asList(
        "Delftstack 1", "Delftstack 2", "Delftstack 3", "Delftstack 4", "Delftstack 5"));

    choiceBox.addSelectionListener(item -> System.out.println(
        item == null ? "No choice selected" : item + " is selected"));

    String selected = choiceBox.getValue();
    System.out.println("Selected item: " + (selected == null ? "none" : selected));

    choiceBox.select("Delftstack 3");
    System.out.println("Selected item: " + choiceBox.getValue());

    choiceBox.clearSelection();
  }
}
Selected item: none
Delftstack 3 is selected
Selected item: Delftstack 3
No choice selected

在 JavaFX 版本中,相同的三個步驟位於 start(Stage) 內:應用程式類別繼承 Application,控制項以 new ChoiceBox<>(FXCollections.observableArrayList("Delftstack 1", "Delftstack 2", "Delftstack 3", "Delftstack 4", "Delftstack 5")) 建立,監聽器透過 choiceBox.getSelectionModel().selectedItemProperty().addListener(...) 附加並更新 Label,而各控制項放在 TilePane 中,以 stage.setScene(new Scene(pane, 400, 200)) 與 stage.show() 顯示;public static void main(String[] args) 會呼叫 launch(args)。狀態標籤一開始顯示 No choice selected,因為 ChoiceBox 尚無選取項目,之後每當使用者挑選項目時都會更新。範例程式碼、標籤文字與輸出字串維持英文原文,與位元組完全相同的範例一致。執行中的視窗如下所示:

從 ChoiceBox 取得選取的項目