使用自定义列表单元格时JavaFX ListView呈现错误

时间:2014-12-24 01:06:47

标签: java listview javafx listviewitem

我正在创建一个highlighting communication logger,它使用ListView在单个单元格中显示每条消息。

enter image description here

它基本上有效,但当我上下快速滚动时,会发生奇怪的事情。如您所见,我突出显示当前所选的单元格和鼠标所在的单元格。在我上下滚动后,突出显示的单元格不是我的鼠标指针所在的单元格,对于某些单元格,我无法通过单击选择它们。

我能够在一个非常简单的例子中重现这一点。假设我们有ListView个字符串,其中包含自定义MyListCell,可使用TextFlow呈现这些单元格。 updateItem的{​​{1}}方法看起来像这样

MyListCell

在初始化中我只是创建一个新的可观察字符串数组,并相应地设置单元格工厂:

@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);
  }

完整的工作示例代码仅包含一些文件(您需要调整包路径):

问题:任何人都可以确认这种行为并告诉我我做错了什么吗?

我的系统是Ubuntu 14.04,带有Oracle jdk 1.8.0_25

1 个答案:

答案 0 :(得分:3)

基本上在JavaFX中创建一个新的Node并将其添加到SceneGraph是一项昂贵的操作。这就是为什么ListView使用虚拟化布局容器,在视口更改时重用其单元格而不是创建新单元格。

您应该重复使用TextFlow内的ListCell或换句话说:将其存储为会员属性,并且仅保留""将其子项设置在updateItem()方法中。

关于TextFlow vs HBox:由于内置(单词)换行,TextFlow具有相当复杂的布局机制。因此,如果HBox完成了您的需要,您应该考虑使用它(当然在ListCell中缓存它)。

您可以尝试缓存Text节点,以进一步提升此功能。但是目前我无法为您提供一个简单的解决方案(JavaFX中的Node只能包含在一个Parent节点中,所以一个简单的WeakHashMap缓存带有computeIfAbsent不会工作)..