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

JavaFX点击按钮后“Computer”文本偏移问题求助

问题原因分析
  • GridPane列宽默认动态计算,点击按钮后添加的电脑选择矩形会改变对应列的宽度,导致"Computer"标签位置偏移。
  • 你给"Computer"标签设置了Hgrow.ALWAYS和HPos.RIGHT,列宽变化时标签会跟着移动。
  • 每次点击都向选择框容器中添加新矩形而非替换旧元素,累积的元素会逐渐改变容器尺寸,加剧偏移。
解决方案

通过固定列宽、调整对齐方式、替换容器内容来稳定布局:

1. 固定GridPane列宽

为每一列设置固定宽度,避免动态变化导致的布局偏移。

2. 标签居中对齐

让"Player"和"Computer"标签与下方选择框居中对齐,确保始终在正上方。

3. 替换选择框内容

每次点击按钮时清空容器旧元素再添加新选择,避免元素累积。

4. 优化布局参数

移除不必要的Hgrow设置,添加元素间距让界面更规整。

修改后的完整代码
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import org.jetbrains.annotations.NotNull;

public class RockPaperScissors extends Application {
    static class Player {
        private final String username;
        private int score;

        public Player(String username) {
            this.username = username;
        }

        public int getScore() {
            return score;
        }

        public void setScore(int score) {
            this.score = score;
        }
    }

    static class ComputerPlayer extends Player {
        public Choice playTurn() {
            return Choice.values()[ThreadLocalRandom.current().nextInt(0, Choice.values().length)];
        }

        public ComputerPlayer(String username) {
            super(username);
        }
    }

    private Label playerNameLabel;
    private Label computerNameLabel;
    private Button rockButton;
    private Button paperButton;
    private Button scissorsButton;
    private Label resultLabel;
    private Player user;
    private ComputerPlayer computer;

    public enum Choice {
        ROCK,
        PAPER,
        SCISSORS
    }

    private StackPane playerChoiceImageView = new StackPane();
    private StackPane computerChoiceImageView = new StackPane();

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

    @Override
    public void start(Stage stage) {
        user = new Player("User");
        computer = new ComputerPlayer("Computer");
        stage.setTitle("Rock, Paper, Scissors");

        playerNameLabel = new Label("Player");
        computerNameLabel = new Label("Computer");
        playerNameLabel.setFont(Font.font("Arial", FontWeight.BOLD, 20));
        computerNameLabel.setFont(Font.font("Arial", FontWeight.BOLD, 20));

        // 设置标签居中对齐,确保在选择框正上方
        GridPane.setHalignment(playerNameLabel, HPos.CENTER);
        GridPane.setMargin(playerNameLabel, new Insets(10, 0, 15, 0));
        GridPane.setHalignment(computerNameLabel, HPos.CENTER);
        GridPane.setMargin(computerNameLabel, new Insets(10, 0, 15, 0));

        Rectangle rockRectangle = createChoiceNode(Choice.ROCK);
        Rectangle paperRectangle = createChoiceNode(Choice.PAPER);
        Rectangle scissorsRectangle = createChoiceNode(Choice.SCISSORS);

        rockButton = new Button("", rockRectangle);
        paperButton = new Button("", paperRectangle);
        scissorsButton = new Button("", scissorsRectangle);

        resultLabel = new Label();
        resultLabel.setFont(Font.font("Arial", FontWeight.BOLD, 20));

        GridPane grid = new GridPane();
        // 设置列约束,固定每列宽度
        for (int i = 0; i < 7; i++) {
            ColumnConstraints colConst = new ColumnConstraints();
            colConst.setPrefWidth(70); // 每列固定70px宽度
            grid.getColumnConstraints().add(colConst);
        }

        grid.add(playerNameLabel, 1, 1);
        grid.add(computerNameLabel, 5, 1);
        grid.add(playerChoiceImageView, 1, 2);
        grid.add(computerChoiceImageView, 5, 2);
        grid.add(rockButton, 2, 5);
        grid.add(paperButton, 3, 5);
        grid.add(scissorsButton, 4, 5);
        grid.add(resultLabel, 1, 6, 5, 1); // 结果标签跨5列显示

        // 设置GridPane内边距和元素间距
        grid.setPadding(new Insets(10));
        grid.setVgap(10);
        grid.setHgap(10);

        StackPane root = new StackPane(grid);
        Scene scene = new Scene(root, 500, 400);
        stage.setScene(scene);
        stage.show();

        rockButton.setOnAction(e -> handleButtonClick(Choice.ROCK));
        paperButton.setOnAction(e -> handleButtonClick(Choice.PAPER));
        scissorsButton.setOnAction(e -> handleButtonClick(Choice.SCISSORS));
    }

    private static @NotNull Rectangle createChoiceNode(Choice choice) {
        Rectangle rect = new Rectangle(60, 60);
        rect.setFill(switch (choice) {
            case ROCK -> Color.BROWN;
            case PAPER -> Color.ANTIQUEWHITE;
            case SCISSORS -> Color.DEEPPINK;
        });
        return rect;
    }

    private final List<Choice> choices = new ArrayList<>();

    private void handleButtonClick(Choice userChoice) {
        Choice computerChoice = computer.playTurn();

        // 清空旧选择,替换为新选择
        playerChoiceImageView.getChildren().clear();
        playerChoiceImageView.getChildren().add(createChoiceNode(userChoice));
        computerChoiceImageView.getChildren().clear();
        computerChoiceImageView.getChildren().add(createChoiceNode(computerChoice));

        choices.add(userChoice);
        choices.add(computerChoice);

        if (userChoice == computerChoice) {
            // 平局
        } else if ((userChoice == Choice.ROCK && computerChoice == Choice.SCISSORS)
                || (userChoice == Choice.PAPER && computerChoice == Choice.ROCK)
                || (userChoice == Choice.SCISSORS && computerChoice == Choice.PAPER)) {
            user.setScore(user.getScore() + 1);
        } else {
            computer.setScore(computer.getScore() + 1);
        }

        resultLabel.setText("Player score: " + user.getScore() + "\n" +
                "Computer score: " + computer.getScore());
    }
}
关键修改说明
  • 添加固定宽度的ColumnConstraints,确保GridPane列宽稳定。
  • 将标签对齐方式改为HPos.CENTER,移除不必要的Hgrow设置,保证标签位置固定。
  • 在点击事件中清空选择框容器的旧元素,避免累积导致的布局变形。
  • 调整按钮和结果标签的布局位置,添加vgap和hgap优化界面间距。

内容的提问来源于stack exchange,提问作者onuk98

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:57:32