gpt4 book ai didi

java - 即使不可见,如何让tableRow闪烁? (JavaFX)

转载 作者:行者123 更新时间:2023-12-01 09:16:00 24 4
gpt4 key购买 nike

起初我的问题是如何让JavaFx中新添加的行闪烁,然后我遇到了很多与该主题相关的问题(例如 javafx: table row flashing )。他们中的大多数都使用 setRowFactory 并通过添加改变伪类状态的时间轴动画来覆盖 updateItem 方法行的。下面是我的代码,我正在尝试构建一个可以重用的FlashControl。

public class TableFlashControl<T> {

private PseudoClass flashHighlight = PseudoClass.getPseudoClass("flash-highlight");
private List<T> newAdded = new ArrayList<>();
private boolean isFilterApplied = false;
private boolean isSorted = false;

public void setIsFilterApplied(boolean isFilterApplied) {
this.isFilterApplied = isFilterApplied;
}

public void add(TableView<T> table){
ListChangeListener<T> change = c -> {
while (c.next()) {
if (c.wasAdded()) {
List<? extends T> added = c.getAddedSubList();
T lastAdded = added.get(0);
if (!isFilterApplied) {
newAdded.add(lastAdded);
}
}
}
};
table.getItems().addListener(change);
table.setRowFactory(param -> new TableRow<T>() {
@Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
return;
}
if (newAdded.contains(item)) {
if (isSorted) {
new Thread(()->{
Timeline flasher = new Timeline(
new KeyFrame(Duration.seconds(0.4), e -> pseudoClassStateChanged(flashHighlight, true)),
new KeyFrame(Duration.seconds(0.8), e -> pseudoClassStateChanged(flashHighlight, false))
);
flasher.setCycleCount(2);
flasher.play();
}).start();
if (item == newAdded.get(0)) {
newAdded.clear();
isSorted = false;
}

}else{
if(item == newAdded.get(0)){
isSorted = true;
}

}
}

}
});
}
}

这里ListChangeListenertable.getItems()关联,它可以帮助我记录新插入的行。

可以在一次操作中添加多行,这意味着 newAdded.size() 可以大于 1。此外,行是从 tableView 的顶部插入的(因为我用数字对其进行排序。)

在 tableView 中,并非所有行都是可见的,并且 updateItem 方法仅更新那些可见的行。当这两种情况发生时我的问题就出现了(见下文)。

第一个场景

The first scenario

在第一种情况下,只有4行可见,如果用户一次插入5行,我无法记录最后一行更新(new_row_5不会调用updateItem) )。因此,我无法清除 newAdded 列表(通过执行 newAdded.clear())

第二种情况

The second scenario

在第二种情况下,只有 4 行再次可见。但是,可见行的顶部和底部都有不可见的行。如果用户插入 2 行,一行将可见,另一行将不可见。就我而言,new_row_2 将闪烁,而 new_row_1 保持不可见。如果用户在 new_row_2 闪烁时向上滚动 tableView,他将看到 new_row_2 正在闪烁,而 new_row_1确实很奇怪。

我也想知道是否有办法找到可见行数。

我对JavaFx还是个新手,不知道这个方法好不好。我希望有人能帮助我解决我的问题。非常感谢!

最佳答案

您的方法似乎不是一个干净的方法。动画取决于项目所在的 TableRow,并且似乎不支持同时发生多个动画。此外,它依赖于项目类的 equals 方法未被覆盖,并且依赖于用户不向 TableView 多次添加项目。此外,您还可能创建大量的 Timeline(顺便说一句,不必从单独的线程启动它们,因为 Timeline.play() 不会阻塞)。

最好让动画依赖于索引。此外,跟踪创建的 TableRow 允许您访问现有单元格(如果它们被分配了需要动画的索引)。您还可以通过将数据存储在合适的数据结构中,使用单个 AnimationTimer 来处理动画。

恕我直言,使用 rowFactory 类来实现此逻辑是最方便的。

以下示例使行闪烁,无论它们是否在屏幕上。

public class FlashTableRowFactory<T> implements Callback<TableView<T>, TableRow<T>> {

private final static PseudoClass FLASH_HIGHLIGHT = PseudoClass.getPseudoClass("flash-highlight");

public FlashTableRowFactory(TableView<T> tableView) {
tableView.getItems().addListener((ListChangeListener.Change<? extends T> c) -> {
while (c.next()) {
if (c.wasPermutated()) {
int from = c.getFrom();
int to = c.getTo();
permutationUpdate(scheduledTasks, c, from, to);
permutationUpdate(unscheduledTasks, c, from, to);
}
if (c.wasReplaced()) {
addRange(c.getFrom(), c.getTo());
} else if (c.wasRemoved()) {
int from = c.getFrom();
int removed = c.getRemovedSize();
removeRange(scheduledTasks, from, from + removed);
removeRange(unscheduledTasks, from, from + removed);
modifyIndices(unscheduledTasks, from, -removed);
modifyIndices(scheduledTasks, from, -removed);
} else if (c.wasAdded()) {
int from = c.getFrom();
int to = c.getTo();
modifyIndices(unscheduledTasks, from, to - from);
modifyIndices(scheduledTasks, from, to - from);
addRange(from, to);
}
}

// remove all flashTasks that are older than the youngest for a
// given index
Set<Integer> indices = new HashSet<>();
removeDuplicates(unscheduledTasks, indices);
removeDuplicates(scheduledTasks, indices);

flashingIndices.clear();
updateFlash(lastUpdate);
refreshFlash();
if (!unscheduledTasks.isEmpty()) {
flasher.start();
}
});
this.tableView = tableView;
}

private static void removeDuplicates(List<FlashTask> list, Set<Integer> found) {
for (Iterator<FlashTask> iterator = list.iterator(); iterator.hasNext();) {
FlashTask next = iterator.next();
if (!found.add(next.index)) {
iterator.remove();
}
}
}

private static void modifyIndices(List<FlashTask> list, int minModify, int by) {
for (FlashTask task : list) {
if (task.index >= minModify) {
task.index += by;
}
}
}

private void addRange(int index, int to) {
for (; index < to; index++) {
unscheduledTasks.add(new FlashTask(index));
}
}

private static void removeRange(List<FlashTask> list, int from, int to) {
for (Iterator<FlashTask> iterator = list.iterator(); iterator.hasNext();) {
FlashTask next = iterator.next();
if (next.index >= from && next.index < to) {
iterator.remove();
}
}
}

private static void permutationUpdate(List<FlashTask> list, ListChangeListener.Change<?> c, int from, int to) {
for (FlashTask task : list) {
if (task.index < to && task.index >= from) {
task.index = c.getPermutation(task.index);
}
}
}

// set of item indices that should flash
private final Set<Integer> flashingIndices = new HashSet<>();

// references to every row created by this factory
private final List<SoftReference<TableRow<T>>> rows = new LinkedList<>();

// tasks waiting to be scheduled
private final List<FlashTask> unscheduledTasks = new LinkedList<>();

// tasks currently being animated
private final List<FlashTask> scheduledTasks = new LinkedList<>();

private static class FlashTask {

int index;
long schedulingTime;

public FlashTask(int index) {
this.index = index;
}

}

private final TableView<T> tableView;
private long lastUpdate;

/**
* Updates flashingIndices set
* @param now the current timestamp
* @return true if the set has been modified, otherwise false.
*/
private boolean updateFlash(long now) {
boolean modified = false;
for (Iterator<FlashTask> iterator = scheduledTasks.iterator(); iterator.hasNext();) {
FlashTask next = iterator.next();

// running time in seconds
double runningTime = (now - next.schedulingTime) / (1000d * 1000d * 1000d);

// slows down the animation for demonstration
final double animationSpeed = 0.1;

if (runningTime < 0.4 / animationSpeed) {
// no need to handle tasks that run for less than 0.4 seconds
break;
} else if (runningTime > 1.6 / animationSpeed) {
// end of task reached
iterator.remove();
modified |= flashingIndices.remove(next.index);
} else if (runningTime > 0.8 / animationSpeed && runningTime < 1.2 / animationSpeed) {
// second "inactive" interval during animation
modified |= flashingIndices.remove(next.index);
} else {
// activate otherwise
modified |= flashingIndices.add(next.index);
}
}
return modified;
}

private final AnimationTimer flasher = new AnimationTimer() {

@Override
public void handle(long now) {
lastUpdate = now;

// activate waiting flash tasks
for (FlashTask task : unscheduledTasks) {
task.schedulingTime = now;
}
scheduledTasks.addAll(unscheduledTasks);
unscheduledTasks.clear();

if (updateFlash(now)) {
refreshFlash();
if (scheduledTasks.isEmpty()) {
// stop, if there are no more tasks
stop();
}
}
}

};

/**
* Sets the pseudoclasses of rows based on flashingIndices set
*/
private void refreshFlash() {
for (Iterator<SoftReference<TableRow<T>>> iterator = rows.iterator(); iterator.hasNext();) {
SoftReference<TableRow<T>> next = iterator.next();
TableRow<T> row = next.get();
if (row == null) {
// remove references claimed by garbage collection
iterator.remove();
} else {
row.pseudoClassStateChanged(FLASH_HIGHLIGHT, flashingIndices.contains(row.getIndex()));
}
}
}

@Override
public TableRow<T> call(TableView<T> param) {
if (tableView != param) {
throw new IllegalArgumentException("This factory can only be used with the table passed to the constructor");
}
return new FlashRow();
}

private class FlashRow extends TableRow<T> {

{
rows.add(new SoftReference<>(this));
}

@Override
public void updateIndex(int i) {
super.updateIndex(i);

// update pseudoclass based on flashingIndices set
pseudoClassStateChanged(FLASH_HIGHLIGHT, flashingIndices.contains(i));
}

}

}

关于java - 即使不可见,如何让tableRow闪烁? (JavaFX),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40542788/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com