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

Posted

技术标签:

【中文标题】如何在 JavaFX 中交换两个 GridPane 节点?【英文标题】:How to swap two GridPane nodes in JavaFX? 【发布时间】:2021-11-04 22:22:04 【问题描述】:

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

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

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);

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

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

【问题讨论】:

设计说明:您应该为此使用javafx.animation API,而不是线程。 @Slaw 你能做一个演示吗?我是 javafx 的初学者。谢谢。 更多帮助请发帖minimal reproducible example 【参考方案1】:

不确定我是否完全理解,但我认为您需要一种方法来交换 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();
    

【讨论】:

是的,这有我需要的...非常感谢!!

以上是关于如何在 JavaFX 中交换两个 GridPane 节点?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JavaFX 的 GridPane 中删除“幽灵线”?

Javafx 中 GridPane 中的 HBox

JavaFx GridPane 中的相对大小

JavaFX中GridPane的行居中对齐

如何在 JavaFX GridPane 的列之间设置填充?

在GridPane JAVAFX中水平居中一行