【问题标题】:JavaFX ListView rendering bug when using custom list cells使用自定义列表单元格时的 JavaFX ListView 呈现错误
【发布时间】:2015-02-22 04:13:17
【问题描述】:

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

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

我能够在一个非常简单的示例中重现这一点。假设我们有一个带有自定义MyListCell 的字符串ListView,使用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

【问题讨论】:

  • 另一个发现:当我用简单的HBox 替换TextFlow 时,我似乎无法重现该问题。

标签: java listview javafx listviewitem


【解决方案1】:

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

您应该做的是在您的ListCell 中重用TextFlow,或者换句话说:将其存储为成员属性并“仅”将其子项设置在updateItem() 方法中。

关于TextFlowHBoxTextFlow 有一个相当复杂的布局机制,因为它内置了(word)换行。因此,如果 HBox 满足您的需求,您应该考虑使用它来代替(当然将其缓存在 ListCell 中)。

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

【讨论】:

  • 我尝试了两种方法:在对象中存储和不存储渲染文本并重用它。没有任何区别,ListViewTextFlow 仍然是错误的。我想这确实是TextFlow 的一些内部属性导致它出错了。此外,我尝试了RichtTextFX.StyleClassedTextArea,它以同样的问题结束。我决定不存储渲染文本的原因是它确实是一个合理的快速操作,因此如果有人真的在日志视图中向后滚动,它可以再次计算。另一方面,如果存储它会占用大量内存。
  • 正如我所猜测的:TextFlow 并不是真的要在 ListView Cell 中使用。或者换句话说:TextFlow 的内部布局需要太多时间同时处理 20-30 个单元格(太多时间 = JavaFX 场景脉冲被限制)。如果 HBox 适合您,请使用它 ;-)
  • 尽管话题老了,不得不说使用 HBox 节点,而不是 TextFlow 解决了我的 ListView 问题。作为话题发起者,我也使用了 updateItem() 方法并花费了大量时间来找到它。谢谢!
  • 100% 这是 TextFlow 的问题,谢谢。
  • 但是有什么办法可以让我在列表滚动上完全渲染文本流迟到吗?
猜你喜欢
  • 1970-01-01
  • 2013-08-17
  • 2013-11-27
  • 2015-02-09
  • 2016-07-23
  • 2016-08-02
  • 1970-01-01
  • 2014-10-04
  • 2019-01-22
相关资源
最近更新 更多