Javafx ObserviveValue更改侦听器:如何访问

Javafx ObserviveValue更改侦听器:如何访问,javafx,changelistener,Javafx,Changelistener,我是JavaFX新手,已经开始转换用Swing编写的自定义组件。作为一种最佳实践,我总是检查事件侦听器(PropertyChangeListener、MouseListener、ActionListener等)是否已包含在目标对象的侦听器中,以确保不会添加同一个侦听器两次。我正试图对JavaFX执行同样的操作,但找不到任何方法来访问侦听器列表(例如,运行list.contains(listener)检查) 我在寻找不存在的东西吗?如果是这样的话,JavaFX没有包含这个特性有什么好的理由吗 谢谢

我是JavaFX新手,已经开始转换用Swing编写的自定义组件。作为一种最佳实践,我总是检查事件侦听器(PropertyChangeListener、MouseListener、ActionListener等)是否已包含在目标对象的侦听器中,以确保不会添加同一个侦听器两次。我正试图对JavaFX执行同样的操作,但找不到任何方法来访问侦听器列表(例如,运行list.contains(listener)检查)

我在寻找不存在的东西吗?如果是这样的话,JavaFX没有包含这个特性有什么好的理由吗


谢谢你的反馈

公共API中没有访问JavaFX中属性的侦听器列表的机制

我不确定我是否真的认为有必要这样做。您的代码控制何时添加和删除侦听器,因此您基本上总是“知道”何时添加了侦听器。从更广泛的意义上讲,您的UI或UI组件始终是某种形式的数据的表示,因此侦听器是否注册只是这些数据的一个函数

一个具体的例子,考虑评论中引用的用例:

public class CustomComponent extends BorderPane {

    private final Button button = new Button("Button");
    private final TextField textField = new TextField();

    private final ObjectProperty<Orientation> orientation = new SimpleObjectProperty<>();

    public ObjectProperty<Orientation> orientationProperty() {
        return orientation ;
    }

    public final Orientation getOrientation() {
        return orientationProperty().get();
    }

    public final void setOrientation(Orientation orientation) {
        orientationProperty().set(orientation);
    }

    public CustomControl(Orientation orientation) {
        setCenter(textField);

        ChangeListener<Number> widthBindingListener = (obs, oldWidth, newWidth) ->
            button.setPrefWidth(newWidth.doubleValue());

        orientationProperty().addListener((obs, oldOrientation, newOrientation) -> {
            if (newOrientation == Orientation.HORIZONTAL) {
                textField.widthProperty().removeListener(widthBindingListener);
                button.setPrefWidth(Control.USE_COMPUTED_SIZE);
                setTop(null);
                setLeft(button);
            } else {
                textField.widthProperty().addListener(widthBindingListener);
                button.setPrefWidth(textField.getWidth());
                setLeft(null);
                setTop(button);
            }
        }

        setOrientation(orientation);

    }

    public CustomControl() {
        this(Orientation.VERTICAL);
    }

    // other methods etc....
}
但这并不能证明这个概念

请注意,正如在@Clemens comment中一样,您可以始终确保侦听器只使用以下习惯用法注册一次:

textField.widthProperty().removeListener(widthBindingListener);
textField.widthProperty().addListener(widthBindingListener);

但在我看来,这似乎不是一个很好的实践:
removeListener
涉及到遍历侦听器列表(如果尚未添加,则遍历整个侦听器列表)。此迭代是不必要的,因为信息已经在其他地方可用。

公共API中没有访问JavaFX中属性的侦听器列表的机制

我不确定我是否真的认为有必要这样做。您的代码控制何时添加和删除侦听器,因此您基本上总是“知道”何时添加了侦听器。从更广泛的意义上讲,您的UI或UI组件始终是某种形式的数据的表示,因此侦听器是否注册只是这些数据的一个函数

一个具体的例子,考虑评论中引用的用例:

public class CustomComponent extends BorderPane {

    private final Button button = new Button("Button");
    private final TextField textField = new TextField();

    private final ObjectProperty<Orientation> orientation = new SimpleObjectProperty<>();

    public ObjectProperty<Orientation> orientationProperty() {
        return orientation ;
    }

    public final Orientation getOrientation() {
        return orientationProperty().get();
    }

    public final void setOrientation(Orientation orientation) {
        orientationProperty().set(orientation);
    }

    public CustomControl(Orientation orientation) {
        setCenter(textField);

        ChangeListener<Number> widthBindingListener = (obs, oldWidth, newWidth) ->
            button.setPrefWidth(newWidth.doubleValue());

        orientationProperty().addListener((obs, oldOrientation, newOrientation) -> {
            if (newOrientation == Orientation.HORIZONTAL) {
                textField.widthProperty().removeListener(widthBindingListener);
                button.setPrefWidth(Control.USE_COMPUTED_SIZE);
                setTop(null);
                setLeft(button);
            } else {
                textField.widthProperty().addListener(widthBindingListener);
                button.setPrefWidth(textField.getWidth());
                setLeft(null);
                setTop(button);
            }
        }

        setOrientation(orientation);

    }

    public CustomControl() {
        this(Orientation.VERTICAL);
    }

    // other methods etc....
}
但这并不能证明这个概念

请注意,正如在@Clemens comment中一样,您可以始终确保侦听器只使用以下习惯用法注册一次:

textField.widthProperty().removeListener(widthBindingListener);
textField.widthProperty().addListener(widthBindingListener);

但在我看来,这似乎不是一个很好的实践:
removeListener
涉及到遍历侦听器列表(如果尚未添加,则遍历整个侦听器列表)。此迭代是不必要的,因为信息已经在其他地方可用。

AFAIK无法访问JavaFX中的信息。你能举个例子说明为什么你需要它们(或者你认为你需要)?我从来没有遇到过这样做的需要。正如我在问题中提到的,我试图避免将同一对象注册为侦听器多次。下面是一个可能发生这种情况的用例,但请相信我,这是可能的,并且当它发生时,事件被激发到侦听器的次数与侦听器在事件侦听器列表中出现的次数相同。低效且不必要,因为听众几乎总是(99.9999999%的时间)需要处理事件。是的,我明白:我从来没有遇到过这样的情况:你不知道听众是否已经注册。这就是我想知道的用例。。。仅处理事件一次。另外——这引起了我的注意——JavaFX文档特别指出,如果侦听器注册了多次,那么调用[list].RemovelListener()只会删除列表中的第一个条目。换句话说,如果你认为你已经删除了一个监听器,并且不知何故它被添加到了列表中两次,你可能会想为什么监听器仍然处理这个事件。你可能只是在添加它之前删除了一个监听器。来自:如果给定的侦听器以前没有注册过(即从未添加过),则此方法调用是不可操作的。他们在框架中这样做,例如在
com.sun.javafx.binding.ContentBinding.bind()
methods.AFAIK中,无法访问javafx中的方法。你能举个例子说明为什么你需要它们(或者你认为你需要)?我从来没有遇到过这样做的需要。正如我在问题中提到的,我试图避免将同一对象注册为侦听器多次。下面是一个可能发生这种情况的用例,但请相信我,这是可能的,并且当它发生时,事件被激发到侦听器的次数与侦听器在事件侦听器列表中出现的次数相同。低效且不必要,因为听众几乎总是(99.9999999%的时间)需要处理事件。是的,我明白:我从来没有遇到过这样的情况:你不知道听众是否已经注册。这就是我想知道的用例。。。仅处理事件一次。另外——这引起了我的注意——JavaFX文档特别指出,如果侦听器注册了多次,那么调用[list].RemovelListener()只会删除列表中的第一个条目。换句话说,如果你认为你已经删除了一个监听器,并且不知何故它被添加到了列表中两次,你可能会想为什么监听器仍然处理这个事件。你可能只是在添加它之前删除了一个监听器。来自:如果给定的侦听器以前没有注册过(即从未添加过),则此方法调用是不可操作的。他们在框架中这样做,例如在
com.sun.javafx.binding.ContentBinding.bind()
方法中。感谢您的回复,在阅读您的示例b/c时,必须进行双重拍摄,它与我自己的代码非常相似。我在出去散步时听到了你关于重新绑定的建议,这可能是针对这种特殊情况最有效的解决方案。原始问题的原因是在