我想听听RDX一个阶段userData的变化.我试图将从getUserData方法返回的对象包装在SimpleObjectProperty中,然后向其中添加一个监听器,但没有起作用.

这是我的try :

SimpleObjectProperty<Object> userDataProperty = new SimpleObjectProperty<>(stage.getUserData());
    userDataProperty.addListener((observable, oldValue, newValue) -> {
    // print when userData is changed
    System.out.println("new userdata:" + stage.getUserData());
});

// change the userData to test if the listener work
stage.setUserData(2);
System.out.println(stage.getUserData());
stage.setUserData(3);
System.out.println(stage.getUserData());

输出:

2
3

如何正确做?

推荐答案

Window类不会公开用户数据的PFA属性,这意味着它不可直接观察.然而,Window#setUserData(Object)方法有这个有点神秘的文档:

用于设置可以在以后检索的单个对象属性的方便方法.这在功能上相当于调用getProperties().put(对象键、对象值)方法.稍后可以通过调用getuserData()来检索该内容.

这似乎表明用户数据保存在Window#getProperties()返回的ObservableMap中.如果你查看the implementation,你会发现确实如此.不幸的是,用户数据输入的密钥是私有的.但您可以使用反射来获取密钥,或者更好地使用MapChangeListener来捕获它.

一旦您拥有该密钥,您就可以使用Bindings#valueAt(ObservableMap, K)来创建一个ObjectBinding,该ObjectBinding将始终报告最新的用户数据值.

这是一个使用MapChangeListener来捕获密钥的示例.

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.collections.MapChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;

public class Main extends Application {

  // Make sure to keep a strong reference to the binding for as long as you need it.
  private ObjectBinding<Object> userData;

  @Override
  public void start(Stage primaryStage) {
    userData = userDataBinding(primaryStage);
    // Note: Using _ for unused parameters was standardized in Java 22.
    userData.addListener(
        (_, oldVal, newVal) -> System.out.printf("User data: %s -> %s%n", oldVal, newVal));

    // Type something into the TextField then press ENTER to see the example at work.
    var field = new TextField();
    field.setMaxWidth(Region.USE_PREF_SIZE);
    field.setOnAction(
        e -> {
          e.consume();
          primaryStage.setUserData(field.getText());
          field.clear();
        });

    primaryStage.setScene(new Scene(new StackPane(field), 500, 300));
    primaryStage.show();
  }

  private ObjectBinding<Object> userDataBinding(Window window) {
    // Use array because local variables must be (effectively) final when used inside
    // a lambda expression or anonymous class.
    var keyHolder = new Object[1];
    window
        .getProperties()
        .addListener(
            new MapChangeListener<>() {
              @Override
              public void onChanged(Change<? extends Object, ? extends Object> change) {
                keyHolder[0] = change.getKey();
                // Only need to capture the key once.
                change.getMap().removeListener(this);
              }
            });
    var oldUserData = window.getUserData(); // save current value
    window.setUserData(new Object());       // invoke the listener
    window.setUserData(oldUserData);        // restore to old value
    return Bindings.valueAt(window.getProperties(), keyHolder[0]);
  }
}

从文档来看,相同的方法可以用于SceneNode.


当然,您可以使用自己的 keys 直接操作Window.getProperties() map .这可能会更容易.

Java相关问答推荐

LocalTime解析截断时间的第二个值

如果给定层次 struct 级别,如何从其预序穿越构造n元树

我的scala文件失败了Scala.g4 ANTLR语法

Oracle DUAL表上使用DDL时jOOQ问题的解析'

如何调整工作时间日历中的时间

测试期间未执行开放重写方法

在Eclipse中数组的可空性

对字符串长度进行排序,但颠倒了顺序(最长字符串在前)

使用多个RemoteDatabase对象的一个线程

WebSockets和Spring Boot安全性出现错误401

在Eclipse中调试未导出的JDK模块的Java包

无法使用Freemarker从XML中读取重复的标记值

为什么StandardOpenOption.CREATE不能通过Ubuntu在中小企业上运行?

有谁能帮我修一下这个吗?使输出变得更加整洁

如何生成指定范围内的11位序列号?

对角线填充二维数组

如何将RESTAssured';S的Http标题转换为<;字符串、字符串和>的映射?

如何在Spring Security中设置一个任何人都可以打开的主页?

控制器建议异常处理

无泄漏函数的Java DRY