JavaFX控件——TableView

article/2025/8/26 11:37:20

在JavaFX 应用中对创建表格最重要的是TableView, TableColumnTableCell这三个类。

你可以通过实现数据模型(data model) 和 实现 单元格工厂(cell factory) 来填充表格。

表格类提供了表格列嵌入式的排序能力和必要时调整列宽度的功能。
下面开始学习表格类的相关内容。

创建一个表格

例子1-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);  }  @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);  //设置自动拉满    table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);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类来创建。

在该例子中,表格组件被添加到VBox 的布局容器中,然而你也可以直接将其添加到应用场景中。

例子 12-1定义了3列将用来存放地址簿的信息:一个联系人的 姓和名以及电子邮箱地址。列通过TableColumn这个类创建。

TableViewgetColumns方法可以获取之前创建过的列。在你的应用中,你可以用此方法动态的添加和移除表格列。

编译并运行此程序将获取输入输出 ,结果如图所示:

你可以通过setVisible 方法来控制列是否显示。

如:如果你的应用逻辑需要隐藏电子邮件地址,可以这样做:emailCol.setVisible(false).
将这句代码添加到例子1-1中,效果如图:

如果你的数据需要更加复杂的呈现方式,你可以创建嵌套列
假设地址簿中的联系方式有两个电子邮箱账户。你需要两列来分别呈现第一个和第二个电子邮箱地址。
像下面代码中展示的一样,创建两个子列,然后调用emailColgetColumns方法

TableColumn firstEmailCol = new TableColumn("Primary");  
TableColumn secondEmailCol = new TableColumn("Secondary");  emailCol.getColumns().addAll(firstEmailCol, secondEmailCol);  

在这段代码里面添加到例子1-1中然后编译并运行, 此表格将呈现下图中的样子.
带有嵌套列的表格
尽管表格已经添加到应用中,但是因为表格中没有数据,标准的标题“表中无内容”(表格内容为空)将呈现在表格中。

如果不想显示上述标题,你可以使用setPlaceholder 方法类制定 一个 Node(节点)对象呈现在空表格中。

定义数据模型( Data Model)

当你要在JavaFx应用中创建一个表格,最好先创建一个类来定义数据模型和提供将来和表格交互的方法和属性。例子1-2中定义了Person类来定义数据和地址簿。

例字1-2 创建 Person 类

public 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这些字符串属性用来提供特殊数据元素的引用。

另外,每个数据元素都提供了getset方法。 这样如果调用 getFirstName方法经返回firstName属性的值,可以通过调用setFirstName方法来为这个属性赋值 。

在数据模型已经在Person 类中呈现以后。你可以创建ObservableList 数组随心所欲的定义数据行(data rows) 在你的表格中展示
下面的代码片段实现了这个任务:

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")  
); 

下一步就是将这些数据和表格的列之间建立联系。你可以像例子1-3中那样通过对每个数据元素的属性定义来实现。

例子1-3 为列创建数据属性

firstNameCol.setCellValueFactory(  new PropertyValueFactory<Person,String>("firstName")  
);  
lastNameCol.setCellValueFactory(  new PropertyValueFactory<Person,String>("lastName")  
);  
emailCol.setCellValueFactory(  new PropertyValueFactory<Person,String>("email")  
);  

setCellValueFactory 方法为每个列定制单元工厂。单元工程通过使用PropertyValueFactory类来实现, 表格列的firstName, lastNameemail 属性来引用Person中相应的属性的 。

当数据模型已经定义完毕,数据已经添加并关联到对应的列,你还可以通过TableViewsetItems 方法来添加表格数据:table.setItems(data).

因为ObservableList 对象能够跟踪表格元素的任何变化,当其中的数据变化,TableView 的内容也自动更新。

例子1-4 创建一个表格并添加数据

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

当你编译并运行此代码将呈现如下图的样子:
表格数据填充

添加新行

图标例子1-4中的表格包好5行数据,目前为止还不能编辑。

你可以用 文本域 为Last Name, and Email columns键入新值 Text Field 组件能够使你的应用接收到用户输入的文本。
例子1-5 将创建3个文本域。并为每个文本域定义提示并创建添加按钮。

例子1-5 利用文本域为表格创建新元素

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)中。因此带有内容信息的实体出现在表格中。
完整代码如下:

例子1-6 用文本域添加条目的表格

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

效果图如下:
用文本域添加条目的表格

此应用没有提供任何校验的过滤器,比如校验电子邮件格式是否正确。当你开发自己的应用时可以添加这些方法。

当前的应用也没有检查是否键入了空值,如果没有提供任何值,点击添加按钮将在表格中键入一个空行。

列数据排序

TableView类提供了列中数据的排序。用户可以通过点击列头来对数据进行排序。第一次点击将进行升序排列,第二次点击将进行降序排列。第三次点击不排列。默认是不排列

用户可以对表格的多列进行排序,同样也可以指定每列数据在排序操作中的优先级。如果想多行排列,用户按住Shift的同时点击想要排序的每一列的列头。

下面的图中, first names升序排列, last names降序排列.记住第一列比第二列的优先级更高
多列排序

作为应用的开发人员,你可以通过setSortType方法设置每一列的排序优先级。你可以分别指定升序和降序的排列规则,例如,用下面的代码来设置emailCol 降序的排序。列:emailCol.setSortType(TableColumn.SortType.DESCENDING);

表格的数据编辑

TableView类不仅能够渲染表格式的数据,还能提供编辑的能力。使用 setEditable 方法来开启表格编辑模式。

setCellFactory 方法,借助TextFieldTableCell的帮助来 重新实现表格单元格作为文本域。

setOnEditCommit 方法具有编辑 指派更新数据到相应表格单元格的能力。

例子1-7 显示怎样用这些方法来 编辑 First Name, Last Name, and Email列。

例子1-7 单元格编辑的实现

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

完整代码如下:

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

下图中,用户正在编辑Michael Brown的姓氏。用户键入在单元格中键入了新的值,然后暗下来 Enter键。只有按下了Enter键,单元格编辑才算结束。这一行为取决于TextField的实现。
编辑表格的单元格

请记住:默认的TextField 实现,需要用户按下Enter键来提交编辑。你可以重新定义TextField的行为来通过焦点变化提交编辑,这是一个好的用户体验。尝试修改代码来实现这个替代的行为。

例子1-8 单元编辑的替换方案

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的取代,提供了更好的而用户体验。

将Map数据添加到表格中

JavaFX SDK 2.2开始,你可以往表格中添加Map类型的数据。用如 例子1-9 展示的 利用MapValueFactory展示 student IDs Map;

例子1-9 往表格中添加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 接口,此接口为定义表格列的单元格工厂而设计的。在例子1-9中,数据行 hash map(哈希map) 展现了TableView对象的一个单行。这个map有两个String(字符串)类型的键: Column1MapKeyColumn2MapKey来映射第一和第二列对应的值。

表格列通过调用setCellValueFactory 来填充与指定键(key)相匹配的数据。以便第一列包含与”A“键(key)对应的值,第二列包含于key(键)”B“对应的值。

当你编译并运行此应用,将显示如图所显示的结果。
带Map数据的表格


http://chatgpt.dhexx.cn/article/fqr7p1ml.shtml

相关文章

ios开发:多个Section的TableView

开发多个Section的tableView。 首先应该考虑到数据源该如何得到 我们这里可以通过两种方式:第一种是读取plist文件。第二种是通过代码进行数据存储以及读取。 多个Section需要的数据源是一个字典&#xff0c;字典里的内容是一个数组。在plist文件中可以这样去创建 在.h文件中…

tableview概述

转自&#xff1a;http://www.cnblogs.com/smileEvday/archive/2012/06/28/tableView.html                 下面分9个方面进行介绍&#xff1a; 一、UITableView概述 UITableView继承自UIScrollView&#xff0c;可以表现为Plain和Grouped两种风格&#xff0c;分…

ios tableView那些事(一)创建一个简单的tableView

工作也有半年多了&#xff01;几乎每个项目中的会用到tableview这个神奇而好用的控件&#xff0c;在学习和工作中都会看别人的博客&#xff01;对我有很大的帮助&#xff0c;就如同站在巨人的肩膀上的感觉吧 哈哈&#xff01;于是决定重新开始写博客&#xff0c;希望能帮助像我…

JavaFX TableView和ListView的点击事件

项目场景&#xff1a; 最近在用JavaFX做一个简易的商城界面&#xff0c;大概想实现这样的功能&#xff1a; 左边显示用户的最近五个购买的产品 使用ListView 点击ListView的项目会定位到相应的tablerow位置 方便用户快速查找中间显示所有可用产品 使用TableView 双击tablerow…

JavaFX【TableView使用详解】

目录 概述 组件 Student ObservableList TableView setCellValueFactory() TableColumn 1. Callback 2. PropertyValueFactory 增加到末行 1、tableView.getItems().add(Student s) 2、list.add(Student s) 删除指定行 1、tableView.getItems().remove(int i) 2、…

QT中TableView数据展示

QT中TableView数据展示 最近在学习QT,大量数据从数据库取出放入QT界面中展示&#xff0c;这时用到了tableView&#xff0c;一些简单的使用分享给大家。 创建数据模型 QStandardItemModel *modelnew QStandardItemModel(); QStandardItemModel是Qt库中的一个类&#xff0c;它…

JAVAFX的TableView基本用法

JAVAFX中的表格显示主要使用TableView 与TableView相关的类: TableColumn TableRow TableCell TablePosition TableViewFocusModel TableViewSelectionModel JavaFX TableView例子: import javafx.application.Application; import javafx.scene.Scene; import javafx.scene…

QT之Tableview

想要了解更多的tableview可以看这位博客Qt深入浅出&#xff08;十五&#xff09;QTableView​ 这里做了一个简单的学生系统查询功能显示Tableview&#xff1a; 表格视图控件QTableView&#xff0c;需要和QStandardItemModel, 配套使用&#xff0c;这套框架是基于MVC设计模式设…

QML TableView 使用详解

目录 一、—个简单的TableView实例 二、TableViewColumn 属性讲解 三、定制表格外观 3.1 itemDelegate3.2 rowDelegate3.3 headerDelegate3.4 定制表格外观后的示例 四、动态增删改查 TabelView TableView 就是 Qt Quick 为表格式呈现数据提供的组件。想必兄台用过 Excel…

QT控件之(TableView)的居中效果

T将tableView中的表头以及文本内容都进行居中处理 1、需要在构造函数中增加一句&#xff1a; //以下增加的是表头的效果 ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//布局排版是全部伸展开的效果2、就是直接对tableView的文本内…

QML学习十七:TableView的简单使用

若该文为原创文章&#xff0c;转载请注明原文出处 一、TableView TableView是Qt Quick为表格式呈现数据提供的组件。 TableView与ListView类似&#xff0c;相比之下多了滚动条、挑选、可调整尺寸的表头等特性&#xff0c;数据也是通过Model来提供&#xff0c;此篇使用的是内建…

JavaFX中TableView的使用

稍微说说JavaFX里面TableView怎么用&#xff0c;&#xff08;其实在JavaFX的源码中都有示例。。。&#xff09; 首先要了解TableView是用来做什么的&#xff0c;TableView是JavaFX的一个表视图&#xff0c;用来显示表格的&#xff0c;在TableView的类注释中写了 /*** see Tab…

Qt4实现TableView显示表格数据

最近又开始搞QT开发了&#xff0c;前面学的MVC啥的都忘得差不多了&#xff0c;重新整理一遍思路吧。 目前的需求是&#xff1a;读取文本文件&#xff0c;表格型数据&#xff0c;用tableview显示出来&#xff0c;最后画图。这涉及到三个问题&#xff0c;文件读写&#xff0c;数…

NAT模式下的虚拟机网络配置

原理 NAT模式&#xff0c;也叫地址转换模式&#xff0c; 当把我们的虚拟机的上网方式设置为NAT模式时&#xff0c;虚拟机、宿主机、各网卡之间的连接关系可用下图来表示&#xff1a; 具体配置流程 1 将本地以太网共享到v8适配器上 2 查看虚拟网络编辑中的NAT模式下的子网IP…

虚拟机vmware设置nat模式上网

桥接模式上网&#xff1a;虚拟机vmware设置桥接模式上网_cao849861802的博客-CSDN博客 首先虚拟机有两个虚拟网卡vmnet0和vmnet8 这个vmnet0默认的是桥接模式&#xff0c;这个vmnet8默认是nat模式&#xff1b; 我们这里只看nat模式&#xff0c;所以先不关心vmnet0虚拟网卡&a…

VMware16NAT模式配置固定IP

文章目录 前言一、NAT配置固定IP二、重启网卡结尾 前言 为什么要配置固定IP呀&#xff1f;这个很容易解释啊&#xff0c;因为配置集群要设置固定IP&#xff08;主结点需要管理子结点&#xff0c;通过固定IP识别机器&#xff09;&#xff0c;因为你访问虚拟机方便&#xff08;不…

VMware Workstation中桥接模式、NAT模式、仅主机模式

一、VMware虚拟机的网络模式 VMware工作站虚拟机有三种网络模式【①桥接模式 ②NAT模式 ③仅主机模式】,如下图所示: 二、VMware虚拟机的网络模式介绍 2.0、VMware的虚拟设备 VMware的虚拟设备 序号虚拟设备编号说明1VMnet0是虚拟桥接网络下的虚拟交换机2VMnet1是虚拟Host-…

vm虚拟机nat模式配置

痛点&#xff1a; 为了解决虚拟机与板子网络的调试的问题&#xff0c;我之前一直用桥接&#xff0c;如果虚拟机想上网就桥接到无线网卡&#xff0c;如果想连接板子&#xff0c;就桥接到有线网卡&#xff0c;麻烦&#xff0c;需要来回切换&#xff0c;还有就是不插板子的情况下和…

nat模式

原文链接&#xff1a;https://www.linuxidc.com/Linux/2016-09/135521p2.htm &#xff08;复制过来只是为了学习方便&#xff0c;如有不妥会立即删除&#xff09; 二、NAT&#xff08;地址转换模式&#xff09; 刚刚我们说到&#xff0c;如果你的网络ip资源紧缺&#xff0c;但…

虚拟机NAT模式无法联网

工作中遇到NAT模式虚拟机&#xff0c;修改了编辑-虚拟网络编辑器 中NAT设置IP&#xff0c;DNS&#xff0c;DHCP等配置&#xff0c;在centos8中修改了ens33文件都无法联网的情况&#xff0c;特此总结解决方案 按照该方法尝试后无效&#xff08;解决方法在下面&#xff09; 第一…