我正在使用JavaFX为GUI创建聊天应用程序。我在ListView中显示聊天内容,但我有一个大问题 - 它非常慢。当我向列表中添加新项目时,尤其是当我向上/向下滚动列表时。我想也许这与列表刷新itsellf每次添加新项目(列表中的每个单元格!)以及每次向上/向下滚动时刷新的事实有关。 有人知道我该怎么做才能解决这个问题? TNX
我重写了ListCell的updateItem:
chatListView.setCellFactory(new Callback,ListCell>(){ @覆盖 public ListCell调用(ListView p){ ListCell cell = new ListCell(){ @覆盖 protected void updateItem(UserInfo item,boolean bln){ super.updateItem(item,bln);
if (item != null) {
BorderPane borderPane = new BorderPane();
ImageView profileImage = new ImageView(new Image(item.getImageURL()));
profileImage.setFitHeight(32);
profileImage.setFitWidth(32);
Rectangle clip = new Rectangle(
profileImage.getFitWidth(), profileImage.getFitHeight()
);
clip.setArcWidth(30);
clip.setArcHeight(30);
profileImage.setClip(clip);
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
WritableImage image = profileImage.snapshot(parameters, null);
profileImage.setClip(null);
profileImage.setImage(image);
ImageView arrowImage = new ImageView(new Image("arrow1.png"));
ImageView arrowImage2 = new ImageView(new Image("arrow1.png"));
Label nameLabel = new Label(item.getUserName());
nameLabel.setStyle(" -fx-text-alignment: center; -fx-padding: 2;");
HBox hbox = null;
Label textLabel = new Label();
String messageText = splitTolines(item.getMessage());
textLabel.setText(messageText);
textLabel.setStyle("-fx-background-color: #a1f2cd; "
+ "-fx-padding: 10;\n"
+ "-fx-spacing: 5;");
hbox = new HBox(arrowImage, textLabel);
VBox vbox = new VBox(profileImage, nameLabel);
BorderPane.setMargin(vbox, new Insets(0, 10, 10, 10));
BorderPane.setMargin(hbox, new Insets(10, 0, 0, 0));
//Time
Date dNow = new Date();
SimpleDateFormat ft = new SimpleDateFormat("hh:mm a");
Label timeLabel = new Label(ft.format(dNow));
timeLabel.setStyle("-fx-font: 8px Tahoma; -fx-width: 100%");
HBox hbox2 = new HBox(arrowImage2, timeLabel);
arrowImage2.setVisible(false);
VBox vbox2 = new VBox(hbox, hbox2);
borderPane.setCenter(vbox2);
borderPane.setLeft(vbox);
setGraphic(borderPane);
}
}
};
return cell;
}
});
答案 0 :(得分:3)
从未在updateItem()
中添加(大)GUI元素,而不检查它是否已存在。
updateItem()
。 updateItem(item, empty)
的第二个布尔值为false,您应该总是将图形重置为null ,因为第二个布尔值是 EMPTY 强>旗帜。 我建议您使用VBox
代替ListView
。
答案 1 :(得分:0)
每次更新视图时,都不得构建组件的新实例。
首先对它们进行一次初始化,然后重复使用并更改其属性。
答案 2 :(得分:0)
我也注意到了这一点。即使对于仅包含5-10个项目的列表(具有缩放图像和文本),它也太慢。由于我不需要选择功能,我也重写了代码以使用VBox而且速度很快就会消失!
为了模拟setItems,我有一个你可以找到的辅助函数:
public static <S, T> void mapByValue(
ObservableList<S> sourceList,
ObservableList<T> targetList,
Function<S, T> mapper)
{
Objects.requireNonNull(sourceList);
Objects.requireNonNull(targetList);
Objects.requireNonNull(mapper);
targetList.clear();
Map<S, T> sourceToTargetMap = new HashMap<>();
// Populate targetList by sourceList and mapper
for (S s : sourceList)
{
T t = mapper.apply(s);
targetList.add(t);
sourceToTargetMap.put(s, t);
}
// Listen to changes in sourceList and update targetList accordingly
ListChangeListener<S> sourceListener = new ListChangeListener<S>()
{
@Override
public void onChanged(ListChangeListener.Change<? extends S> c)
{
while (c.next())
{
if (c.wasPermutated())
{
for (int i = c.getFrom(); i < c.getTo(); i++)
{
int j = c.getPermutation(i);
S s = sourceList.get(j);
T t = sourceToTargetMap.get2(s);
targetList.set(i, t);
}
}
else
{
for (S s : c.getRemoved())
{
T t = sourceToTargetMap.get2(s);
targetList.remove2(t);
sourceToTargetMap.remove2(s);
}
int i = c.getFrom();
for (S s : c.getAddedSubList())
{
T t = mapper.apply(s);
targetList.add(i, t);
sourceToTargetMap.put(s, t);
i += 1;
}
}
}
}
};
sourceList.addListener(new WeakListChangeListener<>(sourceListener));
// Store the listener in targetList to prevent GC
// The listener should be active as long as targetList exists
targetList.addListener((InvalidationListener) iv ->
{
Object[] refs = { sourceListener, };
Objects.requireNonNull(refs);
});
}
然后可以像:
一样使用它ObservableList<Bookmark> bookmarkList;
VBox bookmarkListVBox;
mapByValue(bookmarkList, bookmarkListVBox.getChildren(), bmk -> new Label(bmk.getName());
从可观察列表中自动更新列表(VBox的子节点)。
PS:其他功能如分组在这里=&gt; ObservableListHelper