JavaFXGridPane自适应棋盘布局设置
珍惜时间,勤奋学习!今天给大家带来《JavaFX GridPane动态布局:棋盘自适应窗口设置》,正文内容主要涉及到等等,如果你正在学习文章,或者是对文章有疑问,欢迎大家关注我!后面我会持续更新相关内容的,希望都能帮到正在学习的大家!
JavaFX GridPane 动态布局概述
JavaFX中的GridPane是一种强大的布局容器,它允许我们以行和列的形式组织UI组件。在开发互动性强的应用程序,例如棋盘游戏(如井字棋),我们常常需要根据用户输入或其他条件动态调整GridPane的大小,即增加或减少其列数和行数。简单地设置GridPane的minSize或prefSize并不能有效控制内部单元格的布局,因为GridPane的实际布局是由其内部的列约束(ColumnConstraints)和行约束(RowConstraints)决定的。
理解 ColumnConstraints 与 RowConstraints
ColumnConstraints和RowConstraints是控制GridPane内部列宽和行高的关键。它们允许开发者为每一列或每一行指定详细的布局规则,包括:
- setPrefWidth/Height(double value): 设置列或行的首选宽度/高度。
- setMinWidth/Height(double value): 设置列或行的最小宽度/高度。
- setMaxWidth/Height(double value): 设置列或行的最大宽度/高度。
- setPercentWidth/Height(double value): 设置列或行占用GridPane总宽度的百分比。这对于创建等宽/高或按比例分配空间的列/行非常有用。
- setHgrow(Priority value) / setVgrow(Priority value): 当GridPane有额外空间时,指定列或行如何“增长”。Priority.ALWAYS表示该列/行会尽可能占用额外空间。
通过这些属性,我们可以实现高度灵活的布局,使GridPane及其内部组件能够优雅地响应尺寸变化。
动态添加约束的正确姿势
在尝试动态调整GridPane时,一个常见的误区是在循环中重复修改同一个ColumnConstraints或RowConstraints对象,然后只将其添加一次。例如,以下代码片段无法实现预期效果:
// 错误示例:无法在循环中添加多个独立的约束 public void changeGameBoard(ActionEvent event) { int boardNumber = 5; // 假设用户选择的棋盘大小 if (boardNumber > 2) { ColumnConstraints column1 = new ColumnConstraints(); RowConstraints row1 = new RowConstraints(); for (int i = 0; i < boardNumber; i++) { column1.setPrefWidth(100); // 每次循环都修改同一个对象 row1.setPrefHeight(100); // 每次循环都修改同一个对象 } gameBoard.getColumnConstraints().add(column1); // 最终只添加了一个约束 gameBoard.getRowConstraints().add(row1); // 最终只添加了一个约束 gameBoard.setMinSize(500,500); // 这只能设置GridPane的最小尺寸,不控制内部单元格 } }
这段代码的问题在于,column1和row1在循环外部被创建,每次循环只是修改了这两个对象的属性。循环结束后,GridPane的约束列表中只添加了column1和row1这两个实例,导致所有列/行都遵循相同的最后一个设置,并且只有一列和一行被实际定义。
正确实现方法是,在循环中为每一列和每一行创建并添加独立的ColumnConstraints和RowConstraints实例。
import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.Priority; import javafx.scene.layout.RowConstraints; // ... (其他代码) /** * 动态调整GridPane的列和行数量,并设置固定单元格大小。 * @param gameBoard 要调整的GridPane实例。 * @param boardSize 目标棋盘的边长(例如,5表示5x5的棋盘)。 * @param cellSize 每个单元格的预设大小(宽度和高度)。 */ public void setupDynamicGameBoard(GridPane gameBoard, int boardSize, double cellSize) { // 每次调整前,清空旧的约束,以确保新的布局生效 gameBoard.getColumnConstraints().clear(); gameBoard.getRowConstraints().clear(); // 循环创建并添加 ColumnConstraints for (int i = 0; i < boardSize; i++) { ColumnConstraints colConstraints = new ColumnConstraints(); colConstraints.setPrefWidth(cellSize); // 设置每列的首选宽度 colConstraints.setHgrow(Priority.SOMETIMES); // 允许列在有额外空间时增长 gameBoard.getColumnConstraints().add(colConstraints); } // 循环创建并添加 RowConstraints for (int i = 0; i < boardSize; i++) { RowConstraints rowConstraints = new RowConstraints(); rowConstraints.setPrefHeight(cellSize); // 设置每行的首选高度 rowConstraints.setVgrow(Priority.SOMETIMES); // 允许行在有额外空间时增长 gameBoard.getRowConstraints().add(rowConstraints); } // 设置GridPane的最小尺寸,这会影响GridPane自身,但内部布局由约束决定 // gameBoard.setMinSize(boardSize * cellSize, boardSize * cellSize); // 通常情况下,GridPane会根据其内容和约束自动计算其首选大小 }
实现百分比宽度/高度的自适应布局
对于需要所有列或行等宽/等高,并且能够随着父容器大小变化而自适应调整的场景,使用setPercentWidth/Height是更优的选择。
import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.RowConstraints; // ... (其他代码) /** * 动态调整GridPane的列和行数量,并使用百分比设置实现自适应单元格大小。 * @param gameBoard 要调整的GridPane实例。 * @param boardSize 目标棋盘的边长。 */ public void setupPercentageGameBoard(GridPane gameBoard, int boardSize) { gameBoard.getColumnConstraints().clear(); gameBoard.getRowConstraints().clear(); double percentPerCell = 100.0 / boardSize; // 计算每个单元格应占的百分比 for (int i = 0; i < boardSize; i++) { ColumnConstraints colConstraints = new ColumnConstraints(); colConstraints.setPercentWidth(percentPerCell); // 设置每列占用总宽度的百分比 gameBoard.getColumnConstraints().add(colConstraints); } for (int i = 0; i < boardSize; i++) { RowConstraints rowConstraints = new RowConstraints(); rowConstraints.setPercentHeight(percentPerCell); // 设置每行占用总高度的百分比 gameBoard.getRowConstraints().add(rowConstraints); } // 当使用百分比约束时,GridPane会自动尝试填充其可用空间。 // 如果GridPane的父容器允许增长,GridPane也会随之增长。 }
示例解释: 假设boardSize为3,那么percentPerCell将是100.0 / 3 = 33.33...。 循环将创建3个ColumnConstraints对象,每个都设置setPercentWidth(33.33...),然后添加到GridPane的列约束列表中。同样地,行约束也会被设置。这样,无论GridPane被放置在多大的空间中,它的三列和三行都会均匀地分配可用宽度和高度。
GridPane 与窗口的自适应调整
GridPane的自适应性主要体现在其对内部组件和自身尺寸的调整。当您使用ColumnConstraints和RowConstraints定义了布局规则后:
- GridPane自身尺寸: GridPane会根据其内容、约束以及父容器的可用空间来计算其首选大小。如果使用了百分比约束,GridPane会尝试填充其父容器所提供的所有空间。如果使用了固定宽度/高度,GridPane的首选大小将是所有列/行宽度之和。
- Scene和Stage: GridPane通常作为Scene的根节点或Scene中某个布局容器的子节点。Scene会根据其根节点的首选大小来计算自己的首选大小。Stage(窗口)通常会根据Scene的首选大小来调整自身。
- 如果您希望窗口自动适应GridPane的新尺寸,可以在更新GridPane后调用stage.sizeToScene()方法。这会强制Stage重新计算并调整到Scene的首选大小。
- 在大多数情况下,如果GridPane被放置在允许增长的父容器(如BorderPane的中心、VBox/HBox中设置了Priority.ALWAYS)中,并且GridPane的约束允许其增长(例如setHgrow(Priority.ALWAYS)),那么整个UI会自然地进行尺寸调整。
完整示例:构建可变大小棋盘
以下是一个更完整的示例,展示如何在JavaFX应用程序中动态创建一个可变大小的棋盘GridPane。
import javafx.application.Application; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.Slider; import javafx.scene.layout.BorderPane; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.RowConstraints; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.stage.Stage; public class DynamicGridPaneTutorial extends Application { private GridPane gameBoard; private Label sizeLabel; private int currentBoardSize = 3; // 初始棋盘大小 @Override public void start(Stage primaryStage) { BorderPane root = new BorderPane(); gameBoard = new GridPane(); gameBoard.setStyle("-fx-background-color: lightgray; -fx-grid-lines-visible: true;"); gameBoard.setAlignment(Pos.CENTER); // 棋盘居中 // 控制面板 HBox controlBox = new HBox(10); controlBox.setAlignment(Pos.CENTER); sizeLabel = new Label("当前棋盘大小: " + currentBoardSize + "x" + currentBoardSize); Slider sizeSlider = new Slider(3, 10, currentBoardSize); sizeSlider.setBlockIncrement(1); sizeSlider.setMajorTickUnit(1); sizeSlider.setMinorTickCount(0); sizeSlider.setShowTickLabels(true); sizeSlider.setShowTickMarks(true); sizeSlider.setSnapToTicks(true); Button applyButton = new Button("应用新大小"); applyButton.setOnAction(e -> { currentBoardSize = (int) sizeSlider.getValue(); sizeLabel.setText("当前棋盘大小: " + currentBoardSize + "x" + currentBoardSize); updateGameBoard(currentBoardSize); primaryStage.sizeToScene(); // 窗口适应新内容大小 }); controlBox.getChildren().addAll(sizeLabel, sizeSlider, applyButton); root.setTop(controlBox); root.setCenter(gameBoard); // 初始设置棋盘 updateGameBoard(currentBoardSize); Scene scene = new Scene(root, 600, 600); primaryStage.setTitle("动态GridPane棋盘示例"); primaryStage.setScene(scene); primaryStage.show(); } /** * 根据指定大小更新GridPane棋盘。 * @param boardSize 棋盘的边长。 */ private void updateGameBoard(int boardSize) { // 清空旧的列和行约束 gameBoard.getColumnConstraints().clear(); gameBoard.getRowConstraints().clear(); // 清空旧的子节点(如果棋盘上放置了组件) gameBoard.getChildren().clear(); // 为每列添加约束,使用百分比宽度 double percentPerCell = 100.0 / boardSize; for (int i = 0; i < boardSize; i++) { ColumnConstraints colConstraints = new ColumnConstraints(); colConstraints.setPercentWidth(percentPerCell); colConstraints.setHgrow(Priority.ALWAYS); // 允许列在水平方向上增长 gameBoard.getColumnConstraints().add(colConstraints); } // 为每行添加约束,使用百分比高度 for (int i = 0; i < boardSize; i++) { RowConstraints rowConstraints = new RowConstraints(); rowConstraints.setPercentHeight(percentPerCell); rowConstraints.setVgrow(Priority.ALWAYS); // 允许行在垂直方向上增长 gameBoard.getRowConstraints().add(rowConstraints); } // 在棋盘上放置一些占位符(例如,矩形) for (int row = 0; row < boardSize; row++) { for (int col = 0; col < boardSize; col++) { Rectangle cell = new Rectangle(50, 50, Color.WHITE); // 初始大小,会被GridPane约束覆盖 cell.setStroke(Color.BLACK); // 绑定矩形的宽度和高度到GridPane单元格的实际宽度和高度 cell.widthProperty().bind(gameBoard.widthProperty().divide(boardSize)); cell.heightProperty().bind(gameBoard.heightProperty().divide(boardSize)); gameBoard.add(cell, col, row); } } } public static void main(String[] args) { launch(args); } }
在这个示例中,我们创建了一个滑块来控制棋盘的大小。当用户点击“应用新大小”按钮时,updateGameBoard方法会被调用。该方法首先清空GridPane的所有旧约束和子节点,然后根据新的boardSize动态创建并添加新的ColumnConstraints和RowConstraints,并使用setPercentWidth/Height确保单元格均匀分布。最后,primaryStage.sizeToScene()确保窗口能够适应新生成的棋盘布局。
注意事项与最佳实践
- 清空旧约束: 在每次动态调整GridPane的列/行数量之前,务必调用gameBoard.getColumnConstraints().clear()和gameBoard.getRowConstraints().clear()来移除所有旧的约束。否则,新的约束会与旧的约束叠加,导致不可预测的布局行为。
- 创建新实例: 始终为每一列或每一行创建独立的ColumnConstraints和RowConstraints实例。不要尝试在循环中重复使用或修改同一个实例。
- 百分比与固定值:
- 当需要所有列/行均匀分布或按比例分配空间时,使用setPercentWidth/Height。
- 当需要精确控制每一列/行的尺寸时,使用setPrefWidth/Height、setMinWidth/Height、setMaxWidth/Height。
- 增长优先级: setHgrow(Priority)和setVgrow(Priority)对于GridPane在有额外空间时如何分配非常重要。Priority.ALWAYS表示该列/行会尽可能占用所有可用空间。
- 子节点绑定: 如果GridPane中的子节点需要随单元格大小变化,可以考虑将它们的尺寸属性(如widthProperty()、heightProperty())绑定到GridPane的相应尺寸属性除以列/行数的计算结果上,如示例中Rectangle的绑定方式。
- 父容器影响: GridPane的最终尺寸也会受到其父容器的影响。确保GridPane的父容器(例如BorderPane、VBox、HBox或StackPane)能够提供足够的空间或允许GridPane按其约束进行扩展。
总结
动态调整JavaFX GridPane的列和行是实现灵活用户界面的关键技能。通过正确理解和运用ColumnConstraints和RowConstraints,开发者可以精确控制GridPane内部的布局行为。无论是采用固定尺寸还是百分比分配,遵循创建新约束实例、清空旧约束的原则,并结合窗口的自适应调整,我们就能轻松构建出能够响应用户需求的可变大小棋盘或其他复杂布局。
理论要掌握,实操不能落!以上关于《JavaFXGridPane自适应棋盘布局设置》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

- 上一篇
- 谷歌浏览器截长图技巧全攻略

- 下一篇
- JS自动部署配置详解与技巧
-
- 文章 · java教程 | 13秒前 |
- Java多层列表排序与查找技巧
- 363浏览 收藏
-
- 文章 · java教程 | 44分钟前 |
- SpringBoot安全配置全攻略
- 399浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- SLF4J日志对齐技巧:Logback修饰符详解
- 178浏览 收藏
-
- 文章 · java教程 | 1小时前 | 应用场景 反射机制
- 反射机制是什么?如何应用?优缺点详解
- 116浏览 收藏
-
- 文章 · java教程 | 1小时前 |
- JavaWebSocket集群通信实现全解析
- 454浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java对接银联支付接口教程详解
- 307浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- 时间同步最佳实践:UI与后端处理技巧
- 480浏览 收藏
-
- 文章 · java教程 | 2小时前 |
- Java线程安全与锁机制全解析
- 335浏览 收藏
-
- 文章 · java教程 | 3小时前 |
- Java热更新的几种实现方法
- 112浏览 收藏
-
- 文章 · java教程 | 4小时前 |
- Java数字签名与PKI应用实战解析
- 438浏览 收藏
-
- 文章 · java教程 | 4小时前 |
- Java反射获取泛型方法失败解决方法
- 483浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 514次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- AI Mermaid流程图
- SEO AI Mermaid 流程图工具:基于 Mermaid 语法,AI 辅助,自然语言生成流程图,提升可视化创作效率,适用于开发者、产品经理、教育工作者。
- 291次使用
-
- 搜获客【笔记生成器】
- 搜获客笔记生成器,国内首个聚焦小红书医美垂类的AI文案工具。1500万爆款文案库,行业专属算法,助您高效创作合规、引流的医美笔记,提升运营效率,引爆小红书流量!
- 264次使用
-
- iTerms
- iTerms是一款专业的一站式法律AI工作台,提供AI合同审查、AI合同起草及AI法律问答服务。通过智能问答、深度思考与联网检索,助您高效检索法律法规与司法判例,告别传统模板,实现合同一键起草与在线编辑,大幅提升法律事务处理效率。
- 296次使用
-
- TokenPony
- TokenPony是讯盟科技旗下的AI大模型聚合API平台。通过统一接口接入DeepSeek、Kimi、Qwen等主流模型,支持1024K超长上下文,实现零配置、免部署、极速响应与高性价比的AI应用开发,助力专业用户轻松构建智能服务。
- 257次使用
-
- 迅捷AIPPT
- 迅捷AIPPT是一款高效AI智能PPT生成软件,一键智能生成精美演示文稿。内置海量专业模板、多样风格,支持自定义大纲,助您轻松制作高质量PPT,大幅节省时间。
- 282次使用
-
- 提升Java功能开发效率的有力工具:微服务架构
- 2023-10-06 501浏览
-
- 掌握Java海康SDK二次开发的必备技巧
- 2023-10-01 501浏览
-
- 如何使用java实现桶排序算法
- 2023-10-03 501浏览
-
- Java开发实战经验:如何优化开发逻辑
- 2023-10-31 501浏览
-
- 如何使用Java中的Math.max()方法比较两个数的大小?
- 2023-11-18 501浏览