2014-12-24 132 views
4

我正在創建highlighting communication logger,它使用ListView在單個單元格中顯示每條消息。使用自定義列表單元格時的JavaFX ListView呈現錯誤

enter image description here

它基本的工作原理,但是當我滾動速度非常快上下,奇怪的事情發生了。正如你所看到的,我突出顯示了當前選中的單元格和鼠標所在的單元格。在我上下滾動後,突出顯示的單元格不是我的鼠標指針所在的單元格,對於某些單元格,我無法通過單擊來選擇它們。

我能夠通過一個非常簡單的例子重現這一點。假設我們有一個ListView的字符串,用自定義的MyListCell's渲染那些使用TextFlow的單元格。的MyListCellupdateItem方法看起來像這樣

@Override 
    protected void updateItem(String item, boolean empty) { 

    super.updateItem(item, empty); 

    if (empty || item == null) { 
     setText(null); 
     setGraphic(null); 
     return; 
    } 

    TextFlow textFlow = new TextFlow(new Text(item)); 
    setGraphic(textFlow); 
    setText(null); 
    } 

在初始化我只是創建一個新的字符串觀察到的陣列和我相應地設置電池工廠:

public ObservableList<String > content = FXCollections.observableArrayList(); 
public ListView<String> listView; 

@Override 
public void initialize(URL location, ResourceBundle resources) { 

    listView.setCellFactory(cb -> new MyListCell()); 
    listView.setItems(content); 
    /* ... /* 

完整的工作示例代碼只由一些文件(您需要調整包路徑):

問:任何人都可以確認此行爲,並告訴我什麼,我做錯了什麼?

我的系統是Ubuntu的14.04與Oracle JDK 1.8.0_25

+0

另一個發現:當我更換帶有一個簡單的'HBox'的'TextFlow',那麼似乎我不能重現這個問題。 – halirutan

回答

3

基本上JavaFX中創建一個新的Node並將其添加到場景圖是昂貴的操作。這就是爲什麼ListView使用虛擬化佈局容器,在視口更改時重用其單元,而不是創建新的容器。

你應該做的是重新使用TextFlow裏面你ListCell或者換句話說:它存儲作爲成員屬性和「唯一」的設置它的孩子updateItem()方法內。

關於TextFlow vs HBoxTextFlow由於內置(word)包裝,因此具有相當複雜的佈局機制。因此,如果HBox做你需要的,你應該考慮使用它(當然緩存它在ListCell內)。

您可以嘗試通過緩存Text節點來進一步提高這一點。但目前我不能爲您提供了一個簡單的解決方案(在JavaFX的一個Node只能包含在單個節點Parent,使一個簡單的WeakHashMap緩存與computeIfAbsent將無法​​正常工作)..

+0

我嘗試了兩種方法:在和不在對象中存儲渲染文本並重用它。它沒有任何區別,帶'TextFlow'的'ListView'仍然有問題。我想這確實是TextFlow的一些內部屬性,這使得它出錯了。另外,我嘗試了'RichtTextFX.StyleClassedTextArea',它以相同的問題結束。我決定不存儲渲染文本的原因是它確實是一個合理的快速操作,因此如果有人真的在日誌視圖中回滾,可以再次進行計算。另一方面,如果存儲它將使用大量內存。 – halirutan

+0

正如我猜測:TextFlow並非真正用於ListView Cell中。或者換句話說:TextFlow的內部佈局需要20-30個單元同時花費太多時間(太多時間= JavaFX場景脈衝被限制)。如果HBox爲你工作,使用它;-) – eckig

+0

儘管主題舊,不得不說使用HBox節點,而不是TextFlow解決我的問題與ListView。我也作爲主題啓動者,使用updateItem()方法並花費大量時間來找到它。謝謝! – Pavlo

相關問題