2015-09-10 23 views
0

有沒有一種方法可以確定列表視圖的第一個和最後一個可見行?換句話說,我正在尋找兩個索引到一個數組中,該數組填充了一個代表'顯示窗口'的頂部和底部行的列表視圖。javafx 8 listview第一行和最後一行

回答

1

你可以得到ListView的VirtualFlow,它具有獲取第一行和最後一行的方法。

例子:

import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.Event; 
import javafx.scene.Scene; 
import javafx.scene.control.IndexedCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.layout.Priority; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

import com.sun.javafx.scene.control.skin.VirtualFlow; 

public class ListViewSample extends Application { 

    @Override 
    public void start(Stage stage) { 
     VBox box = new VBox(); 

     ListView<Integer> list = new ListView<>(); 

     ObservableList<Integer> items = FXCollections.observableArrayList(); 
     for(int i=0; i < 100; i++) { 
      items.add(i); 
     } 
     list.setItems(items); 

     box.getChildren().add(list); 

     VBox.setVgrow(list, Priority.ALWAYS); 

     Scene scene = new Scene(box, 200, 200); 
     stage.setScene(scene); 
     stage.show(); 

     VirtualFlow flow = (VirtualFlow) list.lookup(".virtual-flow"); 
     flow.addEventFilter(Event.ANY, event -> { 

      IndexedCell first = flow.getFirstVisibleCellWithinViewPort(); 
      IndexedCell last = flow.getLastVisibleCellWithinViewPort(); 

      System.out.println(list.getItems().get(first.getIndex()) + " - " + list.getItems().get(last.getIndex())); 

     }); 

    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

您在控制檯中看到的完全可見的第一個和最後一個項目。

PS:我離開沒有數據校驗和事件處理你


沒有CSS查找替代版本:

import javafx.application.Application; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.event.Event; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.control.IndexedCell; 
import javafx.scene.control.ListView; 
import javafx.scene.control.ScrollBar; 
import javafx.scene.layout.Priority; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

import com.sun.javafx.scene.control.skin.VirtualFlow; 

public class ListViewSample extends Application { 

    ListView<String> list = new ListView<String>(); 

    @Override 
    public void start(Stage stage) { 
     VBox box = new VBox(); 

     ListView<Integer> list = new ListView<>(); 

     ObservableList<Integer> items = FXCollections.observableArrayList(); 
     for(int i=0; i < 100; i++) { 
      items.add(i); 
     } 
     list.setItems(items); 

     box.getChildren().add(list); 

     VBox.setVgrow(list, Priority.ALWAYS); 

     Scene scene = new Scene(box, 200, 200); 
     stage.setScene(scene); 
     stage.show(); 

     VirtualFlow virtualFlow = null; 
     for(Node node: list.getChildrenUnmodifiable()) { 
      if(node instanceof VirtualFlow) { 
       virtualFlow = (VirtualFlow) node; 
      } 
     } 

     final VirtualFlow flow = virtualFlow; 
     flow.addEventFilter(Event.ANY, event -> { 

      IndexedCell first = flow.getFirstVisibleCellWithinViewPort(); 
      IndexedCell last = flow.getLastVisibleCellWithinViewPort(); 

      System.out.println(list.getItems().get(first.getIndex()) + " - " + list.getItems().get(last.getIndex())); 

     }); 

    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

偉大的解決方案 - 謝謝你羅蘭。我正在加快JavaFX8的速度,但我沒有聽說過VirtualFlow。我有幾本關於JavaFX的書,但沒有提到VirtualFlow。即使使用谷歌搜索這個主題帶來了驚人的結果。所以,感謝你的啓發。 – Frank

+0

我也沒有。只需進入JavaFX的源代碼,你會發現比任何書都能顯示更多的東西;-) – Roland

+0

我可以再問一個關於此的問題嗎?運行你的例子後,我想「是的,就是這樣」。但是快樂是短暫的。一旦我將它添加到我的應用程序中,我一直得到NullPointerExceptions。所以回到Google試圖找出原因。那是當我發現這個: 答案的要點是你需要訪問TableViewSkin的VirtualFlow成員。這並不像聽起來那麼簡單,因爲皮膚在CSS解析之前不會被加載。我添加了一個Listener到TableView的skinProperty,並且能夠以這種方式獲得VirtualFlow。 仍在搜索流..... ;-) – Frank

0

UPDATE

VirtualFlow後纔可用ListView已被渲染,因爲它使用佈局參數,直到ListView在st上可見後纔可用年齡。所以我必須在確定ListView已經被渲染時確保我獲得了VirtualFlow。由於我是操縱各種方法列表我在每個方法的末尾調用此方法:

private VirtualFlow flow; 

private void updateListView(int centreIndex) {  

    if (flow == null) 
     flow = (VirtualFlow) myListView.lookup(".virtual-flow"); 

    if (flow != null){ 
     IndexedCell first = flow.getFirstVisibleCellWithinViewPort(); 
     IndexedCell last = flow.getLastVisibleCellWithinViewPort(); 

     System.out.println(first.getIndex() + " - " + last.getIndex()); 
    } 

// Now the list can be selectively 'redrawn' using the scollTo() method, 
// and using the .getSelectionModel().select(centreIndex) to set the 
// desired cell 

} 

這是一個黑客一點,但它的工作原理。使用佈局參數確實有一個缺點,但需要考慮。如果ListView的高度僅比所有行的總高度小1個像素,則會看到n行,但流程會報告n-1行,這些行起初會顯示爲差異。因此保持固定的佈局高度是勢在必行的。至少現在通過使用scrollTo(..)我可以控制列表中選定項目的位置(當項目在列表中拖動時,我想保持它在列表顯示中居中)。這種解決方案讓我感到不安,但它似乎是唯一的「簡單」方式。

只是一個注意奇怪的邏輯。在程序繼續執行的過程中,獲取流程似乎需要時間。第二個(flow!= null)是避免NullPointerException所必需的。

+0

如果你不需要它們是完全可見的,你可能還想嘗試getFirstVisibleCell()和getLastVisibleCell()。 – Roland

0

更新2

我的黑客事實證明不起作用。整個黑客依賴於時間。渲染是在不同的線程上完成的,一旦我改變了應用中類的實例化順序,我又一次得到了NullPointerException。我轉向Java文檔:

「JavaFX不是線程安全的,所有JavaFX操作都應該在JavaFX處理線程上運行。如果允許JavaFX應用程序與除主處理線程之外的其他線程交互,那麼不可預知的錯誤會發生「

他們這樣做!所以忘了上述 - 它不工作,並會讓你撓頭(以及更多!)試圖調試它;-)

相關問題