JavaFX UI控件教程(十三)之Table View
翻譯自??Table View
在本章中,您將學習如何使用JavaFX應用程序中的表執行基本操作,例如添加表,使用數據填充表以及編輯表行。
JavaFX SDK API中的幾個類旨在以表格形式表示數據。用于創建JavaFX應用程序表中的最重要的類是TableView,TableColumn和TableCell。您可以通過實現數據模型和應用單元工廠來填充表。
表類提供了內置功能,可以對列中的數據進行排序,并在必要時調整列的大小。
圖12-1顯示了表示通訊簿中的聯系信息的典型表。
圖12-1表樣本
?
創建表
例12-1中的代碼片段創建了一個包含三列的空表,并將其添加到應用程序場景中。
例12-1添加表
import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage;public class TableViewSample extends Application {private TableView table = new TableView();public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) {Scene scene = new Scene(new Group());stage.setTitle("Table View Sample");stage.setWidth(300);stage.setHeight(500);final Label label = new Label("Address Book");label.setFont(new Font("Arial", 20));table.setEditable(true);TableColumn firstNameCol = new TableColumn("First Name");TableColumn lastNameCol = new TableColumn("Last Name");TableColumn emailCol = new TableColumn("Email");table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);final VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(10, 0, 0, 10));vbox.getChildren().addAll(label, table);((Group) scene.getRoot()).getChildren().addAll(vbox);stage.setScene(scene);stage.show();} }通過實例化TableView類來創建表控件。在示例12-1中,它被添加到VBox布局容器中,但是,您可以將其直接添加到應用程序場景中。
示例12-1定義了三列,用于將以下信息存儲在地址簿中:聯系人的名字和姓氏以及電子郵件地址。列是使用TableColumn類創建的。
該類的getColumns方法TableView將以前創建的列添加到表中。在應用程序中,您可以使用此方法動態添加和刪除列。
編譯和運行此應用程序將生成如圖12-2所示的輸出。
圖12-2沒有數據的表
您可以通過調用setVisible方法來管理列的可見性。例如,如果應用程序的邏輯需要隱藏用戶電子郵件地址,則可以按如下方式實現此任務:emailCol.setVisible(false)。
當數據結構需要更復雜的表示時,您可以創建嵌套列。
例如,假設地址簿中的聯系人有兩個電子郵件帳戶。然后,您需要兩列來顯示主電子郵件地址和輔助電子郵件地址。創建兩個子列,然后調用該getColumns方法,emailCol如例12-2所示。
示例12-2創建嵌套列
TableColumn firstEmailCol = new TableColumn("Primary"); TableColumn secondEmailCol = new TableColumn("Secondary");emailCol.getColumns().addAll(firstEmailCol, secondEmailCol);將這些行添加到示例12-1并編譯并運行應用程序代碼后,該表將如圖12-3所示。
圖12-3帶嵌套列的表
雖然該表已添加到應用程序中,但會顯示標準標題“表中沒有內容”,因為未定義任何數據。您可以使用該setPlaceholder方法指定Node要在空表中顯示的對象,而不是顯示此標題。
定義數據模型
在JavaFX應用程序中創建表時,最佳實踐是實現定義數據模型的類,并提供方法和字段以進一步使用表。例12-3創建了一個Person類來定義地址簿中的數據。
示例12-3創建Person類
public static class Person {private final SimpleStringProperty firstName;private final SimpleStringProperty lastName;private final SimpleStringProperty email;private Person(String fName, String lName, String email) {this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}public String getFirstName() {return firstName.get();}public void setFirstName(String fName) {firstName.set(fName);}public String getLastName() {return lastName.get();}public void setLastName(String fName) {lastName.set(fName);}public String getEmail() {return email.get();}public void setEmail(String fName) {email.set(fName);}}的firstName,lastName和email串屬性的設置是為了使一個特定的數據元素的引用。
另外,為每個數據元素提供get和set方法。因此,例如,該getFirstName方法返回firstName屬性的值,并且該setFirstName方法指定此屬性的值。
在Person類中概述數據模型時,您可以創建一個ObservableList數組并定義您希望在表中顯示的數據行數。例12-4中的代碼片段實現了此任務。
示例12-4在可觀察列表中定義表數據
final ObservableList<Person> data = FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),new Person("Isabella", "Johnson", "isabella.johnson@example.com"),new Person("Ethan", "Williams", "ethan.williams@example.com"),new Person("Emma", "Jones", "emma.jones@example.com"),new Person("Michael", "Brown", "michael.brown@example.com") );下一步是將數據與表列相關聯。您可以通過為每個數據元素定義的屬性執行此操作,如例12-5所示。
示例12-5將數據屬性設置為列
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("firstName") ); lastNameCol.setCellValueFactory(new PropertyValueFactory<Person,String>("lastName") ); emailCol.setCellValueFactory(new PropertyValueFactory<Person,String>("email") );該setCellValueFactory方法為每列指定單元工廠。的細胞工廠通過使用實現PropertyValueFactory類,它使用firstName,lastName和email所述表的列的特性作為對相應方法的引用Person類。
定義數據模型,并添加數據并與列關聯時,可以使用類的setItems方法將數據添加到表中TableView:table.setItems(data)。
由于該ObservableList對象可以跟蹤對其元素的任何更改,因此TableView只要數據發生更改,內容就會自動更新。
檢查例12-6中顯示的應用程序代碼。
示例12-6創建表并向其中添加數據
import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage;public class TableViewSample extends Application {private TableView<Person> table = new TableView<Person>();private final ObservableList<Person> data =FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),new Person("Isabella", "Johnson", "isabella.johnson@example.com"),new Person("Ethan", "Williams", "ethan.williams@example.com"),new Person("Emma", "Jones", "emma.jones@example.com"),new Person("Michael", "Brown", "michael.brown@example.com"));public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) {Scene scene = new Scene(new Group());stage.setTitle("Table View Sample");stage.setWidth(450);stage.setHeight(500);final Label label = new Label("Address Book");label.setFont(new Font("Arial", 20));table.setEditable(true);TableColumn firstNameCol = new TableColumn("First Name");firstNameCol.setMinWidth(100);firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));TableColumn lastNameCol = new TableColumn("Last Name");lastNameCol.setMinWidth(100);lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));TableColumn emailCol = new TableColumn("Email");emailCol.setMinWidth(200);emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));table.setItems(data);table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);final VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(10, 0, 0, 10));vbox.getChildren().addAll(label, table);((Group) scene.getRoot()).getChildren().addAll(vbox);stage.setScene(scene);stage.show();}public static class Person {private final SimpleStringProperty firstName;private final SimpleStringProperty lastName;private final SimpleStringProperty email;private Person(String fName, String lName, String email) {this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}public String getFirstName() {return firstName.get();}public void setFirstName(String fName) {firstName.set(fName);}public String getLastName() {return lastName.get();}public void setLastName(String fName) {lastName.set(fName);}public String getEmail() {return email.get();}public void setEmail(String fName) {email.set(fName);}} }編譯并運行此應用程序代碼時,將顯示如圖12-4所示的表。
圖12-4填充數據的表
?
添加新行
圖12-4中的表包含五行數據,到目前為止無法修改。
您可以使用文本字段在“名字”,“姓氏”和“電子郵件”列中輸入新值?!?文本字段”控件使您的應用程序可以接收來自用戶的文本輸入。例12-7創建了三個文本字段,定義了每個字段的提示文本,并創建了Add按鈕。
示例12-7使用文本字段在表中輸入新項
final TextField addFirstName = new TextField(); addFirstName.setPromptText("First Name"); addFirstName.setMaxWidth(firstNameCol.getPrefWidth()); final TextField addLastName = new TextField(); addLastName.setMaxWidth(lastNameCol.getPrefWidth()); addLastName.setPromptText("Last Name"); final TextField addEmail = new TextField(); addEmail.setMaxWidth(emailCol.getPrefWidth()); addEmail.setPromptText("Email");final Button addButton = new Button("Add"); addButton.setOnAction(new EventHandler<ActionEvent>() {@Override public void handle(ActionEvent e) {data.add(new Person(addFirstName.getText(),addLastName.getText(),addEmail.getText()));addFirstName.clear();addLastName.clear();addEmail.clear();} });當用戶單擊“添加”按鈕時,在文本字段中輸入的值將包含在Person構造函數中并添加到data可觀察列表中。因此,帶有聯系信息的新條目將顯示在表格中。
檢查例12-8中顯示的應用程序代碼。
示例12-8包含要輸入新項的文本字段的表
import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage;public class FileChooserSample extends Application {private TableView<Person> table = new TableView<Person>();private final ObservableList<Person> data =FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),new Person("Isabella", "Johnson", "isabella.johnson@example.com"),new Person("Ethan", "Williams", "ethan.williams@example.com"),new Person("Emma", "Jones", "emma.jones@example.com"),new Person("Michael", "Brown", "michael.brown@example.com"));final HBox hb = new HBox();public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) {Scene scene = new Scene(new Group());stage.setTitle("Table View Sample");stage.setWidth(450);stage.setHeight(550);final Label label = new Label("Address Book");label.setFont(new Font("Arial", 20));table.setEditable(true);TableColumn firstNameCol = new TableColumn("First Name");firstNameCol.setMinWidth(100);firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));TableColumn lastNameCol = new TableColumn("Last Name");lastNameCol.setMinWidth(100);lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));TableColumn emailCol = new TableColumn("Email");emailCol.setMinWidth(200);emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));table.setItems(data);table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);final TextField addFirstName = new TextField();addFirstName.setPromptText("First Name");addFirstName.setMaxWidth(firstNameCol.getPrefWidth());final TextField addLastName = new TextField();addLastName.setMaxWidth(lastNameCol.getPrefWidth());addLastName.setPromptText("Last Name");final TextField addEmail = new TextField();addEmail.setMaxWidth(emailCol.getPrefWidth());addEmail.setPromptText("Email");final Button addButton = new Button("Add");addButton.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent e) {data.add(new Person(addFirstName.getText(),addLastName.getText(),addEmail.getText()));addFirstName.clear();addLastName.clear();addEmail.clear();}});hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);hb.setSpacing(3);final VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(10, 0, 0, 10));vbox.getChildren().addAll(label, table, hb);((Group) scene.getRoot()).getChildren().addAll(vbox);stage.setScene(scene);stage.show();}public static class Person {private final SimpleStringProperty firstName;private final SimpleStringProperty lastName;private final SimpleStringProperty email;private Person(String fName, String lName, String email) {this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}public String getFirstName() {return firstName.get();}public void setFirstName(String fName) {firstName.set(fName);}public String getLastName() {return lastName.get();}public void setLastName(String fName) {lastName.set(fName);}public String getEmail() {return email.get();}public void setEmail(String fName) {email.set(fName);}} }此應用程序不提供任何過濾器來檢查,例如,是否以錯誤的格式輸入了電子郵件地址。您可以在開發自己的應用程序時提供此類功能。
當前實現也不檢查以確定是否輸入空值。如果未提供任何值,則單擊“添加”按鈕會在表中插入一個空行。
圖12-5演示了用戶如何添加新行數據。
圖12-5將通訊錄添加到通訊簿
圖12-6顯示了單擊“添加”按鈕后的表格。Emma White的聯系方式現已顯示在表格中。
圖12-6新增條目
?
按列排序數據
該TableView級提供了內置的功能來在列中的數據進行排序。用戶可以通過單擊列標題來更改數據的順序。第一次單擊啟用升序排序,第二次單擊啟用降序排序,第三次單擊禁用排序。默認情況下,不應用排序。
用戶可以對表中的多個列進行排序,并在排序操作中指定每個列的優先級。要對多個列進行排序,用戶在單擊要排序的每個列的標題時按Shift鍵。
在圖12-7中,升序排序順序應用于名字,而姓氏則按降序排序。請注意,第一列優先于第二列。
圖12-7排序多列
作為應用程序開發人員,您可以通過應用該setSortType方法為應用程序中的每個列設置排序首選項。您可以指定升序和降序類型。例如,使用以下代碼行為emailCol列設置降序排序類型:emailCol.setSortType(TableColumn.SortType.DESCENDING);。
您還可以通過TableColumn在TableView.sortOrder可觀察列表中添加和刪??除實例來指定要排序的列。此列表中的列順序表示排序優先級(例如,零項的優先級高于第一項)。
要禁止對數據進行排序,請setSortable(false)在列上調用該方法。
?
編輯表格中的數據
將TableView不僅呈現類的表格數據,但它也提供了一些功能來編輯它。使用此setEditable方法可以編輯表格內容。
使用該setCellFactory方法在TextFieldTableCell類的幫助下將表格單元格重新實現為文本字段。該setOnEditCommit方法處理編輯并將更新的值分配給相應的表格單元格。示例12-9顯示了如何應用這些方法來處理名字,姓氏和電子郵件列中的單元格編輯。
示例12-9實現單元格編輯
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn()); firstNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue());}} );lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn()); lastNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setLastName(t.getNewValue());}} );emailCol.setCellFactory(TextFieldTableCell.forTableColumn()); emailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setEmail(t.getNewValue());}} );示例12-10中顯示的應用程序的完整代碼。
示例12-10具有啟用單元格編輯的TableViewSample
import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn.CellEditEvent; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage;public class TableViewSample extends Application {private TableView<Person> table = new TableView<Person>();private final ObservableList<Person> data =FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),new Person("Isabella", "Johnson", "isabella.johnson@example.com"),new Person("Ethan", "Williams", "ethan.williams@example.com"),new Person("Emma", "Jones", "emma.jones@example.com"),new Person("Michael", "Brown", "michael.brown@example.com"));final HBox hb = new HBox();public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) {Scene scene = new Scene(new Group());stage.setTitle("Table View Sample");stage.setWidth(450);stage.setHeight(550);final Label label = new Label("Address Book");label.setFont(new Font("Arial", 20));table.setEditable(true);TableColumn firstNameCol = new TableColumn("First Name");firstNameCol.setMinWidth(100);firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());firstNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue());}});TableColumn lastNameCol = new TableColumn("Last Name");lastNameCol.setMinWidth(100);lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());lastNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setLastName(t.getNewValue());}});TableColumn emailCol = new TableColumn("Email");emailCol.setMinWidth(200);emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));emailCol.setCellFactory(TextFieldTableCell.forTableColumn());emailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setEmail(t.getNewValue());}});table.setItems(data);table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);final TextField addFirstName = new TextField();addFirstName.setPromptText("First Name");addFirstName.setMaxWidth(firstNameCol.getPrefWidth());final TextField addLastName = new TextField();addLastName.setMaxWidth(lastNameCol.getPrefWidth());addLastName.setPromptText("Last Name");final TextField addEmail = new TextField();addEmail.setMaxWidth(emailCol.getPrefWidth());addEmail.setPromptText("Email");final Button addButton = new Button("Add");addButton.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent e) {data.add(new Person(addFirstName.getText(),addLastName.getText(),addEmail.getText()));addFirstName.clear();addLastName.clear();addEmail.clear();}});hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);hb.setSpacing(3);final VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(10, 0, 0, 10));vbox.getChildren().addAll(label, table, hb);((Group) scene.getRoot()).getChildren().addAll(vbox);stage.setScene(scene);stage.show();}public static class Person {private final SimpleStringProperty firstName;private final SimpleStringProperty lastName;private final SimpleStringProperty email;private Person(String fName, String lName, String email) {this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}public String getFirstName() {return firstName.get();}public void setFirstName(String fName) {firstName.set(fName);}public String getLastName() {return lastName.get();}public void setLastName(String fName) {lastName.set(fName);}public String getEmail() {return email.get();}public void setEmail(String fName) {email.set(fName);}} }在圖12-8中,用戶正在編輯Michael Brown的姓氏。要編輯表格單元格,用戶在單元格中輸入新值,然后按Enter鍵。在按下Enter鍵之前,不會修改單元格。此行為由TextField類的實現決定。
圖12-8編輯表格單元格
請注意,TextField控件的默認實現要求用戶按Enter鍵提交編輯。您可以重新定義TextField行為以在焦點更改上提交編輯,這是預期的用戶體驗。嘗試修改代碼來實現這樣的替代行為。
例12-11細胞編輯的替代解決方案
import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn.CellEditEvent; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage; import javafx.util.Callback;public class TableViewSample extends Application {private TableView<Person> table = new TableView<Person>();private final ObservableList<Person> data =FXCollections.observableArrayList(new Person("Jacob", "Smith", "jacob.smith@example.com"),new Person("Isabella", "Johnson", "isabella.johnson@example.com"),new Person("Ethan", "Williams", "ethan.williams@example.com"),new Person("Emma", "Jones", "emma.jones@example.com"),new Person("Michael", "Brown", "michael.brown@example.com"));final HBox hb = new HBox();public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) {Scene scene = new Scene(new Group());stage.setTitle("Table View Sample");stage.setWidth(450);stage.setHeight(550);final Label label = new Label("Address Book");label.setFont(new Font("Arial", 20));table.setEditable(true);Callback<TableColumn, TableCell> cellFactory =new Callback<TableColumn, TableCell>() {public TableCell call(TableColumn p) {return new EditingCell();}};TableColumn firstNameCol = new TableColumn("First Name");firstNameCol.setMinWidth(100);firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));firstNameCol.setCellFactory(cellFactory);firstNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setFirstName(t.getNewValue());}});TableColumn lastNameCol = new TableColumn("Last Name");lastNameCol.setMinWidth(100);lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));lastNameCol.setCellFactory(cellFactory);lastNameCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setLastName(t.getNewValue());}});TableColumn emailCol = new TableColumn("Email");emailCol.setMinWidth(200);emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));emailCol.setCellFactory(cellFactory);emailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {@Overridepublic void handle(CellEditEvent<Person, String> t) {((Person) t.getTableView().getItems().get(t.getTablePosition().getRow())).setEmail(t.getNewValue());}});table.setItems(data);table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);final TextField addFirstName = new TextField();addFirstName.setPromptText("First Name");addFirstName.setMaxWidth(firstNameCol.getPrefWidth());final TextField addLastName = new TextField();addLastName.setMaxWidth(lastNameCol.getPrefWidth());addLastName.setPromptText("Last Name");final TextField addEmail = new TextField();addEmail.setMaxWidth(emailCol.getPrefWidth());addEmail.setPromptText("Email");final Button addButton = new Button("Add");addButton.setOnAction(new EventHandler<ActionEvent>() {@Overridepublic void handle(ActionEvent e) {data.add(new Person(addFirstName.getText(),addLastName.getText(),addEmail.getText()));addFirstName.clear();addLastName.clear();addEmail.clear();}});hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);hb.setSpacing(3);final VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(10, 0, 0, 10));vbox.getChildren().addAll(label, table, hb);((Group) scene.getRoot()).getChildren().addAll(vbox);stage.setScene(scene);stage.show();}public static class Person {private final SimpleStringProperty firstName;private final SimpleStringProperty lastName;private final SimpleStringProperty email;private Person(String fName, String lName, String email) {this.firstName = new SimpleStringProperty(fName);this.lastName = new SimpleStringProperty(lName);this.email = new SimpleStringProperty(email);}public String getFirstName() {return firstName.get();}public void setFirstName(String fName) {firstName.set(fName);}public String getLastName() {return lastName.get();}public void setLastName(String fName) {lastName.set(fName);}public String getEmail() {return email.get();}public void setEmail(String fName) {email.set(fName);}}class EditingCell extends TableCell<Person, String> {private TextField textField;public EditingCell() {}@Overridepublic void startEdit() {if (!isEmpty()) {super.startEdit();createTextField();setText(null);setGraphic(textField);textField.selectAll();}}@Overridepublic void cancelEdit() {super.cancelEdit();setText((String) getItem());setGraphic(null);}@Overridepublic void updateItem(String item, boolean empty) {super.updateItem(item, empty);if (empty) {setText(null);setGraphic(null);} else {if (isEditing()) {if (textField != null) {textField.setText(getString());}setText(null);setGraphic(textField);} else {setText(getString());setGraphic(null);}}}private void createTextField() {textField = new TextField(getString());textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);textField.focusedProperty().addListener(new ChangeListener<Boolean>(){@Overridepublic void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {if (!arg2) {commitEdit(textField.getText());}}});}private String getString() {return getItem() == null ? "" : getItem().toString();}} }請注意,隨著TextFieldTableCell實現的發展,這種方法在將來的版本中可能會變得多余,以提供更好的用戶體驗。
?
將數據映射添加到表中
啟動JavaFX SDK 2.2,您可以將Map數據添加到表中。使用示例12-12中MapValueFactory所示的類來顯示表中學生ID的映射。
示例12-12將映射數據添加到表中
import java.util.HashMap; import java.util.Map; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.MapValueFactory; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.stage.Stage; import javafx.util.Callback; import javafx.util.StringConverter;public class TableViewSample extends Application {public static final String Column1MapKey = "A";public static final String Column2MapKey = "B";public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage stage) {Scene scene = new Scene(new Group());stage.setTitle("Table View Sample");stage.setWidth(300);stage.setHeight(500);final Label label = new Label("Student IDs");label.setFont(new Font("Arial", 20));TableColumn<Map, String> firstDataColumn = new TableColumn<>("Class A");TableColumn<Map, String> secondDataColumn = new TableColumn<>("Class B");firstDataColumn.setCellValueFactory(new MapValueFactory(Column1MapKey));firstDataColumn.setMinWidth(130);secondDataColumn.setCellValueFactory(new MapValueFactory(Column2MapKey));secondDataColumn.setMinWidth(130);TableView table_view = new TableView<>(generateDataInMap());table_view.setEditable(true);table_view.getSelectionModel().setCellSelectionEnabled(true);table_view.getColumns().setAll(firstDataColumn, secondDataColumn);Callback<TableColumn<Map, String>, TableCell<Map, String>>cellFactoryForMap = new Callback<TableColumn<Map, String>,TableCell<Map, String>>() {@Overridepublic TableCell call(TableColumn p) {return new TextFieldTableCell(new StringConverter() {@Overridepublic String toString(Object t) {return t.toString();}@Overridepublic Object fromString(String string) {return string;} });}};firstDataColumn.setCellFactory(cellFactoryForMap);secondDataColumn.setCellFactory(cellFactoryForMap);final VBox vbox = new VBox();vbox.setSpacing(5);vbox.setPadding(new Insets(10, 0, 0, 10));vbox.getChildren().addAll(label, table_view);((Group) scene.getRoot()).getChildren().addAll(vbox);stage.setScene(scene);stage.show();}private ObservableList<Map> generateDataInMap() {int max = 10;ObservableList<Map> allData = FXCollections.observableArrayList();for (int i = 1; i < max; i++) {Map<String, String> dataRow = new HashMap<>();String value1 = "A" + i;String value2 = "B" + i;dataRow.put(Column1MapKey, value1);dataRow.put(Column2MapKey, value2);allData.add(dataRow);}return allData;} }的MapValueFactory類實現Callback接口,并且它是專門設計用于表的列的細胞工廠內使用。在示例12-12中,dataRow哈希映射在TableView對象中顯示單個行。該映射有兩個String鍵:Column1MapKey和Column2MapKey,用于映射第一列和第二列中的相應值。setCellValueFactory調用表列的方法使用與特定鍵匹配的數據填充它們,以便第一列包含與“A”鍵對應的值,第二列包含與“B”鍵對應的值。
編譯并運行此應用程序時,它會生成如圖12-9所示的輸出。
圖12-9帶有地圖數據的TableVIew
?
相關的API文檔?
-
TableView
-
TableColumn
-
TableCell
-
TextField
-
TextFieldTableCell
-
MapValueFactory
-
Button
總結
以上是生活随笔為你收集整理的JavaFX UI控件教程(十三)之Table View的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鸿蒙系统是基于安卓吗
- 下一篇: JavaFX UI控件教程(十四)之Tr