如何构建JavaFX可编辑的表视图

550 阅读8分钟

表格对于应用程序中的数据输入和显示具有重要意义。表视图支持表格式的显示。这种格式使得纠正和检查数据模式更加容易。

由于这种数据显示格式是在像Microsoft Excel这样的表格应用程序中创建的,所以开发人员在事务处理系统(TPS)管理信息系统(MIS)中更喜欢它。

随着对用户界面的关注,JavaFX以表格的形式表示数据。然而,人们只能查看,而不能单独编辑每个单元。

本文将在解决这个问题时提供解决方案。在本文结束时,读者将学会创建一个可编辑的表格视图,从而能够更容易地直接在表格上更新数据。

主要收获

在文章结束时,读者将能够完成以下工作。

  • 创建一个[TableView]。
  • 格式化表格。
  • TableView 上添加数据项。
  • 通过使用其控制器使TableView 可编辑。
  • 获取已编辑的项目。

前提条件

本文是一篇关于JavaFX的中级文章。

为了方便跟进文章的内容,以下是需要的技能和工具。

  • 一个好的Java IDE。建议使用最新的IntelliJ版本。
  • 一个良好的互联网连接。
  • 机器上安装的Java SDK。我们将使用JDK 17。

注意:系统要求和规格可能会随着时间而改变。请务必注意新的要求以及如何在项目中实现它们。

文章结构

在文章中,将按照以下步骤来完成关键收获部分中指出的要点。

  • 项目初始化。
  • 表的创建和设计。
  • 向表添加虚拟数据。
  • 使表的数据可编辑。
  • 取出已编辑的内容。

让我们从第一步开始。

项目初始化

要建立一个新的JavaFX项目,请执行以下步骤。

  • 打开IDE,点击 "新项目"按钮。
  • 选择JavaFX作为框架。
  • 在窗口中设置以下内容。
    • 名称:可编辑的表视图
    • 群组:com.table
    • 工件:editabletableview

New JavaFX editable tableview project

  • 点击'下一步'。
  • 依赖关系部分,设置如下所示的依赖关系,然后点击'完成'按钮。

Project dependencies

初始项目结构

生成的应用程序有如下结构。

.
├── src
│   ├── main
│       ├── java
│          ├── com.table.editabletableview
│                 ├── HelloApplication.java
│                 └── HelloController.java
│          └── module-info.java
│       └── resources
│          └── com.table.editabletableview
│             └── hello-view.fxml
├── editable-tableview.iml
└── pom.xml

新项目结构

  • java/com/table/editabletableview 路径中创建一个新的文件夹,并将其命名为model 。它将保存虚拟数据。
  • 在同一路径下创建另一个名为controller 的文件夹。
  • HelloController.java 文件的位置改为新创建的controller 文件夹。这一步可以通过右键单击文件并将其粘贴到新位置来完成。
  • model 文件夹中,创建一个名为User.java 的新文件。

由此产生的文件夹结构看起来如下。

.
├── src
│   ├── main
│       ├── java
│          ├── com. table.editabletableview
│               ├── controller
│                   └── HelloController.java
│               └── model
│                   └── User.java
│               └── HelloApplication.java
│          └── module-info.java
│       └── resources
│          └── com. table.editabletableview
│             └── hello-view.fxml
├── editable-tableview.iml
└── pom.xml

设置项目、工具和开发环境

为了实现这一点,请做以下工作。

  • 打开在resources/com/table/editabletableview 路径中找到的FXML文件。
  • IDE会在文件的顶部产生一个提示通知,要求安装JavaFX SDK 。只要允许它,IDE就会自动设置它,并为项目配置它。
  • 在靠近状态栏的左下方区域,点击SceneBuilder 选项,查看并使用SceneBuilder开发应用程序。
  • 如果这是第一次在机器上使用IDE创建JavaFX项目,它会给出一个安装SceneBuilder的提示通知。只要点击 "安装 "选项,IDE就会下载它并进行设置。
  • 如果IDE没有自动加载到SceneBuilder视图,请重新启动IDE。

表的创建和设计

  • 在SceneBuilder视图中,只需右键单击VBox ,并选择 "删除 "选项,就可以删除持有Hello 按钮的代码。

下面显示的代码将被删除。

这一步可以在这里的Text 视图中查看。

<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
      fx:controller="com.table.editabletableview.HelloController">
  <padding>
    <Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
  </padding>

  <Label fx:id="welcomeText"/>
  <Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>
  • 打开控制器,删除以下代码。
@FXML
private Label welcomeText;

@FXML
protected void onHelloButtonClick(){
        welcomeText.setText("Welcome to JavaFX Application!");
}
  • 800HelloApplication.java 文件中,将创建的Scene 的宽度和高度改为600 ,如下面一行代码所示。
Scene scene=new Scene(fxmlLoader.load(),800,600);

在这样做的时候,它删除了在项目初始化时生成的默认示例代码。

现在,按以下步骤进行下一步。

  • 打开FXML文件,从左侧面板的容器部分下拖放一个BorderPane 到设计页面的中央。
  • 在右侧面板下的布局部分,为BorderPane ,使其能与创建的场景相适应,设置如下。
    • Pref Width: 800
    • Pref Height: 600
  • 从左侧面板拖放一个TableView 控件到BorderPane的 "中心 "部分。

结果应该是这样的。

New TableView

  • 双击C1 的标题,将其改为id 。对C2 的标题做同样的操作,将其编辑为name
  • 要添加其他列,请前往Controls 部分并选择TableColumn 选项。然后,把它拖放到其他栏目旁边,并适当调整其大小。它的名字将是email
  • TableView 中添加另外两列,分别命名为notesedit 。适当地调整大小,使这些列适合TableView。

SceneBuilder 将生成以下代码。

<!--The application's controller is well pointed out-->
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0"
            prefWidth="800.0" xmlns="http://javafx.com/javafx/11.0.2" xmlns:fx="http://javafx.com/fxml/1"
            fx:controller="com.table.editabletableview.controller.HelloController">
  <center>
    <TableView fx:id="table_info" prefHeight="600.0" prefWidth="800.0" BorderPane.alignment="CENTER">
      <columns>
        <TableColumn fx:id="col_id" prefWidth="75.0" text="id"/>
        <TableColumn fx:id="col_name" prefWidth="132.0" text="name"/>
        <TableColumn fx:id="col_email" prefWidth="167.0" text="email"/>
        <TableColumn fx:id="col_notes" prefWidth="249.0" text="notes"/>
        <TableColumn fx:id="col_update" prefWidth="176.0" text="edit"/>
      </columns>
    </TableView>
  </center>
</BorderPane>

注意,控制器的位置在应用程序中被很好地显示出来了。

结果如下。

Created a table layout

在TableView上添加数据项

定义用户模型

在'User.java'文件中,做以下工作。

  • 添加将用于应用程序的字符串和按钮。
/*Add the strings and buttons to be used in the application*/
String id,name,email,notes;
Button update;
  • 生成它们的构造函数。

它看起来应该如下图所示。

/* Constructors */
public User(String id,String name,String email,String notes,Button update){
    this.id=id;
    this.name=name;
    this.email=email;
    this.notes=notes;
    this.update=update;
}
  • 在构造函数中,创建一个函数来制作 "更新"按钮。该按钮在点击时将显示该行的结果。这个按钮允许人们看到结果,因此,确定结果是否符合预期。

更新按钮点击时。

  • 通过调用on获得idgetId()
  • 通过调用获得姓名getName()
  • 通过调用获得电子邮件getEmail()
  • 通过调用获取笔记getNotes()
update.setOnAction(e->{
    /* Print the values of the row selected */
    ObservableList<User> users=HelloController.table_info_app.getSelectionModel().getSelectedItems();

    /* It outputs the value in the terminal */
    for(User user:users){
        if(user.getUpdate()==update){
            System.out.println("id: "+user.getId());
            System.out.println("name: "+user.getName());
            System.out.println("email: "+user.getEmail());
            System.out.println("notes: "+user.getNotes());
    }}
});
  • 如下所示,在构造函数之外设置获取器和设置器。
/* Getters and setters */
public String getId(){
  return id;
}
public void setId(String id){
  this.id=id;
}
public String getName(){
  return name;
}
public void setName(String name){
  this.name=name;
}
public String getEmail(){
  return email;
}
public void setEmail(String email){
  this.email=email;
}
public String getNotes(){
  return notes;
}
public void setNotes(String notes){
  this.notes=notes;
}
public Button getUpdate(){
  return update;  
}

这段代码为以下内容设置了获取器和设置器。

  • 身份
  • 名称
  • 电子邮件
  • 备注
  • 更新按钮

设置控制器

对于'HelloController.java'文件,做以下工作。

  • 让这个类实现'Initializable'。

这个类如下所示。

public class HelloController implements Initializable {
  /* Line of code */
}

Initializable,是一个JavaFX接口,可以使用初始化方法。

这个方法有助于解决根元素的相对路径。

  • 导入将在应用程序中使用的控件。

它显示在下面的代码中。

public static TableView<User> table_info_app;
public static ObservableList<User> data_table;
@FXML
private TableView<User> table_info;
@FXML
private TableColumn<User, String> column_id,column_name,column_email,column_notes;
@FXML
private TableColumn<User, Button> col_update;

上面的代码导入了。

  • 表视图:table_info

  • 表列:column_id,column_name,column_email,column_notes

  • 按钮:col_update

  • 在导入的控件下,在控制器的根元素被完全处理后,使用下面的代码来初始化一个控制器。

  • 它执行了两个将在后面定义的函数。这些是initializeCols()loadData() 函数。

@Override
public void initialize(URL url,ResourceBundle resourceBundle){
    table_info_app=table_info;

    initializeCols();
    loadData();
}

注意location 参数用于解决根对象的相对路径,如果它是已知的,而resources 为根对象做本地化。

  • 为了更详细地阐述initializeCols() 函数的功能。要指出的是,为特定行单元格输入的值是 "用户 "模型中定义的一组特定数据类型。例如,column_id部分的所有数值是针对所有ID的。
private void initializeCols(){
  // User.java ==>> id, name, email, notes;
  column_id.setCellValueFactory(new PropertyValueFactory<>("id"));
  column_name.setCellValueFactory(new PropertyValueFactory<>("name"));
  column_email.setCellValueFactory(new PropertyValueFactory<>("email"));
  column_notes.setCellValueFactory(new PropertyValueFactory<>("notes"));
  col_update.setCellValueFactory(new PropertyValueFactory<>("update"));
}

如前所述,表中的每一列都与一个数据类型相关。

  • column_id to carry IDs(id)

  • column_name for names(name)

  • column_email 为电子邮件

  • column_notes 用于注释

  • column_update 用于更新按钮(button)

  • 创建另一个名为loadData() 的函数,通过迭代为应用程序创建假数据。把下面的代码复制粘贴到文件中。

private void loadData(){
    data_table=FXCollections.observableArrayList();

    for(int x=1;x< 12;x++){

    /* Generates the data items in the table */
    data_table.add(new User(String.valueOf(x),"name "+x,"email "+x,"notes "+x,new Button("update")));
    }

    table_info.setItems(data_table);
}

上面这段代码产生的结果是记录被存储在系统中。

  • 通过'Main'类运行该应用程序。

输出结果应该是这样的。

Uneditable TableView

  • 试着双击一个单元格,看看是否可以修改内容。

如前所述,我们只能选择它,但不能编辑其内容。

让表格单元格可编辑

现在,在控制器中,做以下工作。

  • 添加一个函数editableCols() ,使单元格有一个Text Field 属性,使我们能够显示信息和编辑属性。
  • 一旦提交完成,它也会改变单元格的值。当值被改变,并按下回车按钮时,就完成了提交。
private void editableCols(){
    column_id.setCellFactory(TextFieldTableCell.forTableColumn());
    column_id.setOnEditCommit(e->e.getTableView().getItems().get(e.getTablePosition().getRow()).setId(e.getNewValue()));

    column_name.setCellFactory(TextFieldTableCell.forTableColumn());
    column_name.setOnEditCommit(e->e.getTableView().getItems().get(e.getTablePosition().getRow()).setName(e.getNewValue()));

    column_email.setCellFactory(TextFieldTableCell.forTableColumn());
    column_email.setOnEditCommit(e->e.getTableView().getItems().get(e.getTablePosition().getRow()).setEmail(e.getNewValue()));

    column_notes.setCellFactory(TextFieldTableCell.forTableColumn());
    column_notes.setOnEditCommit(e->e.getTableView().getItems().get(e.getTablePosition().getRow()).setNotes(e.getNewValue()));

    /* Allow for the values in each cell to be changable */
    table_info.setEditable(true); 
}

上面的代码做了以下工作。

  • 使得TableView ,所有的单元格都可以编辑。
  • 获取特定的单元格是否,对IDs、姓名、电子邮件和备注栏进行双击。

要使用上述函数,请在initializeCols() 函数中调用它,在col_update 行下使用下面这行。

/*Call 'editableCols()' function*/
editableCols();
  • 重新运行应用程序并再次尝试。注意,现在更新发生在修改完成后,按回车键提交修改。

在按下更新按钮时,输出被发送到之前配置的终端。

Final Result

在更新数据库中的内容时,可以获取内容的更新。

结论

表格式是一种非常吸引人的数据表现形式。它很容易理解和使用。编辑和更新内容也是毫不费力。

JavaFX允许人们以表格的形式查看和更新内容。它还允许将样式应用于创建的表格。

到现在为止,读者已经学会了如何。

  • 启动一个JavaFX项目。
  • 创建表格并设计它们。
  • 向表格中添加虚拟数据。
  • 使表的数据可编辑。
  • 在控制台中获取编辑的内容。
  • 操作已编辑的数据。