下拉框只有在單擊時才會彈出所有選項的下拉列表,這固然節省了有限的界面空間,但有時候又需要把所有選項都固定展示到窗口上。像這種平鋪的列表控件,Swing給出的控件名稱是ListBox,而JavaFX提供了列表視圖ListView。在具體編碼運用上,ListView的用法幾乎跟ComboBox一模一樣,二者的列表項擁有相同的數據來源,同樣調用setStyle方法來設置各項字體,而且列表項的選擇監聽器也保持一致,唯一的區別便是控件名稱由ComboBox改成了ListView。
既然ListView的用法與ComboBox雷同,這里就不再羅嗦了,仍舊以快餐列表為例,且看下面的ListView使用代碼片段:
// 獲取列表的界面 private void getListView(BorderPane borderPane) { VBox vbox = new VBox(); // 創建一個垂直箱子 // 初始化快餐列表 List<String> snackList = Arrays.asList("魚香肉絲飯", "香菇滑雞飯", "黑椒牛排飯", "梅菜扣肉飯", "糖醋里脊飯", "紅燒排骨飯", "台式鹵肉飯"); // 把清單對象轉換為JavaFX控件能夠識別的數據對象 ObservableList<String> obList = FXCollections.observableArrayList(snackList); ListView<String> listView = new ListView<String>(obList); // 依據指定數據創建列表視圖 //listView.setItems(obList); // 設置列表視圖的數據來源 listView.setPrefSize(400, 180); // 設置列表視圖的推薦寬高 Label label = new Label("這里查看點餐結果"); // 創建一個標簽 label.setWrapText(true); // 設置標簽文本是否支持自動換行 vbox.getChildren().addAll(listView, label); // 把列表和標簽一起加到垂直箱子上 // 設置列表視圖的選擇監聽器 listView.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", listView.getSelectionModel().getSelectedIndex(), listView.getSelectionModel().getSelectedItem().toString()); label.setText(desc); // 在標簽上顯示當前選中的文本項 } }); borderPane.setCenter(vbox); // 把垂直箱子放到邊界窗格的中央 }
運行包含以上代碼的測試程序,在彈出的窗口中單擊按鈕“顯示列表”,界面中央展示了平鋪直敘的快餐列表視圖,正如下面左圖所示。單擊列表中的某種快餐,窗口下方會顯示當前的選擇結果,此時界面效果如下面右圖所示。
盡管ListView能夠將所有選項羅列在界面上,可是每行僅僅顯示當前選項的文本,無法展現更豐富的組合信息。比如餐廳的點餐窗口,除了快餐名稱,還應展示快餐價格,如此一來,整個快餐列表更像是一份表格,不但分行而且分列,才顯得井然有序。為此JavaFX提供了對應的表格控件名叫TableView,不過因為表格內嵌了結構化信息,所以表格內容需要特制的數據實體。就快餐的數據結構而言,假設它由序號、快餐名稱、快餐價格這三個字段組成,則要預先定義如下所示的快餐信息類:
//定義快餐類 public class Snack { private SimpleStringProperty xuhao; // 序號 private SimpleStringProperty name; // 快餐名稱 private SimpleStringProperty price; // 快餐價格 public Snack(String xuhao, String name, String price) { this.xuhao = new SimpleStringProperty(xuhao); this.name = new SimpleStringProperty(name); this.price = new SimpleStringProperty(price); } public String getXuhao() { // 獲取序號 return xuhao.get(); } public void setXuhao(String xuhao) { // 設置序號 this.xuhao.set(xuhao); } public String getName() { // 獲取快餐名稱 return name.get(); } public void setName(String name) { // 設置快餐名稱 this.name.set(name); } public String getPrice() { // 獲取快餐價格 return price.get(); } public void setPrice(String price) { // 設置快餐價格 this.price.set(price); } }
注意上面定義的快餐各字段屬性,它們的數據類型為表格專用的SimpleStringProperty,只有該類型的數據才會自動填充到表格單元中。
定義好了快餐信息類,接下來再操作表格控件TableView,使用該控件主要包括下列兩個步驟:
1、指定表格視圖的數據來源
首先創建快餐列表的清單對象,並將其轉換為JavaFX能夠識別的ObservableList對象,然后依據這個數據對象創建表格視圖,相應的代碼片段示例如下:
// 創建表格的內容清單 List<Snack> snackList = Arrays.asList( new Snack("1", "魚香肉絲飯", "16"), new Snack("2", "香菇滑雞飯", "18"), new Snack("3", "黑椒牛排飯", "20"), new Snack("4", "梅菜扣肉飯", "17"), new Snack("5", "糖醋里脊飯", "19"), new Snack("6", "紅燒排骨飯", "17"), new Snack("7", "台式鹵肉飯", "15")); // 把清單對象轉換為JavaFX控件能夠識別的數據對象 ObservableList<Snack> obList = FXCollections.observableArrayList(snackList); TableView<Snack> tableView = new TableView<Snack>(obList); // 依據指定數據創建表格視圖
2、創建各列的表頭,以及各列關聯的對象屬性
前一步的數據來源只包含表格的單元內容,不包括表頭的標題行。標題行需要另外通過TableColumn聲明,表格有多少列,就得聲明多少個TableColumn對象,該對象不但規定了當列的標題文字,還規定了當列的內容取自哪個屬性,屬性名稱與第一步數據對象的字段名稱保持一致。以快餐信息為例,快餐對象擁有序號、快餐名稱、快餐價格三個字段,則要給快餐表格分配三個列,且這三列的單元值分別取自Snack類的三個字段(xuhao、name、price)。於是編寫表頭及其關聯屬性的代碼例子如下:
TableColumn firstColumn = new TableColumn("序號"); // 創建一個表格列 firstColumn.setMinWidth(100); // 設置列的最小寬度 // 設置該列取值對應的屬性名稱。此處序號列要展示Snack元素的xuhao屬性值 firstColumn.setCellValueFactory(new PropertyValueFactory<>("xuhao")); TableColumn secondColumn = new TableColumn("快餐名稱"); // 創建一個表格列 secondColumn.setMinWidth(200); // 設置列的最小寬度 // 設置該列取值對應的屬性名稱。此處名稱列要展示Snack元素的name屬性值 secondColumn.setCellValueFactory(new PropertyValueFactory<>("name")); TableColumn thirdColumn = new TableColumn("快餐價格"); // 創建一個表格列 thirdColumn.setMinWidth(110); // 設置列的最小寬度 // 設置該列取值對應的屬性名稱。此處價格列要展示Snack元素的price屬性值 thirdColumn.setCellValueFactory(new PropertyValueFactory<>("price")); // 把幾個標題列一齊添加到表格視圖 tableView.getColumns().addAll(firstColumn, secondColumn, thirdColumn);
把上述兩個步驟加以整合,形成完整的表格操作過程,合並后的表格視圖調用代碼如下所示:
// 獲取表格的界面 private void getTableView(BorderPane borderPane) { VBox vbox = new VBox(); // 創建一個垂直箱子 // 創建表格的內容清單 List<Snack> snackList = Arrays.asList( new Snack("1", "魚香肉絲飯", "16"), new Snack("2", "香菇滑雞飯", "18"), new Snack("3", "黑椒牛排飯", "20"), new Snack("4", "梅菜扣肉飯", "17"), new Snack("5", "糖醋里脊飯", "19"), new Snack("6", "紅燒排骨飯", "17"), new Snack("7", "台式鹵肉飯", "15")); // 把清單對象轉換為JavaFX控件能夠識別的數據對象 ObservableList<Snack> obList = FXCollections.observableArrayList(snackList); TableView<Snack> tableView = new TableView<Snack>(obList); // 依據指定數據創建表格視圖 //tableView.setItems(obList); // 設置表格視圖的數據來源 tableView.setPrefSize(400, 210); // 設置表格視圖的推薦寬高 TableColumn firstColumn = new TableColumn("序號"); // 創建一個表格列 firstColumn.setMinWidth(100); // 設置列的最小寬度 // 設置該列取值對應的屬性名稱。此處序號列要展示Snack元素的xuhao屬性值 firstColumn.setCellValueFactory(new PropertyValueFactory<>("xuhao")); TableColumn secondColumn = new TableColumn("快餐名稱"); // 創建一個表格列 secondColumn.setMinWidth(200); // 設置列的最小寬度 // 設置該列取值對應的屬性名稱。此處名稱列要展示Snack元素的name屬性值 secondColumn.setCellValueFactory(new PropertyValueFactory<>("name")); TableColumn thirdColumn = new TableColumn("快餐價格"); // 創建一個表格列 thirdColumn.setMinWidth(110); // 設置列的最小寬度 // 設置該列取值對應的屬性名稱。此處價格列要展示Snack元素的price屬性值 thirdColumn.setCellValueFactory(new PropertyValueFactory<>("price")); // 把幾個標題列一齊添加到表格視圖 tableView.getColumns().addAll(firstColumn, secondColumn, thirdColumn); vbox.getChildren().add(tableView); // 把表格加到垂直箱子上 borderPane.setCenter(vbox); // 把垂直箱子放到邊界窗格的中央 }
運行包含以上代碼的測試程序,在彈出的窗口中單擊按鈕“顯示表格”,界面上呈現了一個內容豐富的快餐表格,具體效果如下圖所示。
更多Java技術文章參見《Java開發筆記(序)章節目錄》