JavaFX 如何交换GridPane节点并同步过渡动画与数据更新?
问题根因
- JavaFX UI操作限制:所有UI控件属性(
ImageView的图片、Label的文本等)的修改必须在JavaFX Application Thread中执行,你在自定义子线程直接修改ImageView的图片属于非法操作,会出现渲染异常。 - 执行时序错位:启动动画子线程后,你直接在主线程同步执行了Label数值交换、列表更新逻辑,动画需要数秒才能执行完成,而数据更新逻辑瞬间执行完毕,导致动画还在跑的时候数据已经被修改。
修复实现
首先确保导入JavaFX的UI线程调度类:
import javafx.application.Platform;
修改后的insertFront方法代码如下:
public void insertFront() { System.out.println("InsertList before insert "+ insertList.size()+" : "+insertList); if (insertList.size() == 0){ ObservableList<Node> nodes = insertArr[0].getChildren(); Label temp = (Label) nodes.get(1); insertList.add(random.nextInt(999)); temp.setText(""+insertList.get(0)); } else { if (insertList.size() < max) { new Thread(()->{ // 先执行所有过渡动画 for (int i = insertList.size()-1; i >= 0; i--) { int finalI = i; // UI操作投递到UI线程执行 Platform.runLater(()->{ ObservableList<Node> currNodes = insertArr[finalI].getChildren(); ImageView temp = (ImageView) currNodes.get(0); temp.setImage(current); ObservableList<Node> nextNodes = insertArr[finalI +1].getChildren(); ImageView tempNext = (ImageView) nextNodes.get(0); tempNext.setImage(next); }); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Platform.runLater(()->{ ObservableList<Node> currNodes = insertArr[finalI].getChildren(); ImageView temp = (ImageView) currNodes.get(0); ObservableList<Node> nextNodes = insertArr[finalI +1].getChildren(); ImageView tempNext = (ImageView) nextNodes.get(0); temp.setImage(allocated); tempNext.setImage(allocated); }); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } // 所有动画执行完成后,再更新Label和列表数据 Platform.runLater(()->{ for (int i = insertList.size()-1; i >= 0; i--) { ObservableList<Node> currNodes = insertArr[i].getChildren(); ObservableList<Node> nextNodes = insertArr[i+1].getChildren(); Label tempLabel = (Label) currNodes.get(1); Label tempNextLabel = (Label) nextNodes.get(1); tempNextLabel.setText(tempLabel.getText()); tempLabel.setText(""); } ObservableList<Node> nodes = insertArr[0].getChildren(); Label temp = (Label) nodes.get(1); insertList.add(0, random.nextInt(999)); temp.setText("" + insertList.get(0)); System.out.println("InsertList after insert "+ (insertList.size())+" : "+insertList); }); }).start(); } else { insertList.removeAll(insertList); fillInsert(); insertFront(); } } }
效果说明
修改后会按需求先逐格执行背景交换的过渡动画,所有动画完全展示结束后,才会统一更新每个单元格的Label数值,最后在数组头部插入新的随机数,不会再出现动画和数据不同步的问题。
内容的提问来源于stack exchange,提问作者OmKshirsagar
相关产品推荐
相关产品推荐

