概述
TableView是JavaFX的一个重要的组件,毕竟我们在实际工作中表格还是经常使用的东西,不管是存储数据还是展示数据。
组件
接下来我们以学生信息为例,把它放到JavaFX的TableView中去展示,并看一下如何来实现增删改的操作。下面是我们需要用到的类:
Student
在JavaFX中,每一行数据就是一个Bean对象,也就是我们一个Java的实体类(类必须是public的),需要我们自己定义,这里我们的类名就叫Student。
public class Student { private String name; private int age; private double score; private boolean is; public Student(String name, int age, double score, boolean is) { this.name = name; this.age = age; this.score = score; this.is = is; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } public boolean isIs() { return is; } public void setIs(boolean is) { this.is = is; } }
ObservableList<Student>
这是我们的数据源,泛型参数就是我们的Student对象,使用时只需要通过下面这句构造:
ObservableList<Student> list = FXCollections.observableArrayList();
显然,通过名字我们就可以看出来,它支持类似于我们List集合的一些操作,待会增删改的时候再详细介绍。
TableView<Student>
这个类负责我们表格的展示,构造方法如下:
//新建tableView并指定数据源 TableView<Student> tableView = new TableView<>(list);
只指定数据源其实是不够的,我们知道,一个表格包括“表头”和“身体”,而且需要注意的是:我们的TableView是以一列为一个对象的,所以我们需要设置tableview的属性(表头和内容),数据的显示主要有两种方法:
setCellValueFactory()
TableColumn
这是表头,它负责表头的展示,因为前面我们已经指定了数据源,所以这里我们可以通过它来指定每一个列对象的内容(其实就是指定每一列的数据类型),setCellValueFactory()需要传入参数,我们可以通过两种参数来指定:
1. Callback
//第一列 姓名 TableColumn<Student,String> col_name = new TableColumn<>("姓名"); tableView.getColumns().add(col_name);//添加到tableView中展示 //设置该列的数据类型-返回单元格内容 col_name.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Student, String>, ObservableValue<String>>() { @Override public ObservableValue<String> call(TableColumn.CellDataFeatures<Student, String> param) { SimpleStringProperty name = new SimpleStringProperty(param.getValue().getName()); return name; } }); //第二列 年龄 -这里的泛型是Number不是Integer TableColumn<Student,Number> col_age = new TableColumn<>("年龄"); tableView.getColumns().add(col_age); //这里的泛型是Number不是Integer,因为SimpleIntegerProperty继承了Observable<Number>接口,泛型是Number不是Integer col_age.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Student, Number>, ObservableValue<Number>>() { @Override public ObservableValue<Number> call(TableColumn.CellDataFeatures<Student, Number> param) { SimpleIntegerProperty age = new SimpleIntegerProperty(param.getValue().getAge()); return age; } }); //第三列 战斗力 -这里的泛型是Number不是Boolean TableColumn<Student,Number> col_score = new TableColumn<>("战斗力"); tableView.getColumns().add(col_score); col_score.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Student, Number>, ObservableValue<Number>>() { @Override public ObservableValue<Number> call(TableColumn.CellDataFeatures<Student, Number> param) { SimpleDoubleProperty score = new SimpleDoubleProperty(param.getValue().getScore()); return score; } }); //第四列 是否无敌 TableColumn<Student,Boolean> col_is = new TableColumn<>("是否无敌"); tableView.getColumns().add(col_is); col_is.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Student, Boolean>, ObservableValue<Boolean>>() { @Override public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Student, Boolean> param) { SimpleBooleanProperty is = new SimpleBooleanProperty(param.getValue().isIs()); return is; } });
需要注意的是,我们JavaFX对普通Java支持的基本类型进行了抽象,我们需要使用JavaFX规定的数据类型,比如我们的 Integer 和 Double 都需要转为Number类型,但是String和Boolean不需要。
2. PropertyValueFactory
需要注意的是,如果使用这种方法来指定内容的数据类型,这里我们可以使用Java自己的数据类型不需要使用JavaFX的Number类型,因此这种也更加简便:
//第一列 姓名 TableColumn<Student,String> col_name = new TableColumn<>("姓名"); tableView.getColumns().add(col_name); //第二列 年龄 --这里不需要使用Number代替 TableColumn<Student,Integer> col_age = new TableColumn<>("年龄"); tableView.getColumns().add(col_age); //第三列 战斗力 -这里不需要使用Number代替 TableColumn<Student,Double> col_score = new TableColumn<>("战斗力"); tableView.getColumns().add(col_score); //第四列 TableColumn<Student,Boolean> col_is = new TableColumn<>("是否无敌"); tableView.getColumns().add(col_is); col_name.setCellValueFactory(new PropertyValueFactory<Student,String>("name")); col_age.setCellValueFactory(new PropertyValueFactory<Student,Integer>("age")); col_age.setCellValueFactory(new PropertyValueFactory<Student,Double>("score")); col_age.setCellValueFactory(new PropertyValueFactory<Student,Boolean>("is"));
增加到末行
显然对数据进行增删改其实就是通过修改我们的数据源(ObservableList<Student>)的数据集合list来实现的,这里又是可以通过两种方法来实现:
1、tableView.getItems().add(Student s)
Button bu = new Button("增加一行数据"); bu.setOnAction(event->{ //增加到最后一行 tableView.getItems().add(new Student("石敢当",999,100.0,true)); });
2、list.add(Student s)
bu.setOnAction(event->{ list.add(new Student("石敢当",999,100.0,true)); tableView.refresh(); });
删除指定行
同样是两种方法(参数为0代表删除第一行,1代表第二行,以次类推...):
1、tableView.getItems().remove(int i)
//删除第一行 bu_rm.setOnAction(event -> { tableView.getItems().remove(0);//0是第一行,1是第二行,以此类推 });
2、list.remove(int i)
//删除第一行 bu_rm.setOnAction(event -> { list.remove(0); tableView.refresh(); });
修该指定行
同样两张方法:
1、tableView.getItems().set(int i,Student s)
表示将第 i+1 行的内容换为新的对象s
//修改第一行 bu_update.setOnAction(event -> { //同样0是第一行,1是第二行,以此类推 tableView.getItems().set(0,new Student("熊大",18,80.0,true)); });
2、s.setX()
//数据源 ObservableList<Student> list = FXCollections.observableArrayList(); //一行内容对对应的对象 Student s1 = new Student("李大喜",15,75.0,false); list.add(s1); //对已经有的对象进行修该实现表格的内容更新 bu_update.setOnAction(event -> { //只修改属性我们可以通过Bean对象的set方法来修改,减少对象的创建 s1.setAge(20); tableView.refresh();//需要刷新才能修改成功 });
注意:使用list的方法进行add、remove以及使用直接对对象进行修改的时候,我们需要刷新一下tableView才能重新展示数据。
完整代码
TableTest
import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.xpath.internal.operations.Bool; import javafx.application.Application; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; public class TableTest extends Application{ public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { ObservableList<Student> list = FXCollections.observableArrayList(); list.add(new Student("燕双鹰", 18, 90.0, true)); TableView tableView = new TableView(list); TableColumn<Student,String> col_name = new TableColumn<>("姓名"); tableView.getColumns().add(col_name); TableColumn<Student,Integer> col_age = new TableColumn<>("年龄"); tableView.getColumns().add(col_age); TableColumn<Student,Double> col_score = new TableColumn<>("分数"); tableView.getColumns().add(col_score); TableColumn<Student,Boolean> col_is = new TableColumn<>("无敌"); tableView.getColumns().add(col_is); col_name.setCellValueFactory(new PropertyValueFactory<Student,String>("name")); col_age.setCellValueFactory(new PropertyValueFactory<Student,Integer>("age")); col_score.setCellValueFactory(new PropertyValueFactory<Student,Double>("score")); col_is.setCellValueFactory(new PropertyValueFactory<Student,Boolean>("is")); AnchorPane pane = new AnchorPane(); pane.getChildren().addAll(tableView); AnchorPane.setLeftAnchor(tableView, 50.0); AnchorPane.setTopAnchor(tableView, 50.0); Button add = new Button("添加一行"); add.setOnAction(event->{ tableView.getItems().add(new Student("光头强", 20, 80.0, true));//不需要刷新 // list.add(new Student("李大喜", 15, 50.0, true)); // tableView.refresh(); }); pane.getChildren().add(add); AnchorPane.setLeftAnchor(add, 20.0); Button del = new Button("删除第一行"); del.setOnAction(event->{ tableView.getItems().remove(0); // list.remove(0); // tableView.refresh(); }); pane.getChildren().add(del); AnchorPane.setLeftAnchor(del, 80.0); Button change = new Button("修改第一行"); change.setOnAction(event->{ tableView.getItems().set(0, new Student("光头强", 20, 80.0, true));//不需要刷新 // list.set(0,new Student("李大喜", 15, 50.0, true)); // tableView.refresh(); }); pane.getChildren().add(change); AnchorPane.setLeftAnchor(change, 160.0); Scene scene = new Scene(pane); primaryStage.setTitle("Javafx"); primaryStage.setScene(scene); primaryStage.setHeight(600); primaryStage.setWidth(600); primaryStage.show(); } }