You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 09:15:30