如何让JavaFX中不同GridPane的对应列宽度相等?
如何让JavaFX中不同GridPane的对应列宽度相等?
提问需求
我想要实现这样的效果:两个带标题的面板(TitledPane),每个面板里都包含一个两列的GridPane——第一列是标签,第二列是输入控件。我希望上方TitledPane里GridPane的标签列宽度和下方的保持完全一致,不然界面看起来很不协调。而且因为标签文本会随用户语言变化,所以不能用固定像素宽度。
目前我的代码是这样的:
public class MyGridPanes extends Application { @Override public void start(Stage stage) { GridPane gridPane1 = new GridPane(); gridPane1.add(new Label("One two three"), 0, 0); gridPane1.add(new TextField(), 1, 0); gridPane1.setHgap(20); var titledPane1 = new TitledPane("Top", gridPane1); titledPane1.setCollapsible(false); GridPane gridPane2 = new GridPane(); gridPane2.setHgap(20); gridPane2.add(new Label("Four five six seven"), 0, 0); gridPane2.add(new TextField(), 1, 0); var titledPane2 = new TitledPane("Bottom", gridPane2); titledPane2.setCollapsible(false); Scene scene = new Scene(new VBox(titledPane1, titledPane2), 400, 200); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
现在的问题是:两个GridPane的标签列宽度因为标签文本长度不同而不一致,上方标签短列宽就窄,下方标签长列宽就宽,界面看起来很不整齐。
解决方案
这个场景我太熟了,之前做多语言配置界面时踩过一模一样的坑!固定宽度绝对是下下策,给你两个简单又靠谱的方案,完全适配多语言场景:
方案一:用ColumnConstraints+双向绑定同步列宽
核心思路是给两个GridPane的列设置统一的约束规则,再把它们的标签列宽度双向绑定,这样不管哪一侧的列宽变化,另一侧都会自动同步:
public class MyGridPanes extends Application { @Override public void start(Stage stage) { // 配置两列的约束:标签列不自动扩展,输入列占满剩余空间 ColumnConstraints labelColumn = new ColumnConstraints(); labelColumn.setHgrow(Priority.NEVER); // 禁止列自动扩展 labelColumn.setFillWidth(false); // 只适配内容宽度,不填充多余空间 ColumnConstraints inputColumn = new ColumnConstraints(); inputColumn.setHgrow(Priority.ALWAYS); // 占满剩余可用空间 // 第一个TitledPane和GridPane GridPane gridPane1 = new GridPane(); gridPane1.getColumnConstraints().addAll(labelColumn, inputColumn); gridPane1.add(new Label("One two three"), 0, 0); gridPane1.add(new TextField(), 1, 0); gridPane1.setHgap(20); var titledPane1 = new TitledPane("Top", gridPane1); titledPane1.setCollapsible(false); // 第二个TitledPane和GridPane GridPane gridPane2 = new GridPane(); ColumnConstraints labelColumn2 = new ColumnConstraints(); labelColumn2.setHgrow(Priority.NEVER); labelColumn2.setFillWidth(false); gridPane2.getColumnConstraints().addAll(labelColumn2, inputColumn); gridPane2.add(new Label("Four five six seven"), 0, 0); gridPane2.add(new TextField(), 1, 0); gridPane2.setHgap(20); var titledPane2 = new TitledPane("Bottom", gridPane2); titledPane2.setCollapsible(false); // 关键:双向绑定两个标签列的宽度,保证完全同步 labelColumn.prefWidthProperty().bindBidirectional(labelColumn2.prefWidthProperty()); Scene scene = new Scene(new VBox(titledPane1, titledPane2), 400, 200); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
方案二:绑定列宽到标签的最大宽度
如果想让标签列直接适配两个标签中更宽的那个,可以用Bindings.max()动态获取最大宽度,再绑定给列约束,这样列宽会自动调整到能容纳最长标签的尺寸:
public class MyGridPanes extends Application { @Override public void start(Stage stage) { ColumnConstraints labelColumn = new ColumnConstraints(); labelColumn.setHgrow(Priority.NEVER); labelColumn.setFillWidth(false); ColumnConstraints inputColumn = new ColumnConstraints(); inputColumn.setHgrow(Priority.ALWAYS); // 第一个GridPane和标签 Label label1 = new Label("One two three"); GridPane gridPane1 = new GridPane(); gridPane1.getColumnConstraints().addAll(labelColumn, inputColumn); gridPane1.add(label1, 0, 0); gridPane1.add(new TextField(), 1, 0); gridPane1.setHgap(20); var titledPane1 = new TitledPane("Top", gridPane1); titledPane1.setCollapsible(false); // 第二个GridPane和标签 Label label2 = new Label("Four five six seven"); GridPane gridPane2 = new GridPane(); gridPane2.getColumnConstraints().addAll(labelColumn, inputColumn); gridPane2.add(label2, 0, 0); gridPane2.add(new TextField(), 1, 0); gridPane2.setHgap(20); var titledPane2 = new TitledPane("Bottom", gridPane2); titledPane2.setCollapsible(false); // 关键:动态计算两个标签的最大宽度,绑定给标签列的首选宽度 DoubleBinding maxLabelWidth = Bindings.max(label1.widthProperty(), label2.widthProperty()); labelColumn.prefWidthProperty().bind(maxLabelWidth); Scene scene = new Scene(new VBox(titledPane1, titledPane2), 400, 200); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } }
两种方法都不需要硬编码像素值,完全适配多语言场景下的文本长度变化,你可以根据自己的需求选一个~
备注:内容来源于stack exchange,提问作者SilverCube
相关产品推荐
相关产品推荐

