版权声明:本文为博主原创文章,未经博主允许不得转载。
简单概述
在用JavaFX 做表格的时候(TableView),发现JavaFX内置了很多功能,最常见的就是排序。TableView 下包含了 TableColumn。每一列是一个TableColumn,该列会根据对象的类型(比如Integer, Double, Float, String 等等)进行排序。再排序的时候,默认调用对应类型的Comparator进行排序,当然你也可以创建自己的Comparator。这个功能很实用,那么问题来了,这和我的标题又有什么联系呢。
事情是这样的,我的表格中有一列是展示工资的。众所周知,工资没必要保留太多位数字,一般两位数就够了。但刚开始用TableColumn时,因为工资是自动计算出来的,如下图所示。
金额等于 0.07 x 3 = 0.21, 但显示的效果是0.2100000000… 很不美观
再者,我们看向日期列,因为需要格式化显示日期格式,所以不得不将Date 转化为String 打印输出。导致的结果就是默认调用String类的 Comparator,然后排序结果是这样的:
2019-5-1, 2019-5-11, 2019-5-12, … 2019-5-2, 2019-5-21, …
没有按照真正的日期排序,很不理想
解决办法
TableColumn 的 两个方法,setCellValueFactory 和 setCellFactory, 可以完美解决 以上问题
首先我们介绍少一下大概场景,涉及以下几个类
Wage.class
public class Wage {
private int eid; //员工编号
private String name; //员工姓名
private int numDays; //工作天数
private double wage; //工资
//以下是get 和 set 方法
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
...
FXML 控制器
WageManageController.class
public class WageManageController implements Initializable{
@FXML
TableView<Wage> tbView;
@FXML
TableColumn<Wage, Integer> eidColumn,numDayColumn;
@FXML
TableColumn<Wage, String> nameColumn;
@FXML
TableColumn<Wage, Double> wageColumn;
@FXML
ComboBox<String> cbMonth;
@FXML
Label sumWage;
// 省略部分代码
private void initiColumns() {
eidColumn.setCellValueFactory(new PropertyValueFactory<Wage, Integer>("eid"));
nameColumn.setCellValueFactory(new PropertyValueFactory<Wage, String>("name"));
numDayColumn.setCellValueFactory(new PropertyValueFactory<Wage, Integer>("numDays"));
wageColumn.setCellValueFactory(new PropertyValueFactory<Wage, Double>("wage"));
wageColumn.setCellFactory(col->{
TableCell<Wage, Double> cell = new TableCell<Wage, Double>(){
@Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
this.setText(null);
this.setGraphic(null);
if (!empty) {
int rowIndex = this.getIndex();
double d = tbView.getItems().get(rowIndex).getWage();
this.setText(StringUtils.formatNumber(2, d));
}
}
};
return cell;
});
wageColumn.setStyle("-fx-alignment:CENTER-RIGHT");
}
//省略部分代码
还有一个FXML文件就不向大家展示了,大家可以设计自己的UI
接下来就是重点了,主要区分这两个方法,以及了解他们是如何工作的
wageColumn.setCellValueFactory
我们传入了参数 new PropertyValueFactory<Wage, Double>(“wage”)
该列会自动调用方法getWage() 去过去对应的数据。尖括号里的第一个值是对象类,也就是我们的Wage.class, 第二个是要访问的属性的类型(在对象类里是double类型,但java会自动把他封装为Double对象)。最后括号的里的字符串就是变量名(Wage.class 里的 private double wage;),这一点必须保持一致。在排序的时候会调用Double类的Comparator。然而在打印输出的时候,会默认调用Double的toString()方法。这样是导致输出效果不好的原因所在。同时如果我们处理的是Date类,输出效果就更可怕了,因为他默认也是调用Date类的toString()方法。
wageColumn.setCellFactory
这个方法就完美解决了展示效果的问题,并且还不影响应该有的排序效果。每一个TableColumn都有自己的TableCell, 对于TableCell目前还没有深入了解,就不展开了。在这里,我们需要重写TableCell的方法
public void updateItem(Double item, boolean empty)
这里的Double 要和你要访问的类型保持一直,也就是上边的new TableCell<Wage, Double>() 然后就是调用setText()方法, 对这TableCell设置文本内容(要显示的内容)。你可以看到,在这里我调用了StringUtils.formatNumber()方法 (自己写的方法)对数组进行格式化输出,该方法返回一个字符串。同理,如果需要对日期进行格式化输出,只需调用对应的方法就好了。
感谢你审阅,欢迎指正及评论。一定及时回复