JavaFX表格控件TableView高级应用:自动添加ID列、删除操作列、单元格内容个性化渲染

问题描述

我们在用Javafx开发应用程序的时候,TableView是比较常用的用来展示数据的控件,但是它的灵活性确实没有WEB开发里面的控件好,比如,我遇到的问题就有:

  1. 数据库存储里面的ID列(序号)一般是自增性质的,不停的增加、删除操作后,这个序号列就会乱,数字 不连续,而我们要显示到GUI里面的序号列肯定需要按正常顺序显示的,本文提供构造顺序序号列的方法;
  2. 操作列(比如删除)的渲染问题,一种思路就是在表格控件之外加一个删除按钮,点击按钮的时候判断一下当前选中的行,然后执行删除操作。本文讨论另外一种思路,单独在表格里面添加一个删除列(每行都有一个删除按钮,单击则删除所在行数据);
  3. 很多时候,我们具有个性化显示表格数据的需求,比如,显示学生数学成绩的某列,我们希望把那些低于60分的分数标红,而及格分数则不做处理;
TableView理解

JavaFX表格控件渲染数据主要有两种方法:
1. setCellValueFactory(new PropertyValueFactory<>(“字段名”)),适合表格列数已知,有对应实体的情况(比如,学生信息,我们假定它只有姓名、性别、学号、地址、联系方式等固定字段,则适合采用此种方式进行渲染);
2. setCellValueFactory(new MapValueFactory<>(“对应列的键值”)),适合表格列数在渲染之前未知,需要根据传入数据的维数确定的情况,此时因为没有固定列数,所以一般数据也没有对应的实体类,数据需要用Map进行构造,一行数据就是一个Map;
本文主要针对列数已知的情况,Map的情况同理。

代码DEMO
工程目录如下图:

这里写图片描述

Main.java

/**
 * 实现表格的序号列的计算填充,
 * 实现按钮操作列的正常显示以及事件绑定
 */
package application;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(this.getClass().getResource("FXTable.fxml"));
            // 为表格设置控制器
            loader.setController(new TableController());
            AnchorPane rootPane = loader.load();
            Scene scene = new Scene(rootPane,506,460);
            primaryStage.sizeToScene();
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Student.java

package application;

public class Student {
    private String firstName;
    private String lastName;
    private int age;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Student(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
}

TableController.java

package application;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
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.PropertyValueFactory;
import javafx.scene.image.ImageView;

public class TableController implements Initializable {
    @FXML
    private Label fxLabel;
    @FXML
    private TableView<Student> stuTable;
    @FXML
    private TableColumn<Student, String> idCol, fNameCol, lNameCol, delCol;
    @FXML
    private TableColumn<Student, Integer> ageCol;
    @FXML
    private TableColumn<Student, Boolean> isAdultCol;

    public ObservableList<Student> getStuData() {

        Student stu1 = new Student("赵", "哈", 16);
        Student stu2 = new Student("钱", "大", 26);
        Student stu3 = new Student("孙", "阿", 23);
        Student stu4 = new Student("李", "佛山", 17);
        Student stu5 = new Student("周", "阿萨德", 23);
        Student stu6 = new Student("吴", "更好", 12);
        Student stu7 = new Student("郑", "和", 28);
        Student stu8 = new Student("王", "费", 23);
        Student stu9 = new Student("刘", "的", 15);
        Student stu10 = new Student("关", "时是", 23);
        Student stu11 = new Student("张", "良好", 19);
        Student stu12 = new Student("诸葛", "列", 23);
        Student stu13 = new Student("司马", "咯跑", 20);

        ObservableList<Student> stuLists = FXCollections.observableArrayList(stu1, stu2, stu3, stu4, stu5, stu6, stu7,
                stu8, stu9, stu10, stu11, stu12, stu13);
        return stuLists;
    }

    /**
     * 显示学生表格
     * 
     * @param stuLists
     */
    public void showStuTable(ObservableList<Student> stuLists) {
        fNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
        lNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
        // ageCol.setCellValueFactory(new PropertyValueFactory<>("age"));
        idCol.setCellFactory((col) -> {
            TableCell<Student, String> cell = new TableCell<Student, String>() {
                @Override
                public void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    this.setText(null);
                    this.setGraphic(null);

                    if (!empty) {
                        int rowIndex = this.getIndex() + 1;
                        this.setText(String.valueOf(rowIndex));
                    }
                }
            };
            return cell;
        });

        ageCol.setCellFactory((col) -> {
            TableCell<Student, Integer> cell = new TableCell<Student, Integer>() {

                @Override
                public void updateItem(Integer item, boolean empty) {
                    super.updateItem(item, empty);
                    this.setText(null);
                    this.setGraphic(null);

                    if (!empty) {
                        int age = this.getTableView().getItems().get(this.getIndex()).getAge();
                        this.setText(String.valueOf(age));
                        if (age < 18) {
                            this.getStyleClass().add("mark");
                        }
                    }
                }

            };
            return cell;
        });

        isAdultCol.setCellFactory((col) -> {
            TableCell<Student, Boolean> cell = new TableCell<Student, Boolean>() {

                @Override
                public void updateItem(Boolean item, boolean empty) {
                    super.updateItem(item, empty);
                    this.setText(null);
                    this.setGraphic(null);

                    if (!empty) {
                        CheckBox checkBox = new CheckBox();
                        this.setGraphic(checkBox);
                        checkBox.selectedProperty().addListener((obVal, oldVal, newVal) -> {
                            if (newVal) {
                                // 添加选中时执行的代码
                                System.out.println("第" + this.getIndex() + "行被选中!");
                                // 获取当前单元格的对象
                                // this.getItem();
                            }

                        });
                    }
                }

            };
            return cell;
        });

        delCol.setCellFactory((col) -> {
            TableCell<Student, String> cell = new TableCell<Student, String>() {

                @Override
                public void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    this.setText(null);
                    this.setGraphic(null);

                    if (!empty) {
                        ImageView delICON = new ImageView(getClass().getResource("delete.png").toString());
                        Button delBtn = new Button("删除", delICON);
                        this.setGraphic(delBtn);
                        delBtn.setOnMouseClicked((me) -> {
                            Student clickedStu = this.getTableView().getItems().get(this.getIndex());
                            System.out.println("删除 " + clickedStu.getFirstName() + clickedStu.getLastName() + " 的记录");
                        });
                    }
                }

            };
            return cell;
        });

        stuTable.setItems(stuLists);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        fxLabel.setWrapText(true);
        fxLabel.setText("        javafx_Label标签的换行测试,用于弹出框的提示信息测试,Label控件也可以换行。");

        this.showStuTable(this.getStuData());
    }

}

FXTable.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="461.0" prefWidth="489.0" stylesheets="@Fxtable.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <TableView fx:id="stuTable" layoutY="54.0" prefHeight="407.0" prefWidth="402.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="54.0">
        <columns>
            <TableColumn fx:id="idCol" prefWidth="75.0" text="序号" />
          <TableColumn fx:id="fNameCol" prefWidth="87.0" text="姓氏" />
          <TableColumn fx:id="lNameCol" prefWidth="79.0" text="名字" />
            <TableColumn fx:id="ageCol" prefWidth="73.0" text="年龄" />
            <TableColumn fx:id="delCol" prefWidth="86.0" text="删除列" />
            <TableColumn fx:id="isAdultCol" prefWidth="88.0" text="成年?" />
        </columns>
      </TableView>
      <Label fx:id="fxLabel" layoutY="-1.0" prefHeight="56.0" prefWidth="402.0" />
   </children>
</AnchorPane>
运行截图:

这里写图片描述

这里写图片描述

实现描述:
  1. 实体类里面无ID字段,表格做数据展示的时候临时构造顺序ID列数据;
  2. 删除操作列的渲染,并且添加单击事件,能够实时响应删除动作;
  3. 年龄一列的个性化显示,未成年年龄显示为红色字体;

另,DEMO源码可以向我索要。

  • 13
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
要将JavaFX中的TableView变成只有一行一,可以采用以下步骤: 1. 设置TableView的行数和数为1: ```java tableView.setFixedCellSize(25); tableView.setPrefHeight(26); tableView.setPrefWidth(100); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tableView.setPlaceholder(new Label("")); tableView.setEditable(false); tableView.getSelectionModel().setCellSelectionEnabled(true); tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); tableView.setMinWidth(100); tableView.setMaxWidth(Double.MAX_VALUE); tableView.setMinHeight(30); tableView.setMaxHeight(30); tableView.setPrefSize(100, 30); tableView.getItems().clear(); tableView.getColumns().clear(); tableView.getColumns().add(new TableColumn()); tableView.getItems().add(new Object()); ``` 2. 设置的宽度和可编辑性: ```java TableColumn column = tableView.getColumns().get(0); column.setEditable(true); column.setSortable(false); column.setReorderable(false); column.setResizable(false); column.setPrefWidth(100); column.setMaxWidth(100); column.setMinWidth(100); column.setCellValueFactory(new PropertyValueFactory<>("value")); ``` 3. 设置单元格的样式: ```java tableView.setRowFactory(tv -> new TableRow<>() { @Override protected void updateItem(Object item, boolean empty) { super.updateItem(item, empty); if (empty) { setStyle("-fx-background-color: transparent;"); } else { setStyle("-fx-background-color: white; -fx-border-color: black;"); } } }); column.setCellFactory(tc -> new TableCell<>() { @Override protected void updateItem(Object item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); } else { setText(item.toString()); } } }); ``` 这样,就可以将TableView变成只有一行一表格

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值