起初我的问题是如何让一个新添加的行在JavaFx中闪烁,然后我经历了很多与这个主题相关的问题(例如javafx:表行闪烁)。他们中的大多数人都在使用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;
}
}
}
}
});
}
}
在这里,ListChangeListener与table.getItems()相关联,这有助于我记录新插入的行。
可以在一个操作中添加多行,这意味着newAdded.size()可以大于1。此外,行是从tableView的顶部插入的(因为我使用Number对其进行排序。)
在tableView中,并非所有行都是可见的,updateItem方法只更新那些可见的行。当这两种情况发生时,我的问题就来了(见下文)。
第一种情况
在第一种情况下,只有4行可见,如果用户在一次内插入5行,我无法记录最后一行更新(new_row_5不会调用updateItem)。因此,我无法清除newAdded列表(通过执行 newAdded.clear())
第二种情况
在第二种情况下,只有 4 行再次可见。但是,在可见行的顶部和底部都有不可见的行。如果用户插入 2 行,则一行可见,另一行不可见。就我而言,new_row_2会闪烁,而new_row_1仍然不可见。如果用户在new_row_2闪烁时向上滚动 tableView,他将看到new_row_2在闪烁,而new_row_1不是,这真的很奇怪。
我还想知道是否有任何方法可以找到可见行数。
我还是JavaFx的新手,我不知道这个方法是否好。我希望有人能帮我解决问题。谢谢!
你的方法看起来不像是一个干净的方法。动画取决于项目所在的< code>TableRow,并且似乎不支持同时出现多个动画。此外,它依赖于item类的< code>equals方法不会被覆盖,并且依赖于用户不会将一个项目多次添加到< code>TableView中。此外,您可能会创建大量的< code>Timeline(不必从单独的线程btw启动它们,因为< code>Timeline.play()不会阻塞)。
最好使动画依赖于索引。此外,跟踪创建的 TableRow
还允许您访问现有单元格,如果为它们分配了需要动画的索引。您也可以使用单个动画计时器处理动画
,方法是将数据存储在合适的数据结构中。
此外,使用< code>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));
}
}
}
在重定向的情况下,Flash消息似乎会被破坏。我编写了简单的测试代码: 我调用不带参数的操作,它会添加一个flash并重定向。当它呈现页面时-flash不存在。 视图部分很好,因为如果我设置flash并在不重定向的情况下进行渲染,它会正确渲染。 为什么? 编辑:布局视图代码:
我怎样才能使背景色在每次按下按钮时连续闪现2个新颜色?现在它只显示两种颜色,但它们不会连续闪烁或闪烁。
这是因为在开发模式下,为了通过 Webpack 实现热加载,CSS代码是打包在 JavaScript 代码中,并动态打到页面中去,从而元素重绘引起了闪烁。 不用担心,在生产模式下,CSS代码会单独打包至独立的文件并置于head标签内,不会出现页面闪烁的现象。
本文向大家介绍如何使用JavaScript创建闪烁文本?,包括了如何使用JavaScript创建闪烁文本?的使用技巧和注意事项,需要的朋友参考一下 要创建闪烁的文本,请使用JavaScript方法。此方法使字符串闪烁,就像在BLINK标记中一样。 注–不推荐使用HTML <blink>标记,并且并非在所有浏览器中都适用。 示例 您可以尝试运行以下代码以使用JavaScript方法创建闪烁的文本-
我在Lollipop上的共享元素转换中看到了奇怪的事情。共享元素在开始动画之前闪烁(请看视频https://www.youtube.com/watch?v=DCoyyC_S-9A) 我不知道为什么会这样。但是,当我添加
我在约束布局中有一些视图。我使用动画来显示和隐藏视图。当视图消失时,它会闪烁一秒钟,然后变为可见,然后消失。
我试图用pyplay制作一个游戏,我几乎完成了,但我想让被画在墙上的盒子不闪烁,这些红色的盒子在整个游戏中闪烁,我不想让它们闪烁,最后,我在一个if条件下调用player碰撞函数,在这里每当我制作新的碰撞器时,我每次都要在if条件下添加函数,我想要的是碰撞器对象自动调用这个函数,而不需要我在if语句中为碰撞器的每个实例调用它对象。请指导我如何这样做。
减低闪烁 以Interlace(交错扫描)方式在电视机输出PSP™规格软件的影像时,设定是否要减低画面的闪烁。 关 不减低画面的闪烁。 开 减低画面的闪烁。