JavaFX TableColumn 的 setCellValueFactory 和 setCellFactory 应用场景

版权声明:本文为博主原创文章,未经博主允许不得转载。

JavaFX TableColumn 的 setCellValueFactory 和 setCellFactory 应用场景

简单概述

在用JavaFX 做表格的时候(TableView),发现JavaFX内置了很多功能,最常见的就是排序。TableView 下包含了 TableColumn。每一列是一个TableColumn,该列会根据对象的类型(比如Integer, Double, Float, String 等等)进行排序。再排序的时候,默认调用对应类型的Comparator进行排序,当然你也可以创建自己的Comparator。这个功能很实用,那么问题来了,这和我的标题又有什么联系呢。
事情是这样的,我的表格中有一列是展示工资的。众所周知,工资没必要保留太多位数字,一般两位数就够了。但刚开始用TableColumn时,因为工资是自动计算出来的,如下图所示。
示例-1
金额等于 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()方法 (自己写的方法)对数组进行格式化输出,该方法返回一个字符串。同理,如果需要对日期进行格式化输出,只需调用对应的方法就好了。


感谢你审阅,欢迎指正及评论。一定及时回复

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值