如何在 JavaFX 中交换两个 GridPane 节点?

How to swap two GridPane nodes in JavaFX?

我想在 javafx 的 GUI 中模拟数组元素的交换。 我有一个网格窗格 Memory,它就像一个数组。网格的第 1 行只有数组。 在每个 row/col 中,我添加了一个具有图像视图和标签的堆栈窗格。 我想更改当前节点及其下一个节点的图像视图。连同数据。

我尝试通过循环进行,但没有看到结果。 所以我使用了一个线程来交换背景图像,但不允许交换标签值。 这是我在更改背景时没有交换的最接近的。

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--) {
                    ObservableList<Node> currNodes = insertArr[i].getChildren();
                    ImageView temp = (ImageView) currNodes.get(0);
                    temp.setImage(current);

                    ObservableList<Node> nextNodes = insertArr[i+1].getChildren();
                    ImageView tempNext = (ImageView) nextNodes.get(0);
                    tempNext.setImage(next);
                    Label tempLabel = (Label) currNodes.get(1);
                    Label tempNextLabel = (Label) nextNodes.get(1);

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    temp.setImage(allocated);
                    tempNext.setImage(allocated);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            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));
        } else {
            insertList.removeAll(insertList);
            fillInsert();
            insertFront();
        }
    }
    System.out.println("InsertList after insert "+ (insertList.size())+" : "+insertList);
}

但这不是同步的。我试图实现的是至少先显示背景的交换,然后直接更新行。 但是因为线程不同步,转换很慢并且网格行被更新。

我至少需要同步线程方面的帮助,以便首先显示转换。然后换行。

不确定我是否完全理解,但我认为您需要一种方法来交换 GridPane 中的两个节点。

这是一个完整的演示,它是如何工作的。

GridItem.java

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;

public class GridItem extends StackPane {
    private String text;
    private Color backgroundColor;

    public GridItem(String text, Color color) {
        setText(text);
        setBackgroundColor(color);
        Label textLabel = new Label(text);
        getChildren().add(textLabel);
        StackPane.setAlignment(textLabel, Pos.CENTER);

        setBackground(new Background(new BackgroundFill(color, CornerRadii.EMPTY, Insets.EMPTY)));
        setPrefSize(100, 100);
    }

    public Color getBackgroundColor() {
        return backgroundColor;
    }

    public void setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

HelloApplication.java

import java.util.Random;

import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) {
        GridPane gridPane = new GridPane();
        for (int i = 0; i < 16; i++) {
            gridPane.add(
                    new GridItem("Hello " + i,
                            Color.color(new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble())), i % 4, i / 4);
        }

        Scene scene = new Scene(gridPane, 900, 650);

        scene.setOnMouseClicked(e -> swapGridPane(gridPane, 0, 0, 3, 3, true));
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

    public static void swapGridPane(GridPane gridPane, int i1, int j1, int i2, int j2, boolean animate) {
        Node node1 = getNodeByRowColumnIndex(i1, j1, gridPane);
        Node node2 = getNodeByRowColumnIndex(i2, j2, gridPane);
        gridPane.getChildren().removeAll(node1, node2);

        gridPane.add(node1, i2, j2);
        gridPane.add(node2, i1, j1);

        if (animate) {
            fadeIn(node1);
            fadeIn(node2);
        }
    }

    public static void fadeIn(Node node) {
        FadeTransition fadeTransition = new FadeTransition(Duration.millis(200), node);
        fadeTransition.setFromValue(0);
        fadeTransition.setToValue(1);
        fadeTransition.play();
    }

    public static Node getNodeByRowColumnIndex(final int row, final int column, GridPane gridPane) {
        return gridPane.getChildren().stream()
                       .filter(node -> GridPane.getRowIndex(node) == row)
                       .filter(node -> GridPane.getColumnIndex(node) == column)
                       .findFirst().get();
    }

    public static void main(String[] args) {
        launch();
    }
}