您的位置:首页 > 编程语言 > Java开发

JavaFx TableView 实时的根据行对象数据变化刷新

2017-03-30 05:47 1711 查看
1, 最简单粗暴,但也最不合理的做法

在数据对象更新后,调用 table.refresh() 方法。

这样做,表格实际上是刷新了,因为绑定的list里的对象确实发生了变化。

* 但是,这样并不符合数据绑定的工作方式,实际上调用refresh()的结果是重新渲染表格,可理解为表格初始化为空白后,重新加载了,当然实际fx不是这么做,但refresh()意味着实际是UI层重新初始化。

* 并不是数据绑定的监听起了作用。原因(痛点):table 绑定 list ,Oracle 只实现了增加、删除2个动作的监听,即是说,list 中单个元素本身属性值的修改,并不会被数据绑定所监听。

因为以上原因,出现的现象就是:

当 list 中元素有增、删时候, table 能够实时刷新。

当 list 中元素属性变化时候, table 不能实时刷新。(因为此时修改事件并不受监听,list 不认为自己有变化,随之 table 也就不会刷新)。

—- 第1种情况,致使 list 监听不到变化的前提是,修改的属性为JavaBean普通属性类型(如String,Integer) ,对 table cell 定义如:

tc_status.setCellValueFactory(new PropertyValueFactory<Account,String>("status"));


2,因为JavaBean普通属性,即使通过

new PropertyValueFactory<Account,String>("name")


这样的包装,变成可以在 table 中显示,但实际上偏离了 JavaFx 的设计初衷。

与 JavaFx UI 层进行交互的类属性,应当定义为对应的 xxxProperty 包装类 (如 StringProperty , IntegerProperty 等 )。

然后,在对 table cellValueFactory 定义时,就可以直接返回 xxxProperty 对象 (因为 StringProperty 本身就是 ObservableValue 的子类)

代码实例:

// 定义为 final 好像是一种规范做法
private final StringProperty status = new SimpleStringProperty();

// * 特别说明: xxxProperty 方法名,是 fx 的规范,只要属性名加上 Peoperty() 作为方法名,fx 就能自动监听该属性的变化!
public StringProperty statusProperty() {
return status;
}
// 原有的 set 方法,并不受字段类型变化而改变,仍然接受同样的参数,只是方法体需要修改一下
public void setStatus(String status) {
this.status.set(status);
}

// 原有的 get 方法,并不受字段类型变化而改变,仍然返回同样的类型,只是方法体需要修改一下
public String getStatus(){
return status.get();
}

....
// Controller 中定义
// 这样的写法就行了!当该属性值变化时,fx 绑定能立即捕捉到,并且刷新UI
tc_status.setCellValueFactory(new PropertyValueFactory("status"));


经过这样对原来JavaBean属性的改造,当属性发生变化时,list 能够捕捉到,因此 table 上对应的值也能实时刷新。(这才是数据绑定,而不是第1种做法中对table UI层的强制刷新)

要注意,如果是 IntegerProperty , DoubleProperty 数字类型的,应定义为 Number ,而不是 Interger,如下所示,对应的 setCellValueFactory 方法对应参数类型也应为 Number。(* 非必须定义,可以不定义)

TableColumn<Account,Number> tc_num4xxx;


前面定义 setValueFactory 的方法,在 JDK8 中可以这样写:

tc_num4xxx.setCellValueFactory(param->param.getValue().num4xxx());


3, 高级做法:

table 上每个单元格,实际上不只可以容纳String、Integer 等类型,还可以容纳各种FX UI控件,

比如可以将单元格填充为 Label , CheckBox , ProgressBar

示例 (把 ProgressBar 塞进去)

tc_progress.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<Account, ProgressBar>, ObservableValue<ProgressBar>>() {
@Override
public ObservableValue<ProgressBar> call(
TableColumn.CellDataFeatures<Account, ProgressBar> param) {
// 取出 table 上绑定的对应对象
Account account = param.getValue();
// 制造 ProgressBar UI 实例
ProgressBar progressbar = new ProgressBar();
// 绑定 progress这个property属性到UI上
progressbar.progressProperty().bind(account.progress());
// 返回 ProgressBar 类型对象
return new SimpleObjectProperty<ProgressBar>(progressbar);
}
});


如果要塞一个 Label 进去,同理参数类型设为 Label , 然后给想要单元格能够监听的属性 添加onChange监听,这样当属性变化时, Label 的 text 能够被更新,也就实现了刷新的目的。

tc_status.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Account,Label>, ObservableValue<Label>>(){

@Override
public ObservableValue<Label> call(CellDataFeatures<Account, Label> param) {
// TODO 定义 Label
final Label label = new Label(param.getValue().getStatus());
try {
label.setText(param.getValue().getStatus());

// 添加对属性值的监听事件,当值变化时,更新 Label 的 text 属性
param.getValue().status().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue,
String newValue) {
// TODO
Platform.runLater(()->
label.setText("-->"+newValue)
);
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return new SimpleObjectProperty<Label>(label);
}
/////////////////////////////////////////////////////
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javafx
相关文章推荐