2015-11-25 84 views
1

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

我在找什么不存在的东西吗?如果是这样,那么为什么JavaFX不包含此功能(恕我直言,它应该)有什么好理由?

感谢您的反馈!

+0

AFAIK无法访问JavaFX中的用户。你能举个例子说明你为什么需要他们(或者认为你是这样做的)?我从来没有遇到需要这样做。 –

+0

正如我在我的问题中提到的,我试图避免多次注册与侦听器相同的对象。一个可能发生这种情况的用例会在附加评论中出现,但请相信我有可能,并且当它发生时,事件被触发到侦听器的次数与侦听器出现在事件侦听器列表中的次数相同。效率低下,不必要,因为听众几乎总是(99.9999999%的时间)需要处理事件 – jfr

+0

是的,我明白:我从来没有遇到过你不知道听众是否已经注册的情况。这是我想知道的用例。 –

回答

0

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

我不确定我真的看到这个需求。你的代码可以控制添加和删除监听器的时间,所以当添加监听器时你基本上总是“知道”。从更广泛的意义上讲,您的用户界面或用户界面组件始终是某种形式数据的呈现形式,因此,是否注册监听器只是这些数据的功能。

对于一个具体的例子,考虑使用的情况下在评论中引用:

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.... 
} 

在这个例子中,你可能只需要使用一个结合,而不是听众:

button.prefWidthProperty().bind(Bindings 
    .when(orientationProperty().isEqualTo(Orientation.HORIZONTAL)) 
    .then(Control.USE_COMPUTED_SIZE) 
    .otherwise(textField.widthProperty())); 

但没有证明这个概念......

请注意,正如在@Clemens评论中一样,您可以始终确保一个听众只用一次成语注册一次:

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

但是这只是在我看来不是非常好的做法:removeListener涉及迭代通过侦听器列表中(和在它尚未加入的情况下,听众的整个列表)。这种迭代是不必要的,因为信息已经在其他地方可用。

+0

感谢您的回复,在阅读您的示例b/c时不得不做两次采访,与我自己的代码相似是不可思议的。你的建议重新绑定到我这里来散步,这可能是这种特殊情况下最有效的解决方案。原始问题的原因是与Swing合作开发的事件模型,它是许多其他模型的祖先,并且运行良好。在切换到JavaFX时,我试图保留Swing中的好东西(至少是进程)并将它们转换为新格式。当这是不可能的,我想知道为什么。 – jfr

+0

我认为我们可能不同意暴露听众名单是否是Swing“好东西”的一部分。对我来说,这是一种代码味道([“不适当的亲密”](https://en.wikipedia.org/wiki/Code_smell))。如果你有'addListener'和'removeListener'方法,你为什么需要公开列表;或者相反,如果你公开这个列表,为什么还要有其他方法? Richard Bair(JavaFX的首席架构师,在Swing上突出)有一次有趣的采访,他说:“在Swing中我们打破了很多人的代码”。 (继续...) –

+0

我认为JavaFX虽然离完美还很远,但在良好的OOP方面(主要是在各个版本的首次发布之间理解的概念)方面,对Swing的改进很多:您将在其中看到更多的“final”方法JavaFX旨在强制执行类不变量,并且您会发现您可以编写JavaFX而不太依赖于对现有类进行子类化,并且(与您的问题相关)对实际实现细节的属性的暴露程度较低。你可能需要更加努力地编写代码,但最终你会得到更好的代码。 –