與Swing一樣,JavaFX依然提供了三種選擇框,它們是復選框CheckBox、單選按鈕RadioButton、下拉框ComboBox,分別說明如下:
一、復選框CheckBox
復選框允許同時勾選多個,已勾選的時候在方框內部打個勾,未勾選的時候顯示空心方框。查看CheckBox的源碼,發現它與Button控件都派生自抽象類ButtonBase,因而CheckBox擁有和Button同樣的set***/get***方法。不同之處主要有以下兩點:
1、關於勾選狀態的設置與判斷:調用setSelected方法可以設置復選框的勾選狀態,調用isSelected方法可以判斷復選框是否被勾選了。
2、關於勾選監聽器的設置:先調用selectedProperty方法獲得復選框的屬性對象,再調用屬性對象的addListener方法設置該復選框的勾選監聽器。下面是給復選框設置單擊監聽器的代碼例子:
CheckBox ck = new CheckBox("滿意"); // 創建一個復選框
ck.selectedProperty().addListener(new ChangeListener<Boolean>() { // 設置復選框的勾選監聽器
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
// 單擊復選框會觸發這里的changed方法
}
});
接下來舉個具體的案例,餐廳的點餐系統要在界面上羅列各種菜餚,以便顧客勾選准備下單的菜品。簡單起見先列出三道菜餚,對應三個復選框,編寫完成的界面代碼示例如下:
// 獲取復選框的界面
private void getCheckBox(BorderPane borderPane) {
VBox vbox = new VBox(); // 創建一個垂直箱子
HBox hbox = new HBox(); // 創建一個水平箱子
CheckBox ck1 = new CheckBox("麻婆豆腐"); // 創建一個復選框
CheckBox ck3 = new CheckBox("清蒸桂花魚"); // 創建一個復選框
CheckBox ck2 = new CheckBox("香辣小龍蝦"); // 創建一個復選框
hbox.getChildren().addAll(ck1, ck2, ck3); // 把三個復選框一起加到水平箱子上
CheckBox[] boxArray = new CheckBox[]{ck1, ck2, ck3}; // 構建復選框數組
Label label = new Label("這里查看菜單詳情"); // 創建一個標簽
label.setWrapText(true); // 設置標簽文本是否支持自動換行
vbox.getChildren().addAll(hbox, label); // 把水平箱子和標簽一起加到垂直箱子上
ck1.selectedProperty().addListener(new ChangeListener<Boolean>() { // 設置復選框的勾選監聽器
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
// 拼接並顯示當前的勾選結果,以及已經勾選的菜餚
label.setText(String.format("您%s了%s。當前已點菜餚包括:%s",
(ck1.isSelected() ? "點" : "取消"), ck1.getText(), getCheckedItem(boxArray)));
}
});
ck2.selectedProperty().addListener(new ChangeListener<Boolean>() { // 設置復選框的勾選監聽器
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
// 拼接並顯示當前的勾選結果,以及已經勾選的菜餚
label.setText(String.format("您%s了%s。當前已點菜餚包括:%s",
(ck2.isSelected() ? "點" : "取消"), ck2.getText(), getCheckedItem(boxArray)));
}
});
ck3.selectedProperty().addListener(new ChangeListener<Boolean>() { // 設置復選框的勾選監聽器
@Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean old_value, Boolean new_value) {
// 拼接並顯示當前的勾選結果,以及已經勾選的菜餚
label.setText(String.format("您%s了%s。當前已點菜餚包括:%s",
(ck3.isSelected() ? "點" : "取消"), ck3.getText(), getCheckedItem(boxArray)));
}
});
borderPane.setCenter(vbox); // 把垂直箱子放到邊界窗格的中央
}
上面代碼用到了新方法getCheckedItem,該方法用來獲取已經選中的所有菜餚,它的代碼定義如下所示:
// 獲取已經選定的菜單
private String getCheckedItem(CheckBox[] boxArray) {
String itemDesc = "";
for (CheckBox box : boxArray) { // 遍歷復選框數組
if (box.isSelected() == true) { // 復選框被選中了
if (itemDesc.length() > 0) {
itemDesc = itemDesc + "、";
}
itemDesc = itemDesc + box.getText(); // 菜單添加選定的菜餚
}
}
return itemDesc;
}
運行包含以上代碼的點餐程序,彈出的窗口初始界面如下圖所示。

從左往右依次單擊三個復選框,界面上的點餐結果分別如下列三張圖所示。



二、單選按鈕RadioButton
在同一小組內的單選按鈕,最多只能選擇其中一個,它被選中時在圓圈內部顯示一個圓點,未選中時只顯示空心圓圈。RadioButton也由ButtonBase派生而來,因此擁有與Button控件同樣的set***/get***方法。區別之處主要有下列兩點:
1、關於加入到一個單選小組:調用單選按鈕的setToggleGroup方法,即可加入到指定的按鈕小組,該小組的控件類型是ToggleGroup。
2、關於單選按鈕的選擇監聽器:JavaFX把這個監聽器改到小組上面了,先調用ToggleGroup對象的selectedToggleProperty方法獲得單選組的屬性對象,再調用屬性對象的addListener方法設置該小組的單擊監聽器。
仍然以點餐系統為例,這次准備讓顧客享用單點的快餐,小店剛開業暫時只提供三種快餐,對應三個單選按鈕,編寫完成的界面代碼示例如下:
// 獲取單選按鈕的界面
private void getRadioButton(BorderPane borderPane) {
VBox vbox = new VBox(); // 創建一個垂直箱子
HBox hbox = new HBox(); // 創建一個水平箱子
RadioButton rb1 = new RadioButton("魚香肉絲飯"); // 創建一個單選按鈕
rb1.setSelected(true); // 設置按鈕是否選中
RadioButton rb2 = new RadioButton("香菇滑雞飯"); // 創建一個單選按鈕
RadioButton rb3 = new RadioButton("黑椒牛排飯"); // 創建一個單選按鈕
hbox.getChildren().addAll(rb1, rb2, rb3); // 把三個單選按鈕一起加到水平箱子上
ToggleGroup group = new ToggleGroup(); // 創建一個按鈕小組
rb1.setToggleGroup(group); // 把單選按鈕1加入到按鈕小組
rb2.setToggleGroup(group); // 把單選按鈕2加入到按鈕小組
rb3.setToggleGroup(group); // 把單選按鈕3加入到按鈕小組
Label label = new Label("這里查看點餐結果"); // 創建一個標簽
label.setWrapText(true); // 設置標簽文本是否支持自動換行
vbox.getChildren().addAll(hbox, label); // 把水平箱子和標簽一起加到垂直箱子上
// 設置單選組合的單擊監聽器
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
@Override
public void changed(ObservableValue<? extends Toggle> arg0, Toggle old_toggle, Toggle new_toggle) {
// 在標簽上顯示當前選中的單選按鈕文本
label.setText("您點了" + ((RadioButton)new_toggle).getText());
}
});
borderPane.setCenter(vbox); // 把垂直箱子放到邊界窗格的中央
}
運行包含以上代碼的點餐程序,彈出的窗口初始界面如下圖所示。

從圖示可見當前默認選中了第一個快餐“魚香肉絲飯”,此時先后單擊第二個快餐和第三個快餐,界面上的點餐結果分別如下列兩張圖所示。



三、下拉框ComboBox
如果單選小組里面的選項有很多,全部羅列到窗口上勢必占用大量界面空間,故而采用可伸縮的下拉框較為合適。平時只顯示最近一次選中的文字,需要改變的話再單擊彈出下拉列表,在下拉列表中選完再恢復原狀。看起來JavaFX的下拉框跟Swing的功能差不多,不過JavaFX的ComboBox控件用起來頗為怪異,有下面幾點需要特別注意:
1、關於選中某項以及獲取選中項:得先調用下拉框的getSelectionModel方法獲得模型對象,再調用模型對象的相應方法完成指定功能。例如,調用模型對象的select方法可以選中某項,調用getSelectedIndex方法可以獲得選中項的序號,調用getSelectedItem方法可以獲得選中項的對象。
2、關於設置下拉框的字體:ComboBox控件竟然沒提供setFont方法,只能調用setStyle方法通過css樣式設置文本字體及其大小。
3、關於設置下拉框的選擇監聽器:這個操作更復雜,要先調用下拉框的getSelectionModel方法獲得模型對象,再調用模型對象的selectedItemProperty方法獲得該模型的屬性對象,接着調用屬性對象的addListener方法給下拉框添加選擇監聽器。
繼續以點餐系統為例,原來那家快餐店的生意日趨紅火,快餐種類增加了不少,他們的點餐系統也將單選小組改造成了下拉框。改造完成的界面代碼示例如下:
// 獲取下拉框的界面
private void getComboBox(BorderPane borderPane) {
VBox vbox = new VBox(); // 創建一個垂直箱子
// 初始化快餐列表
List<String> snackList = Arrays.asList("魚香肉絲飯", "香菇滑雞飯", "黑椒牛排飯",
"梅菜扣肉飯", "糖醋里脊飯", "紅燒排骨飯", "台式鹵肉飯");
// 把清單對象轉換為JavaFX控件能夠識別的數據對象
ObservableList<String> obList = FXCollections.observableArrayList(snackList);
ComboBox<String> comboBox = new ComboBox<String>(obList); // 依據指定數據創建下拉框
//comboBox.setItems(obList); // 設置下拉框的數據來源
comboBox.getSelectionModel().select(0); // 設置下拉框默認選中第1項
Font font = Font.font("NSimSun", 16); // 創建一個字體對象
comboBox.setStyle(String.format("-fx-font: %f \"%s\";", font.getSize(), font.getFamily())); // 設置下拉框的字體
comboBox.setEditable(false); // 設置下拉框能否編輯。默認不允許編輯
Label label = new Label("這里查看點餐結果"); // 創建一個標簽
label.setWrapText(true); // 設置標簽文本是否支持自動換行
vbox.getChildren().addAll(comboBox, label); // 把水平箱子和標簽一起加到垂直箱子上
// 設置下拉框的選擇監聽器
comboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> arg0, String old_str, String new_str) {
// getSelectedIndex方法可獲得選中項的序號,getSelectedItem方法可獲得選中項的對象
String desc = String.format("您點了第%d項,快餐名稱是%s",
comboBox.getSelectionModel().getSelectedIndex(),
comboBox.getSelectionModel().getSelectedItem().toString());
label.setText(desc); // 在標簽上顯示當前選中的文本項
}
});
borderPane.setCenter(vbox); // 把垂直箱子放到邊界窗格的中央
}
運行包含以上代碼的點餐程序,彈出的窗口初始界面如下圖所示。

單擊下拉框控件,下方彈出一個包含所有快餐的列表框,具體界面如下圖所示。

單擊下拉列表中的某一項,表示換成指定的快餐,此時下拉列表隱藏,下拉框的文字變成剛點的快餐名稱,點餐結果正如下圖所示。

更多Java技術文章參見《Java開發筆記(序)章節目錄》
