如何使JavaFX属性侦听器在oldVaule和newValue相同的情况下触发事件? 让我们考虑一个示例代码: SimpleIntegerProperty simpleIntegerProperty = new SimpleIntegerProperty(0); simpleIntegerProperty.addListener((observable, oldValue, newValue) -> { // execution code when the event is fired. });
使用如何使JavaFX属性侦听器在oldVaule和newValue相同的情况下触发事件? 让我们考虑一个示例代码: SimpleIntegerProperty simpleIntegerProperty = new SimpleIntegerProperty(0); simpleIntegerProperty.addListener((observable, oldValue, newValue) -> { // execution code when the event is fired. });,java,javafx,Java,Javafx,使用setValue()方法设置新值时,如果oldValue和newValue相同,则不会触发事件。只有当他们不同的时候 一个例子: 我有一个列表视图与包含一些“元素”的可观察列表绑定在一起 我可以在应用程序的不同位置添加更多元素 有一个按钮“开始”启动一个程序-它 遍历列表并对每个元素执行一些操作 过程是另一类。它对元素执行一些操作,还包含simpleintegerperty-currentlyChosenElementIndex,以指示当前所选元素的索引 当当前元素正在进行时,我希望Li
setValue()
方法设置新值时,如果oldValue和newValue相同,则不会触发事件。只有当他们不同的时候
一个例子:
- 我有一个
与包含一些“元素”的列表视图
可观察列表绑定在一起
- 我可以在应用程序的不同位置添加更多元素
- 有一个按钮“开始”启动一个程序-它 遍历列表并对每个元素执行一些操作
过程是另一类。它对元素执行一些操作,还包含
-simpleintegerperty
,以指示当前所选元素的索引currentlyChosenElementIndex
ListView
显示这一点。现在,在该过程中,GUI被阻止,并且当前元素在执行过程中在列表视图上被选中。程序结束后,应用程序将CurrentLyHosenElementIndex重置为零,这是一个索引,我有问题。当过程开始时,第一个元素不会被选择,因为应用程序setValue()
与以前的相同
有什么方法可以改变这一点吗?您不能简单地使用SimpleIntegerProperty
类来实现这一点。但您可以扩展类并添加所需的功能。创建这样一个类
public class NotifySetIntegerProperty extends SimpleIntegerProperty {
private OnSetValueListener valueListener;
public NotifySetIntegerProperty(int initialValue) {
super(initialValue);
}
@Override
public void set(int newValue) {
super.set(newValue);
if(valueListener!= null) {
valueListener.onValueSet(newValue);
}
}
public void setValueListener(OnSetValueListener valueListener) {
this.valueListener = valueListener;
}
public interface OnSetValueListener {
void onValueSet(int value);
}
}
然后您可以使用它,并在调用setValue
或set
方法时收到通知
NotifySetIntegerProperty property = new NotifySetIntegerProperty(0);
property.setValueListener(new NotifySetIntegerProperty.OnSetValueListener() {
@Override
public void onValueSet(int value) {
System.out.println(value);
}
});
property.setValue(1);
property.setValue(0);
将输出
1
0
如果您的过程
的currentlyChosenElementIndex
表示当前正在处理的元素的索引,那么当当前没有处理任何元素时,将其等于0
基本上会使应用程序处于不一致的状态。对于表示索引的内容,通常的约定是使用-1
表示“无值”。因此,我认为将currentlyChosenElementIndex
初始化为-1
,并在过程完成后将其重置为-1
更有意义。(当未选择任何内容时,这也将与选择模型的选定索引一致。)
这意味着您在使用该值时必须小心,以避免任何ArrayIndexOutOfBoundsException
s-即,您必须检查特殊值并单独处理
这里有一个SSCCE:
import java.util.List;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class ProcessListElements extends Application {
private int count = 0 ;
@Override
public void start(Stage primaryStage) {
ListView<String> listView = new ListView<>();
for (int i = 0 ; i < 10 ; i++) addElement(listView.getItems());
Procedure procedure = new Procedure();
Button startProcessButton = new Button("Start Process");
Button addItemButton = new Button("Add item");
Button deleteItemButton = new Button("Delete item");
TextArea log = new TextArea();
startProcessButton.setOnAction(e -> {
log.clear();
listView.requestFocus();
new Thread(() -> procedure.process(listView.getItems())).start();
});
addItemButton.setOnAction(e -> addElement(listView.getItems()));
deleteItemButton.setOnAction(e -> listView.getItems().remove(listView.getSelectionModel().getSelectedIndex()));
deleteItemButton.disableProperty().bind(listView.getSelectionModel().selectedItemProperty().isNull());
HBox controls = new HBox(5, startProcessButton, addItemButton, deleteItemButton);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(listView, null, log, controls, null);
procedure.currentlyChosenElementIndexProperty().addListener((obs, oldIndex, newIndex) -> {
Platform.runLater(() ->
listView.getSelectionModel().clearAndSelect(newIndex.intValue()));
});
procedure.currentlyChosenElementIndexProperty().addListener((obs, oldIndex, newIndex) -> {
Platform.runLater(() -> {
controls.setDisable(newIndex.intValue() != Procedure.NO_ELEMENT);
});
});
procedure.currentlyChosenElementIndexProperty().addListener((obs, oldIndex, newIndex) -> {
if (oldIndex.intValue() != Procedure.NO_ELEMENT) {
log.appendText("Processing of element "+oldIndex.intValue()+" complete\n");
}
if (newIndex.intValue() != Procedure.NO_ELEMENT) {
log.appendText("Processing element "+newIndex.intValue()+" started\n");
}
});
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private void addElement(List<String> list) {
count++ ;
list.add("Item "+count);
}
public static class Procedure {
private static final int NO_ELEMENT = - 1;
private final ReadOnlyIntegerWrapper currentlyChosenElementIndex = new ReadOnlyIntegerWrapper(NO_ELEMENT);
public void process(List<?> items) {
if (Platform.isFxApplicationThread()) {
throw new IllegalStateException("This method blocks and must not be executed on the FX Application Thread");
}
try {
for (int i = 0 ; i < items.size(); i++) {
currentlyChosenElementIndex.set(i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
currentlyChosenElementIndex.set(NO_ELEMENT);
}
public final ReadOnlyIntegerProperty currentlyChosenElementIndexProperty() {
return this.currentlyChosenElementIndex.getReadOnlyProperty();
}
public final int getCurrentlyChosenElementIndex() {
return this.currentlyChosenElementIndexProperty().get();
}
}
public static void main(String[] args) {
launch(args);
}
}
import java.util.List;
导入javafx.application.application;
导入javafx.application.Platform;
导入javafx.beans.property.ReadOnlyIntegerProperty;
导入javafx.beans.property.ReadOnlyIntegraterRapper;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.ListView;
导入javafx.scene.control.TextArea;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.layout.HBox;
导入javafx.stage.stage;
公共类ProcessListElements扩展了应用程序{
私有整数计数=0;
@凌驾
公共无效开始(阶段primaryStage){
ListView ListView=新建ListView();
对于(inti=0;i<10;i++)addElement(listView.getItems());
程序程序=新程序();
按钮启动流程按钮=新按钮(“启动流程”);
按钮addItemButton=新按钮(“添加项”);
按钮deleteItemButton=新按钮(“删除项目”);
TextArea log=新建TextArea();
启动进程按钮。设置操作(e->{
log.clear();
requestFocus();
新线程(()->procedure.process(listView.getItems()).start();
});
addItemButton.setOnAction(e->addElement(listView.getItems());
deleteItemButton.setOnAction(e->listView.getItems().remove(listView.getSelectionModel().getSelectedIndex());
deleteItemButton.disableProperty().bind(listView.getSelectionModel().SelectEditeProperty().isNull());
HBox controls=新HBox(5,StartProcess按钮、addItemButton、deleteItemButton);
控件。设置对齐(位置中心);
控件。设置填充(新插图(5));
BorderPane root=新的BorderPane(listView,null,log,controls,null);
procedure.currentlychosenelementindex exproperty().addListener((obs、旧索引、新索引)->{
Platform.runLater(()->
listView.getSelectionModel().clearAndSelect(newIndex.intValue());
});
procedure.currentlychosenelementindex exproperty().addListener((obs、旧索引、新索引)->{
Platform.runLater(()->{
controls.setDisable(newIndex.intValue()!=Procedure.NO_元素);
});
});
procedure.currentlychosenelementindex exproperty().addListener((obs、旧索引、新索引)->{
if(oldIndex.intValue()!=过程。无\u元素){
log.appendText(“元素处理”+oldIndex.intValue()+“完成”\n”);
}
if(newIndex.intValue()!=Procedure.NO_元素){
log.appendText(“处理元素”+newIndex.intValue()+“已启动”\n”);
}
});
场景=新场景(root,600600);
初级阶段。场景(场景);
primaryStage.show();
}
专用无效补遗(列表){
计数++;
列表。添加(“项目”+计数);
}
公共静态类程序{
私有静态final int NO_元素=-1;
private final ReadOnlyIntegraterRapper CurrentlyHosenElementIndex=新的ReadOnlyIntegraterRapper(无元素);
公共作废流程(列表项){
if(Platform.isFxApplicationThread()){
抛出新的IllegalStateException(“此方法阻塞并且不能执行到
class DelicateSimpleDoubleProperty extends SimpleDoubleProperty{
@Override
public void set( double newValue ) {
if (get() == newValue){
super.set(newValue + 0.0000000000001);
}else {
super.set(newValue);
}
}
}