原文链接地址:http://docs.oracle.com/javafx/2/ui_controls/table-view.htm#CJAGAAEE
在这一章,你将学习如:添加一个表格表、数据填充、编辑表格行等格组件 JavaFx的基本操作。
很多JavaFX SDK API种的类为在表格表单中呈现数据。在JavaFX 应用中对创建表格最重要的是TableView
, TableColumn
和TableCell这三个类。
你可以通过实现数据模型(data model) 和 实现 单元格工厂(cell
factory) 来填充表格。
表格类提供了表格列嵌入式的排序能力和必要时调整列宽度的功能。
表格12-1 展示了一个呈现地址簿信息内容的典型的表格
表格 12-1 表格示例
例子12-1表格片段 创建了一个3列的空表格并添加到应用场景中
Example 12-1 Adding a Table 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); } @Override public 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定义了3列将用来存放地址簿的信息:一个联系人的 姓和名以及电子邮箱地址。列通过TableColumn这个类创建。
TableView
的getColumns方法可以获取之前创建过的列。在你的应用中,你可以用此方法动态的添加和移除表格列。
编译并运行此程序将获取输入输出,如图12-2所示:
你可以通过setVisible
方法来控制列是否显示。
如:如果你的应用逻辑需要隐藏电子邮件地址,不可以这样做:emailCol.setVisible(false)
.
如果你的数据需要更加复杂的呈现方式,你可以创建嵌套列。
假设地址簿中的联系方式有两个电子邮箱账户。你需要两列来分别呈现第一个和第二个电子邮箱地址。
像例12-2中展示的一样,创建两个子列,然后调用emailCol
的getColumns方法
Example 12-2 Creating Nested Columns TableColumn firstEmailCol = new TableColumn("Primary"); TableColumn secondEmailCol = new TableColumn("Secondary"); emailCol.getColumns().addAll(firstEmailCol, secondEmailCol);
在例 12-1的代码里面添加上述代码然后编译并运行, 此表格将呈现图 12-3中的样子.
图12-3 带有嵌套列的表格
尽管表格已经添加到应用中,但是因为表格中没有数据,标准的标题“No content in table”(表格内容为空)将呈现在表格中。
如果不想显示上述标题,你可以使用setPlaceholder 方法类制定 一个 Node(节点)对象呈现在空表格中。
表格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
数组随心所欲的定义数据行(data
rows) 在你的表格中展示
例12-4 的代码片段实现了这个任务:
Example 12-4 Defining Table Data in an Observable List
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中相应的属性的 。
当数据模型已经定义完毕,数据已经添加并关联到对应的列,你还可以通过TableView 的setItems
方法来添加表格数据::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); } @Override public 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中的表格包好5行数据,目前为止还不能编辑。
你可以用 文本域 为Last Name, and Email columns键入新值 Text Field 组件能够使你的应用接收到用户输入的文本。例12-7 创建3个文本域。并为每个文本域定义提示并创建添加按钮。
例
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 (observable list)中。因此带有内容信息的实体出现在表格中。
验证例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); } @Override public 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>() { @Override public 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 的详细联系方式出现在了表格中。
TableView类提供了列中数据的排序。用户可以通过点击列头来对数据进行排序。第一次点击将进行升序排列,第二次点击将进行降序排列。第三次点击不排列。默认是不排列。
用户可以对表格的多列进行排序,同样也可以指定每列数据在排序操作中的优先级。如果想多行排列,用户按住Shift的同时点击想要排序的每一列的列头。
图12-7中, first names升序排列, last names降序排列.记住第一列比第二列的优先级更高。
作为应用的开发人员,你可以通过setSortType方法设置每一列的排序优先级。你可以分别指定升序和降序的排列规则,例如,用下面的代码来设置emailCol 降序的排序。列:emailCol.setSortType(TableColumn.SortType.DESCENDING);
.
你可以指定哪一行排序 通过添加和移除
来制定哪些列排序。TableView.sortOrder
observable
list. TableColumn实例
列的顺序代表排序的优先级(例如,0条比第1条更高)。
如果想禁用排序 调用 列的setSortable(false)
方法即可。
TableView类不仅能够渲染表格式的数据,还能提供编辑的能力。使用 setEditable
方法来开启表格编辑模式。
用 setCellFactory
方法,借助TextFieldTableCell的帮助来
重新实现表格单元格作为文本域。
setOnEditCommit
方法具有编辑
指派更新数据到相应表格单元格的能力。
例12-9 显示怎样用这些方法来 编辑 First Name, Last Name, and Email列。
例 12-9单元格编辑的实现
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn()); firstNameCol.setOnEditCommit( new EventHandler<CellEditEvent<Person, String>>() { @Override public 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>>() { @Override public 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>>() { @Override public void handle(CellEditEvent<Person, String> t) { ((Person) t.getTableView().getItems().get( t.getTablePosition().getRow()) ).setEmail(t.getNewValue()); } } );例 12-10将展示完整的代码
例 12-10 允许单元格编辑的表格示例
<pre name="code" class="java">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); } @Override public 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>>() { @Override public 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>>() { @Override public 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>>() { @Override public 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>() { @Override public 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编辑表格的单元格
请记住:默认的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); } @Override public 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>>() { @Override public 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>>() { @Override public 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>>() { @Override public 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>() { @Override public 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() { } @Override public void startEdit() { if (!isEmpty()) { super.startEdit(); createTextField(); setText(null); setGraphic(textField); textField.selectAll(); } } @Override public void cancelEdit() { super.cancelEdit(); setText((String) getItem()); setGraphic(null); } @Override public 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>(){ @Override public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) { if (!arg2) { commitEdit(textField.getText()); } } }); } private String getString() { return getItem() == null ? "" : getItem().toString(); } }
记住这种处理方式可能会在未来的升级中变得多余,TextFieldTableCell 的实现对TextField的取代,提供了更好的而用户体验。
从JavaFX SDK 2.2开始,你可以往表格中添加Map类型的数据。用如 例 12-12 展示的 利用MapValueFactory展示 student IDs Map;
例 12-12 往表格中添加Map数据
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); } @Override public 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>>() { @Override public TableCell call(TableColumn p) { return new TextFieldTableCell(new StringConverter() { @Override public String toString(Object t) { return t.toString(); } @Override public 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中,数据行 hash map(哈希map) 展现了TableView对象的一个单行。这个map有两个String(字符串)类型的键: Column1MapKey
和 Column2MapKey来映射第一和第二列对应的值。
表格列通过调用setCellValueFactory
来填充与指定键(key)相匹配的数据。以便第一列包含与”A“键(key)对应的值,第二列包含于key(键)”B“对应的值。
当你编译并运行此应用,将显示如12-9所显示的结果。
图 12-9 带 Map 数据的表格
Using JavaFX UI Controls 12 Table View
原文地址:http://blog.csdn.net/w605283073/article/details/46475167