2015-11-25 143 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而不太依賴於對現有類進行子類化,並且(與您的問題相關)對實際實現細節的屬性的暴露程度較低。你可能需要更加努力地編寫代碼,但最終你會得到更好的代碼。 –