JavaFX SortedList:监听列表变化和列表项更新事件
JavaFX SortedList: listen the list changes and the list items updated event
用例:
- 有序的 ListView(或 TableView)
- 显示后进行插入
- 键更新在显示后进行
启动时列表:
加18后:
更新后:
如您所见,没有任何变化!
代码:
public final class SortedListTest extends Application {
@Override
public void start( Stage stage ) throws Exception {
final ObservableList<IntegerProperty> il =
FXCollections.observableArrayList();
il.add( new SimpleIntegerProperty( 12 ));
il.add( new SimpleIntegerProperty( 24 ));
il.add( new SimpleIntegerProperty( 36 ));
final Button add = new Button( "Add 18" );
final Button update = new Button( "Update 24 to 8" );
final HBox ctrl = new HBox( 4.0, add, update );
final ListView<IntegerProperty> listVw =
new ListView<>( new SortedList<>( il, (l,r)-> l.get() - r.get()));
stage.setScene(
new Scene(
new BorderPane( listVw, ctrl, null, null, null ), 180, 120 ));
stage.show();
add.setOnAction( e -> {
il.add( new SimpleIntegerProperty( 18 ));
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
update.setOnAction( e -> {
il.get( 1 ).set( 8 );
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
}
public static void main( String[] args ) {
launch( args );
}
}
控制台:
--------------
IntegerProperty [value: 12]
IntegerProperty [value: 24]
IntegerProperty [value: 36]
IntegerProperty [value: 18]
--------------
IntegerProperty [value: 12]
IntegerProperty [value: 8]
IntegerProperty [value: 36]
IntegerProperty [value: 18]
我们可以看到模型已正确更新,但视图却没有,为什么?
工作示例
(在接受了 James_D 的非常简单但很好的答案之后:)
这是一个完整的示例,其中包含用于说明解决方案的属性记录:
public final class SortedListTest extends Application {
class Record {
final IntegerProperty _key = new SimpleIntegerProperty();
final StringProperty _value = new SimpleStringProperty();
Record( int k, String v ) {
_key .set( k );
_value.set( v );
}
@Override
public String toString() {
return "Key = " + _key.get() + ", value = " + _value.get();
}
}
@Override
public void start( Stage stage ) throws Exception {
final ObservableList<Record> il =
FXCollections.observableArrayList(
rec -> new Observable[]{ rec._key });
il.add( new Record( 12, "Douze" ));
il.add( new Record( 24, "Vingt quatre" ));
il.add( new Record( 36, "Trente six" ));
final Button add = new Button( "Add 18" );
final Button update = new Button( "Update 24 to 8" );
final HBox ctrl = new HBox( 4.0, add, update );
final SortedList<Record> sortedList =
il.sorted((l,r)-> Integer.compare(l._key.get(), r._key.get()));
final ListView<Record> listVw = new ListView<>( sortedList );
stage.setScene( new Scene(
new BorderPane( listVw, ctrl, null, null, null ), 200, 140 ));
stage.show();
add.setOnAction( e -> {
il.add( new Record( 18, "Dix huit" ));
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
update.setOnAction( e -> {
il.get( 1 )._key.set( 8 );
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
}
public static void main( String[] args ) {
launch( args );
}
}
结果:
SortedList
观察其底层 ObservableList
。因此,它只会在底层列表触发更改事件时更新其顺序。
要使可观察列表在其中一个元素的状态发生变化时触发更新事件(与列表添加、删除或重新排序元素相反),它必须观察相应的属性。除非您使用 extractor 告诉它这样做,否则不会发生这种情况。提取器是一个将列表中的元素映射到应该观察的属性数组的函数:如果这些属性发生变化,列表将触发更新事件。在您的场景中,列表是排序列表的基础列表,这将允许排序列表自行重新排序。
因此您需要将基础列表创建为
final ObservableList<IntegerProperty> il =
FXCollections.observableArrayList(
( IntegerProperty intProp ) -> new Observable[]{ intProp });
(即你要观察的属性就是元素本身)。
用例:
- 有序的 ListView(或 TableView)
- 显示后进行插入
- 键更新在显示后进行
启动时列表:
加18后:
更新后:
如您所见,没有任何变化!
代码:
public final class SortedListTest extends Application {
@Override
public void start( Stage stage ) throws Exception {
final ObservableList<IntegerProperty> il =
FXCollections.observableArrayList();
il.add( new SimpleIntegerProperty( 12 ));
il.add( new SimpleIntegerProperty( 24 ));
il.add( new SimpleIntegerProperty( 36 ));
final Button add = new Button( "Add 18" );
final Button update = new Button( "Update 24 to 8" );
final HBox ctrl = new HBox( 4.0, add, update );
final ListView<IntegerProperty> listVw =
new ListView<>( new SortedList<>( il, (l,r)-> l.get() - r.get()));
stage.setScene(
new Scene(
new BorderPane( listVw, ctrl, null, null, null ), 180, 120 ));
stage.show();
add.setOnAction( e -> {
il.add( new SimpleIntegerProperty( 18 ));
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
update.setOnAction( e -> {
il.get( 1 ).set( 8 );
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
}
public static void main( String[] args ) {
launch( args );
}
}
控制台:
--------------
IntegerProperty [value: 12]
IntegerProperty [value: 24]
IntegerProperty [value: 36]
IntegerProperty [value: 18]
--------------
IntegerProperty [value: 12]
IntegerProperty [value: 8]
IntegerProperty [value: 36]
IntegerProperty [value: 18]
我们可以看到模型已正确更新,但视图却没有,为什么?
工作示例
(在接受了 James_D 的非常简单但很好的答案之后:)
这是一个完整的示例,其中包含用于说明解决方案的属性记录:
public final class SortedListTest extends Application {
class Record {
final IntegerProperty _key = new SimpleIntegerProperty();
final StringProperty _value = new SimpleStringProperty();
Record( int k, String v ) {
_key .set( k );
_value.set( v );
}
@Override
public String toString() {
return "Key = " + _key.get() + ", value = " + _value.get();
}
}
@Override
public void start( Stage stage ) throws Exception {
final ObservableList<Record> il =
FXCollections.observableArrayList(
rec -> new Observable[]{ rec._key });
il.add( new Record( 12, "Douze" ));
il.add( new Record( 24, "Vingt quatre" ));
il.add( new Record( 36, "Trente six" ));
final Button add = new Button( "Add 18" );
final Button update = new Button( "Update 24 to 8" );
final HBox ctrl = new HBox( 4.0, add, update );
final SortedList<Record> sortedList =
il.sorted((l,r)-> Integer.compare(l._key.get(), r._key.get()));
final ListView<Record> listVw = new ListView<>( sortedList );
stage.setScene( new Scene(
new BorderPane( listVw, ctrl, null, null, null ), 200, 140 ));
stage.show();
add.setOnAction( e -> {
il.add( new Record( 18, "Dix huit" ));
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
update.setOnAction( e -> {
il.get( 1 )._key.set( 8 );
System.err.println( "--------------" );
il.stream().forEach( System.err::println );
});
}
public static void main( String[] args ) {
launch( args );
}
}
结果:
SortedList
观察其底层 ObservableList
。因此,它只会在底层列表触发更改事件时更新其顺序。
要使可观察列表在其中一个元素的状态发生变化时触发更新事件(与列表添加、删除或重新排序元素相反),它必须观察相应的属性。除非您使用 extractor 告诉它这样做,否则不会发生这种情况。提取器是一个将列表中的元素映射到应该观察的属性数组的函数:如果这些属性发生变化,列表将触发更新事件。在您的场景中,列表是排序列表的基础列表,这将允许排序列表自行重新排序。
因此您需要将基础列表创建为
final ObservableList<IntegerProperty> il =
FXCollections.observableArrayList(
( IntegerProperty intProp ) -> new Observable[]{ intProp });
(即你要观察的属性就是元素本身)。