JavaFX UI控件教程(十三)之Table View

翻译自  Table View

在本章中,您将学习如何使用JavaFX应用程序中的表执行基本操作,例如添加表,使用数据填充表以及编辑表行。

JavaFX SDK API中的几个类旨在以表格形式表示数据。用于创建JavaFX应用程序表中的最重要的类是TableViewTableColumnTableCell。您可以通过实现数据模型和应用单元工厂来填充表。

表类提供了内置功能,可以对列中的数据进行排序,并在必要时调整列的大小。

图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);}}

firstNamelastNameemail串属性的设置是为了使一个特定的数据元素的引用。

另外,为每个数据元素提供getset方法。因此,例如,该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类,它使用firstNamelastNameemail所述表的列的特性作为对相应方法的引用Person类。

定义数据模型,并添加数据并与列关联时,可以使用类的setItems方法将数据添加到表中TableViewtable.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);

您还可以通过TableColumnTableView.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Boostrap技能点整理之【bootstrap简介】

bootstrap&#xff0c;目前市面上最受欢迎HTML、CSS、JavaScript框架&#xff0c;用于开发响应式布局、移动设备优先的 WEB 项目。从今天起&#xff0c;我们就开始整理bootstrap的相关技能点。1什么是 Bootstrap呢&#xff1f;Bootstrap 是最受欢迎的 HTML、CSS 和 JS 框架&…

asp.net core mvc中如何把二级域名绑定到特定的控制器上

由于公司的工作安排&#xff0c;一直在研究其他技术&#xff0c;所以一直没时间更新博客&#xff0c;今天终于可以停下手头的事情&#xff0c;写一些新内容了。 应用场景&#xff1a;企业门户网站会根据内容不同&#xff0c;设置不同的板块&#xff0c;如新浪有体育&#xff0c…

Boostrap技能点整理之【网格系统】

今天我们来串串bootstrap总的网格系统&#xff0c;说到网格系统&#xff0c;依稀记得当时教程上不叫网格&#xff0c;而叫栅格&#xff0c;我总觉得这个栅(shān )读起来不得劲&#xff0c;就读他的另一个音&#xff0c;栅&#xff08;zh&#xff09;格&#xff0c;每次遇到就读…

JavaFX UI控件教程(十四)之Tree View

翻译自 Tree View 在本章中&#xff0c;您将学习如何在JavaFX应用程序中构建树结构&#xff0c;向树视图添加项&#xff0c;处理事件以及通过实现和应用单元工厂来自定义树单元。 包的TreeView类javafx.scene.control提供了层次结构的视图。在每个树中&#xff0c;层次结构…

ASP.NET Core 指定环境发布(hosting environment)

ASP.NET Core 应用程序发布命令&#xff1a; dotnet publish [<PROJECT>] [-f|--framework] [-r|--runtime] [-o|--output] [-c|--configuration] [--version-suffix] [-v|--verbosity] [-h|--help] 发布示例命令&#xff08;生成在bin/release/netcoreapp1.1/publish目…

求素数为什么到平方根就行了

package com.wdl.day05;/* 100000以内的所有质数的输出。实现方式一 质数&#xff1a;素数&#xff0c;只能被1和它本身整除的自然数。-->从2开始&#xff0c;到这个数-1结束为止&#xff0c;都不能被这个数本身整除。对PrimeNumberTest.java文件中质数输出问题的优化 */ pu…

JavaFX UI控件教程(十五)之Combo Box

翻译自 Combo Box 本章介绍如何在JavaFX应用程序中使用组合框。它讨论了可编辑和不可编辑的组合框&#xff0c;教您如何跟踪可编辑组合框中的更改并处理它们上的事件&#xff0c;并解释如何使用单元工厂来更改组合框的默认实现。 组合框是用户界面的典型元素&#xff0c;使…

Boostrap技能点整理之【按钮样式】

昨天我们看了看bootstrap的网&#xff08;栅&#xff09;格系统&#xff0c;想必都对bootstrap网格系统有个大致的了解&#xff0c;今天我们再来看看bootstrap的按钮组合。按钮的样式在boostrap中&#xff0c;任何带有 class .btn 的元素都会继承圆角灰色按钮的默认外观。但是 …

MyBatis中的缓存

01 Mybatis中的缓存简介 缓存的好处&#xff1a;只是查询才有缓存 &#xff08;增删改没有缓存的&#xff09;&#xff0c;可以增块访问的速度 sqlsession级缓存 &#xff08;一级缓存&#xff09; 默认开启的 所有的操作是公用同一个SQLsession对象并且执行的是同一条SQL语句的…

基于VS2017的Docker Support体检ASP.NET Core站点的Docker部署

最近在学习如何用 Docker 部署生产环境中的 ASP.NET Core 站点&#xff0c;作为一个 Docer 新手&#xff0c;从何处下手更容易入门呢&#xff1f;一开始就手写 Docker 配置文件&#xff08;Docfile, docker-compose.yml&#xff09;容易让人产生挫败感&#xff0c;想到 Visual …

JavaFX UI控件教程(十六)之Separator

翻译自 Separator 本章介绍如何使用分隔符组织JavaFX应用程序的UI组件。 SeparatorJavaFX API中可用的类表示水平或垂直分隔线。它用于划分应用程序用户界面的元素&#xff0c;不会产生任何操作。但是&#xff0c;您可以设置样式&#xff0c;对其应用视觉效果&#xff0c;甚…

eclipse下载与安装步骤详解,包含解决错误(最全最详细,多图)

以前一直用的是myeclipse,今天有幸接触eclipse,那我们就先来安装的配置一下&#xff0c;下载地址&#xff1a;公众号中回复常用软件下载&#xff0c;下载完成以后就可以安装了&#xff0c;首先我们来先安装jdk1.7,打开jdk的安装包双击即可&#xff0c;直接点击下一步&#xff1…

微软中国Azure开源开发者(深圳)研讨会

时间&#xff1a;2017年6月28日 地点&#xff1a;深圳福田香格里拉大酒店 微软开发技术与云平台自从迈向开放、开源、跨平台的转型以来&#xff0c;已经受到全球开源社区们的关注。从Github 上高居世界首位的开源项目贡献数量&#xff0c;可以看到微软贯彻开源战略的实际行动。…

JavaFX UI控件教程(十七)之Slider

翻译自 Slider 在本章中&#xff0c;您将学习如何在JavaFX应用程序中使用滑块来显示和与一系列数值进行交互。 该Slider控件由一个轨道和一个可拖动的拇指组成。它还可以包括刻度线和刻度标签&#xff0c;用于指示范围的数值。图16-1显示了一个典型的滑块并指出了它的主要元…

Photoshop中将图片拖不进软件的编辑区的解决方法,超详细

今天在学习ps的过程中&#xff0c;发现我的ps怎么和人家老师的不一样&#xff0c;怎么不一样呢&#xff1f;人家老师的ps5中&#xff0c;鼠标可以直接拖到ps的编辑栏中&#xff0c;可是我的死活拖不进去。怎么办&#xff1f;怎么办&#xff1f;经过自己瞎鼓捣和上网查&#xff…

IdentityServer4 指定角色授权(Authorize(Roles=amp;quot;adminamp;quot;))

1. 业务场景 IdentityServer4 授权配置Client中的AllowedScopes&#xff0c;设置的是具体的 API 站点名字&#xff0c;也就是使用方设置的ApiName&#xff0c;示例代码&#xff1a; //授权中心配置new Client{ ClientId "client_id_1", AllowedGrantTypes G…

JavaFX UI控件教程(十八)之Progress Bar和Progress Indicator

翻译自 Progress Bar and Progress Indicator 在本章中&#xff0c;您将了解进度指示器和进度条&#xff0c;以及可视化JavaFX应用程序中任何操作进度的UI控件。 本ProgressIndicator类及其直接子类ProgressBar所提供的功能&#xff0c;以表明特定的任务是处理和检测是如何工…

你不知道ADo.Net中操作数据库的步骤【超详细整理】

1.先创建数据库连接字符串&#xff1a; string strcon "Data Source.;Initial CatalogschoolDB;Integrated SecurityTrue";2.创建SqlConnection对象&#xff0c;需要注意的是SqlConnection对象在using System.Data.SqlClient;命名空间中。 SqlConnection conn new…

C# 7.2和8.0路线图

C# 7.2和8.0的许多新功能已经列入了计划&#xff0c;其中包括空引用类型和有限形式的多重继承。 只读引用和只读结构体 [7.2原型] 首先提到的是只读引用和结构体。简单来讲&#xff0c;这项特性使得C#能够使用类似const的参数来提高性能。像我们所知道的“ref只读参数”和简单…