Javafx:将矩形形状与锯切数组元素交换

Javafx:将矩形形状与锯切数组元素交换,javafx,Javafx,我正在使用JavaFx进行排序算法模拟。在对数组元素进行排序时,我想显示Rectangles的交换。但是有一个问题是,矩形随机移动,并且没有按照我尝试的PathTransition数组元素排序的顺序进行。如果我尝试使用TranslateTransition,当我翻译y时,在翻译x之后,圆圈跟随对角线。为什么会发生这种情况?我还尝试将文本单独添加到矩形中,但失败了。代码如下: PathTransition pathtransition1; PathTransition pathtransition

我正在使用JavaFx进行排序算法模拟。在对数组元素进行排序时,我想显示
Rectangle
s的交换。但是有一个问题是,矩形随机移动,并且没有按照我尝试的
PathTransition
数组元素排序的顺序进行。如果我尝试使用
TranslateTransition
,当我翻译y时,在翻译x之后,圆圈跟随对角线。为什么会发生这种情况?我还尝试将文本单独添加到矩形中,但失败了。代码如下:

PathTransition pathtransition1;
PathTransition pathtransition2;

@Override
public void start(Stage primaryStage) {

    Pane root = new Pane();
    int[] a = {5, 8, 0, 3, 1};
    Text[] text = new Text[5];

    Rectangle[] rect = new Rectangle[5];
    for (int i = 0; i < 5; i++) {
        rect[i] = new Rectangle(100 * i, 300, 40, 40);
        rect[i].setArcHeight(10);
        rect[i].setArcWidth(10);
        rect[i].setFill(Color.ORANGE);
        text[i] = new Text(Integer.toString(a[i]));
        text[i].setFont(Font.font("VERDANA", FontWeight.BOLD, 12));

        root.getChildren().addAll(rect[i], text[i]);
    }

    // Selection Sort
    int min;
    for (int i = 0; i < a.length; i++) {

        min = i;
        for (int j = i + 1; j < a.length; j++) {
            if (a[j] < a[min]) {
                min = j;

            }
        }
        if (min != i) {
            int temp = a[i];
            a[i] = a[min];
            a[min] = temp;
            swap1(rect[i], 60, (int) rect[min].getX());
            swap2(rect[min], 60, (int) rect[i].getX());
            Rectangle temporary = rect[i];
            rect[i] = rect[min];
            rect[min] = temporary;

        }
        System.out.println(a[i]);
    }

    Scene scene = new Scene(root, 800, 600);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}


void swap1(Rectangle rect, int d, int sx) {
    Path path1 = new Path(new MoveTo(rect.getX(), rect.getY()),
            new LineTo(rect.getX(), rect.getY() - d),
            new MoveTo(rect.getX(), rect.getY() - d),
            new LineTo(sx, rect.getY() - d),
            new MoveTo(sx, rect.getY() - d),
            new LineTo(sx, rect.getY())
    );
    pathtransition1 = new PathTransition(seconds(1), path1, rect);
    pathtransition1.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
    pathtransition1.setCycleCount(1);

    pathtransition1.setAutoReverse(false);
    pathtransition1.play();
}


void swap2(Rectangle rect, int d, int sx) {

    Path path2 = new Path(new MoveTo(rect.getX(), rect.getY()),
            new LineTo(rect.getX(), rect.getY() + d),
            new MoveTo(rect.getX(), rect.getY() + d),
            new LineTo(sx, rect.getY() + d),
            new MoveTo(sx, rect.getY() + d),
            new LineTo(sx, rect.getY())
    );
    pathtransition2 = new PathTransition(seconds(4), path2, rect);
    pathtransition2.setOrientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
    pathtransition2.setCycleCount(1);
    pathtransition2.setAutoReverse(false);
    pathtransition2.play();

}
路径转换路径转换1;
路径转换路径转换2;
@凌驾
公共无效开始(阶段primaryStage){
窗格根=新窗格();
int[]a={5,8,0,3,1};
Text[]Text=新文本[5];
矩形[]矩形=新矩形[5];
对于(int i=0;i<5;i++){
rect[i]=新矩形(100*i,300,40,40);
rect[i].setArcHeight(10);
rect[i].setArcWidth(10);
rect[i].setFill(Color.ORANGE);
text[i]=新文本(Integer.toString(a[i]);
text[i].setFont(Font.Font(“VERDANA”,fontwweight.BOLD,12));
root.getChildren().addAll(rect[i],text[i]);
}
//选择排序
int-min;
for(int i=0;i
出了什么问题以及如何修复它

  • 您需要降低交换算法的速度 交换是基于每个矩形的当前位置进行的每次迭代。但是,动画过渡需要一段时间才能运行,因此矩形在过渡完成之前不在需要的位置,但迭代正在不间断地运行,不等待过渡完成

    解决这一问题的一种方法是继续将路径变换添加到一个大的顺序变换中,然后播放整个序列,而不是一次播放一个步骤

    解决此问题的另一种方法是在自己的线程中运行swap算法,并在每一步暂停它,直到相关的步骤动画完成(这是我在提供的示例解决方案中采用的方法)

  • 每次转换后,需要将矩形重新定位到其新位置
  • 路径变换将修改对象的平移X/Y坐标。转换步骤完成后,设置要转换到新转换坐标的对象的X/Y坐标,然后重置translateX/Y坐标

    rect.setX(rect.getX() + rect.getTranslateX());
    rect.setY(rect.getY() + rect.getTranslateY());
    rect.setTranslateX(0);
    rect.setTranslateY(0);
    
  • 路径定位逻辑中存在一些小错误
  • 交换物品后,它们最后的休息位置稍微不合适

  • 将文本添加到场景中,但不定位它
  • 不要使用矩形,只需使用带有彩色背景的标签,并将其四处移动即可

    示例屏幕截图

    在下面的示例中,标记为
    1
    8
    的元素处于交换转换过程中:

    更新的样本代码

    import javafx.animation.PathTransition;
    import javafx.application.*;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.layout.*;
    import javafx.scene.shape.*;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    import java.util.concurrent.*;
    import java.util.concurrent.locks.*;
    
    public class Sorter extends Application {
        final Pane root = new Pane();
    
        final PathTransition[] pathtransition = new PathTransition[2];
    
        final Lock lock = new ReentrantLock();
        final Condition[] swapComplete  = { lock.newCondition(), lock.newCondition() };
    
        final int[] data = {5, 8, 0, 3, 1};
    
        @Override
        public void start(Stage stage) {
            Label[] labels = createLabels(data);
            root.getChildren().addAll(labels);
            root.setStyle("-fx-background-color: oldlace;");
    
            Scene scene = new Scene(root, 600, 250);
            stage.setScene(scene);
            stage.show();
    
            sort(data, labels);
        }
    
        private void sort(int[] a, Label[] rect) {
            // Selection Sort
            Thread thread = new Thread(
                    () -> {
                        int min;
                        for (int i = 0; i < a.length; i++) {
    
                            min = i;
                            for (int j = i + 1; j < a.length; j++) {
                                if (a[j] < a[min]) {
                                    min = j;
    
                                }
                            }
                            if (min != i) {
                                int temp = a[i];
                                a[i] = a[min];
                                a[min] = temp;
                                final int finalMin = min;
                                final int finalI = i;
    
                                FutureTask<Void> future = new FutureTask<>(
                                        () -> {
                                            swap(
                                                    0,
                                                    rect[finalI],
                                                    60,
                                                    rect[finalMin].getLayoutX() - rect[finalI].getLayoutX(),
                                                    Duration.seconds(1)
                                            );
                                            swap(
                                                    1,
                                                    rect[finalMin],
                                                    -60,
                                                    rect[finalI].getLayoutX() - rect[finalMin].getLayoutX(),
                                                    Duration.seconds(4)
                                            );
    
                                            return null;
                                        }
                                );
    
                                lock.lock();
                                try {
                                    Platform.runLater(future);
                                    future.get();
                                    for (Condition condition: swapComplete) {
                                        condition.await();
                                    }
                                } catch (InterruptedException e) {
                                    Thread.interrupted();
                                    break;
                                } catch (ExecutionException e) {
                                    e.printStackTrace();
                                    break;
                                } finally {
                                    lock.unlock();
                                }
    
                                Label temporary = rect[i];
                                rect[i] = rect[min];
                                rect[min] = temporary;
                            }
                            System.out.println(a[i]);
                        }
                    }
            );
            thread.setDaemon(true);
            thread.start();
        }
    
        private Label[] createLabels(int[] a) {
            Label[] rect = new Label[a.length];
    
            for (int i = 0; i < a.length; i++) {
                createLabel(i, a, rect);
            }
    
            return rect;
        }
    
        private void createLabel(int i, int[] a, Label[] rect) {
            rect[i] = new Label(Integer.toString(a[i]));
            rect[i].setMinSize(40, 40);
            rect[i].setMaxSize(40, 40);
            rect[i].setAlignment(Pos.CENTER);
            rect[i].setStyle(
                    "-fx-background-radius: 10; " +
                    "-fx-background-color: orange; " +
                    "-fx-font-family: Verdana; " +
                    "-fx-font-size: 12pt; " +
                    "-fx-font-weight: bold;"
            );
            rect[i].relocate(100 * i + 80, 100);
        }
    
    
        void swap(int transitionIdx, Region node, double dy, double dx, Duration duration) {
            double cx = node.getWidth() / 2;
            double cy = node.getHeight() / 2;
    
            Path path1 = new Path(
                    new MoveTo(cx, cy),
                    new LineTo(cx, cy + dy),
                    new LineTo(dx + cx, cy + dy),
                    new LineTo(dx + cx, cy)
            );
    
            pathtransition[transitionIdx] = new PathTransition(duration, path1, node);
    
            pathtransition[transitionIdx].setOnFinished(event -> {
                node.setLayoutX(node.getLayoutX() + node.getTranslateX());
                node.setLayoutY(node.getLayoutY() + node.getTranslateY());
                node.setTranslateX(0);
                node.setTranslateY(0);
    
                lock.lock();
                try {
                    swapComplete[transitionIdx].signal();
                } finally {
                    lock.unlock();
                }
            });
    
            pathtransition[transitionIdx].play();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    导入javafx.animation.PathTransition;
    导入javafx.application.*;
    导入javafx.geometry.Pos;
    导入javafx.scene.scene;
    导入javafx.scene.control.Label;
    导入javafx.scene.layout.*;
    导入javafx.scene.shape.*;
    导入javafx.stage.stage;
    导入javafx.util.Duration;
    导入java.util.concurrent.*;
    导入java.util.concurrent.locks.*;
    公共类分类器扩展应用{
    最终窗格根=新窗格();
    最终路径转换[]路径转换=新路径转换[2];
    最终锁定=新的可重入锁定();
    最终条件[]swapComplete={lock.newCondition(),lock.newCondition()};
    final int[]data={5,8,0,3,1};
    @凌驾
    公众假期开始(阶段){
    标签[]标签=创建标签(数据);
    root.getChildren().addAll(标签);
    root.setStyle(“-fx背景色:oldlace;”);
    场景=新场景(root,600250);
    舞台场景;
    stage.show();
    分类(数据、标签);
    }
    私有void排序(int[]a,Label[]rect){
    //选择排序
    螺纹=ne
    
    private static class AnimationElements {
    
        private final PathTransition transition;
        private final MoveTo start;
        private final LineTo horizontalMove;
    
        public AnimationElements(double height) {
            this.start = new MoveTo();
            this.horizontalMove = new LineTo();
            horizontalMove.setAbsolute(false);
    
            LineTo l1 = new LineTo(0, height);
            l1.setAbsolute(false);
            LineTo l2 = new LineTo(0, -height);
            l2.setAbsolute(false);
    
            this.transition = new PathTransition(Duration.seconds(4), new Path(start, l1, horizontalMove, l2));
        }
    
        public void init(Node movedNode, Node moveEnd) {
            // init animation according to positions of the Nodes to move
            double sx = movedNode.getTranslateX();
            double dx = moveEnd.getTranslateX() - sx;
            start.setX(sx + movedNode.getLayoutBounds().getWidth() / 2);
            start.setY(movedNode.getTranslateY() + movedNode.getLayoutBounds().getHeight() / 2);
            horizontalMove.setX(dx/*+movedNode.getLayoutBounds().getWidth()/2*/);
            transition.setNode(movedNode);
        }
    
        public PathTransition getTransition() {
            return transition;
        }
    
    }
    
    private static class Swap {
    
        private final int index1;
        private final int index2;
    
        public Swap(int index1, int index2) {
            this.index1 = index1;
            this.index2 = index2;
        }
    
        public void init(AnimationElements animation1, AnimationElements animation2, Node[] sortNodes) {
            // initialize both positions
            Node n1 = sortNodes[index1];
            Node n2 = sortNodes[index2];
            animation1.init(n1, n2);
            animation2.init(n2, n1);
    
            // swap order to be correct for the next swap
            sortNodes[index2] = n1;
            sortNodes[index1] = n2;
        }
    }
    
    @Override
    public void start(Stage primaryStage) {
        // create list of swaps to execute; could be generated by sorting algorithm
        List<Swap> swaps = Arrays.asList(new Swap(0, 1), new Swap(1, 2), new Swap(3, 4), new Swap(0, 4));
    
        AnimationElements animationElements1 = new AnimationElements(100);
        AnimationElements animationElements2 = new AnimationElements(-100);
    
        // both swap animations happen simultaniously
        ParallelTransition animation = new ParallelTransition(animationElements1.getTransition(), animationElements2.getTransition());
    
        Color[] colors = new Color[]{
            Color.RED,
            Color.BLUE,
            Color.LIME,
            Color.YELLOW,
            Color.ORANGE
        };
        Node[] nodes = new Node[5];
        for (int i = 0; i < nodes.length; i++) {
            Rectangle rect = new Rectangle(100, 20, colors[i]);
            rect.setTranslateY(200);
            rect.setTranslateX(i * 100);
            nodes[i] = rect;
        }
    
        Iterator<Swap> iterator = swaps.iterator();
        animation.setOnFinished(evt -> {
            if (iterator.hasNext()) {
                // continue with next swap
                iterator.next().init(animationElements1, animationElements2, nodes);
                animation.play();
            }
        });
        if (iterator.hasNext()) {
            // execute first swap
            iterator.next().init(animationElements1, animationElements2, nodes);
            animation.play();
        }
    
        Pane root = new Pane(nodes);
    
        Scene scene = new Scene(root, 500, 400);
    
        primaryStage.setScene(scene);
        primaryStage.show();
    }