JavaFX实现冒泡排序动画遇阻,对标VisuAlgo效果求修正
JavaFX冒泡排序动画问题:复刻VisuAlgo效果失败
作为编程新手,我尝试用JavaFX复刻VisuAlgo上的冒泡排序动画,已经通过数组元素值生成对应高度的矩形,试图用TranslateTransition实现基于矩形高度的排序动画,但代码无法实现预期效果,期望最终效果与VisuAlgo的冒泡排序动画一致。以下是我的代码:
public class BubbleSortController implements Initializable { @FXML private Pane pane; private final int[] array = {10,9,11,15}; @Override public void initialize(URL url, ResourceBundle resourceBundle) { drawRectangle(); sortRectangles(); } public void drawRectangle(){ double startX = 60; double startY = 350; // Initial Baseline of rectangles double heightMultiplier = 10; double width = 35; for(int value : array ){ double actualStartY = startY - (value * heightMultiplier); Rectangle rectangle = new Rectangle(startX, actualStartY, width, value*heightMultiplier); rectangle.setFill(Color.TURQUOISE); pane.getChildren().add(rectangle); startX += width + 7.5; } } public void sortRectangles(){ ObservableList<Node> rectangleList = pane.getChildren(); for(int i = 0; i < rectangleList.size() - 1 ; i++ ){ Node nodeI = rectangleList.get(i); Node nodeJ = rectangleList.get(i+1); Rectangle rectangleI = (Rectangle) nodeI; Rectangle rectangleJ = (Rectangle) nodeJ; if (rectangleI.getHeight() > rectangleJ.getHeight()){ TranslateTransition transition1 = new TranslateTransition(); TranslateTransition transition2 = new TranslateTransition(); transition1.setDuration(Duration.seconds(1)); transition2.setDuration(Duration.seconds(1)); transition1.setNode(rectangleI); transition2.setNode(rectangleJ); rectangleI.setFill(Color.RED); rectangleJ.setFill(Color.RED); transition1.setByX(rectangleJ.getX() - rectangleI.getX()); transition2.setByX(rectangleI.getX() - rectangleJ.getX()); transition1.play(); transition2.play(); } } } }
问题分析
现有代码存在几个关键问题:
- 冒泡排序逻辑不完整:只执行了一轮相邻元素比较,没有实现冒泡排序需要的多轮循环(外层循环控制轮数,内层循环处理每轮的逐个比较)
- 动画不同步且无顺序:直接调用
play()会让所有交换动画同时执行,不符合排序的分步展示逻辑 - 节点状态未更新:TranslateTransition仅改变视觉位置,未修改矩形的实际
X坐标,也没调整pane中节点的顺序,后续循环会基于错误的节点顺序继续比较 - 高亮未还原:交换后的红色高亮没有恢复为原颜色,不符合VisuAlgo的动画交互逻辑
修正后的代码
import javafx.animation.*; import javafx.fxml.Initializable; import javafx.scene.Node; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.util.Duration; import java.net.URL; import java.util.ResourceBundle; public class BubbleSortController implements Initializable { @FXML private Pane pane; private final int[] array = {10, 9, 11, 15}; private final double width = 35; private final double gap = 7.5; @Override public void initialize(URL url, ResourceBundle resourceBundle) { drawRectangle(); sortRectangles(); } public void drawRectangle() { double startX = 60; double startY = 350; double heightMultiplier = 10; for (int value : array) { double actualStartY = startY - (value * heightMultiplier); Rectangle rectangle = new Rectangle(startX, actualStartY, width, value * heightMultiplier); rectangle.setFill(Color.TURQUOISE); pane.getChildren().add(rectangle); startX += width + gap; } } public void sortRectangles() { ObservableList<Node> rectangleList = pane.getChildren(); SequentialTransition sequentialTransition = new SequentialTransition(); int n = rectangleList.size(); // 冒泡排序外层循环:控制轮数 for (int i = 0; i < n - 1; i++) { // 内层循环:每轮比较到未排序的最后一个元素 for (int j = 0; j < n - i - 1; j++) { Rectangle rectJ = (Rectangle) rectangleList.get(j); Rectangle rectJ1 = (Rectangle) rectangleList.get(j + 1); // 创建当前步骤的动画组 ParallelTransition stepTransition = new ParallelTransition(); // 高亮当前比较的两个矩形 FillTransition highlightJ = new FillTransition(Duration.seconds(0.3), rectJ, Color.TURQUOISE, Color.RED); FillTransition highlightJ1 = new FillTransition(Duration.seconds(0.3), rectJ1, Color.TURQUOISE, Color.RED); stepTransition.getChildren().addAll(highlightJ, highlightJ1); // 判断是否需要交换 if (rectJ.getHeight() > rectJ1.getHeight()) { // 计算交换的X偏移量 double moveDistance = width + gap; // 创建移动动画 TranslateTransition moveJ = new TranslateTransition(Duration.seconds(0.8), rectJ); moveJ.setByX(moveDistance); TranslateTransition moveJ1 = new TranslateTransition(Duration.seconds(0.8), rectJ1); moveJ1.setByX(-moveDistance); stepTransition.getChildren().addAll(moveJ, moveJ1); // 动画完成后更新节点顺序和实际坐标 stepTransition.setOnFinished(event -> { // 交换节点在pane中的顺序 rectangleList.set(j, rectJ1); rectangleList.set(j + 1, rectJ); // 更新实际X坐标,重置Translate偏移 double tempX = rectJ.getX(); rectJ.setX(rectJ1.getX()); rectJ1.setX(tempX); rectJ.setTranslateX(0); rectJ1.setTranslateX(0); }); } // 添加还原颜色的动画 FillTransition unhighlightJ = new FillTransition(Duration.seconds(0.3), rectJ, Color.RED, Color.TURQUOISE); FillTransition unhighlightJ1 = new FillTransition(Duration.seconds(0.3), rectJ1, Color.RED, Color.TURQUOISE); stepTransition.getChildren().addAll(unhighlightJ, unhighlightJ1); // 将当前步骤添加到总序列 sequentialTransition.getChildren().add(stepTransition); } } // 启动整个排序动画 sequentialTransition.play(); } }
关键改进说明
- 完整冒泡排序逻辑:实现了外层循环控制轮数、内层循环处理每轮比较的标准冒泡排序结构
- 有序动画执行:用
SequentialTransition管理所有步骤动画,保证按排序顺序依次执行;用ParallelTransition同步单步内的高亮、移动动画 - 节点状态同步:动画完成后交换pane中节点的顺序,并更新矩形的实际
X坐标,重置TranslateX偏移,确保后续比较基于正确的节点顺序 - 视觉交互还原:添加高亮-交换-还原颜色的过渡动画,更贴近VisuAlgo的交互效果
内容的提问来源于stack exchange,提问作者Andrew Appah
相关产品推荐
相关产品推荐

