2014-12-24 94 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

相关问题