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

JavaFX中代码设置ComboBox在GridPane的rowSpan不生效问题

JavaFX GridPane 添加跨两行ComboBox不生效问题

我尝试通过代码向已有的GridPane(名为daysGridPane)中添加一个ComboBox,要求该ComboBox跨两行显示。整体布局嵌套关系为:daysGridPane放在parentGridPane内的ScrollPane中,目的是让daysGridPane内容可滚动,其余UI保持固定显示。但实际添加后,ComboBox并未跨两行,仅占据上方单元格。

窗口显示时,“Monday”下方的第一个ComboBox是通过SceneBuilder的FXML定义的,我在SceneBuilder中创建了第二个跨两行的ComboBox,并将所有等效设置复制到代码中,但仍未生效。从截图可见网格线,新增的行比parentGridPane的行更小,不确定这是否为问题根源。


相关FXML文件

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>

<GridPane fx:id="parentGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" stylesheets="@application.css" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.levin.ctrl.TrainingPlanEditorCtrl">
   <children>
      <ComboBox fx:id="startHourComboBox" GridPane.columnIndex="1" GridPane.rowIndex="1">
         <GridPane.margin>
            <Insets top="6.0" />
         </GridPane.margin>
      </ComboBox>
      <ComboBox fx:id="startMinutesComboBox" GridPane.columnIndex="3" GridPane.rowIndex="1">
         <GridPane.margin>
            <Insets right="6.0" top="6.0" />
         </GridPane.margin>
      </ComboBox>
      <ComboBox fx:id="endHourComboBox" GridPane.columnIndex="1" GridPane.rowIndex="2">
         <GridPane.margin>
            <Insets bottom="12.0" top="6.0" />
         </GridPane.margin>
      </ComboBox>
      <ComboBox fx:id="endMinutesComboBox" GridPane.columnIndex="3" GridPane.rowIndex="2">
         <GridPane.margin>
            <Insets bottom="12.0" right="6.0" top="6.0" />
         </GridPane.margin>
      </ComboBox>
      <Label text=":" GridPane.columnIndex="2" GridPane.rowIndex="1">
         <GridPane.margin>
            <Insets left="3.0" right="3.0" />
         </GridPane.margin>
      </Label>
      <Label text=":" GridPane.columnIndex="2" GridPane.rowIndex="2">
         <GridPane.margin>
            <Insets left="3.0" right="3.0" />
         </GridPane.margin>
      </Label>
      <Label text="Start" GridPane.rowIndex="1">
         <GridPane.margin>
            <Insets left="12.0" right="6.0" />
         </GridPane.margin>
      </Label>
      <Label text="End" GridPane.rowIndex="2">
         <GridPane.margin>
            <Insets left="12.0" right="6.0" />
         </GridPane.margin>
      </Label>
      <Button fx:id="addDayButton" mnemonicParsing="false" onAction="#addDay" text="+" GridPane.columnIndex="5">
         <GridPane.margin>
            <Insets right="12.0" top="12.0" />
         </GridPane.margin>
      </Button>
      <Button fx:id="addIntervallButton" mnemonicParsing="false" onAction="#addIntervall" text="+" GridPane.columnIndex="1" GridPane.rowIndex="3">
         <GridPane.margin>
            <Insets bottom="12.0" top="12.0" />
         </GridPane.margin>
      </Button>
      <Separator prefWidth="200.0" GridPane.columnSpan="2147483647" GridPane.rowIndex="4">
         <GridPane.margin>
            <Insets bottom="6.0" top="6.0" />
         </GridPane.margin>
      </Separator>
      <Button fx:id="okButton" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#ok" text="OK" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="5">
         <GridPane.margin>
            <Insets bottom="24.0" top="6.0" />
         </GridPane.margin>
      </Button>
      <Button fx:id="cancelButton" mnemonicParsing="false" onAction="#cancel" text="Cancel" GridPane.columnIndex="4" GridPane.rowIndex="5">
         <GridPane.margin>
            <Insets bottom="24.0" top="6.0" />
         </GridPane.margin>
      </Button>
      <ScrollPane fx:id="daysScrollPane" GridPane.columnIndex="4" GridPane.hgrow="ALWAYS" GridPane.rowSpan="3" GridPane.vgrow="ALWAYS">
         <content>
            <GridPane fx:id="daysGridPane" maxWidth="1.7976931348623157E308">
              <columnConstraints>
                <ColumnConstraints />
              </columnConstraints>
              <rowConstraints>
                <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="ALWAYS" />
              </rowConstraints>
               <children>
                  <ComboBox fx:id="dayComboBox">
                     <GridPane.margin>
                        <Insets bottom="6.0" right="12.0" />
                     </GridPane.margin>
                  </ComboBox>
                  <ComboBox fx:id="sessionComboBox" maxHeight="1.7976931348623157E308" GridPane.rowIndex="1" GridPane.rowSpan="2">
                     <GridPane.margin>
                        <Insets right="12.0" />
                     </GridPane.margin>
                  </ComboBox>
               </children>
            </GridPane>
         </content>
         <GridPane.margin>
            <Insets right="12.0" top="12.0" />
         </GridPane.margin>
      </ScrollPane>
   </children>
   <columnConstraints>
      <ColumnConstraints />
      <ColumnConstraints />
      <ColumnConstraints />
      <ColumnConstraints />
      <ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="10.0" />
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints minHeight="10.0" />
      <RowConstraints />
      <RowConstraints minHeight="10.0" />
      <RowConstraints minHeight="10.0" />
      <RowConstraints minHeight="10.0" vgrow="NEVER" />
      <RowConstraints minHeight="10.0" vgrow="NEVER" />
   </rowConstraints>
</GridPane>

原添加ComboBox的代码

@FXML
protected void addIntervall(ActionEvent event) {


    // Find the index for the new column 
    int newRowIndex = parentGridPane.getRowConstraints().size() -3; // add-intervall, ok, cancel button rows

    ...
    
    // extend session daysGridPane
    GridPane.setRowSpan(daysScrollPane, GridPane.getRowSpan(daysScrollPane) + 2);
    
    daysGridPane.setGridLinesVisible(true);
    
    RowConstraints rowC1 = new RowConstraints();    // we need two new rows that are spaned by the new ComboBox
    RowConstraints rowC2 = new RowConstraints();

    rowC1.setVgrow(Priority.ALWAYS);
    rowC1.setMaxHeight(Double.MAX_VALUE);
    rowC1.setFillHeight(true);
    rowC2.setVgrow(Priority.ALWAYS);
    rowC2.setMaxHeight(Double.MAX_VALUE);
    rowC2.setFillHeight(true);
    daysGridPane.getRowConstraints().add(newRowIndex, rowC1 );      
    daysGridPane.getRowConstraints().add(newRowIndex, rowC2);
    
    ComboBox<Session> newSessionCB = new ComboBox<Session>();
    daysGridPane.add(newSessionCB, 0, newRowIndex);
    GridPane.setRowSpan(newSessionCB, 2);
    newSessionCB.setMaxHeight(Double.MAX_VALUE);
    GridPane.setVgrow(newSessionCB, Priority.ALWAYS);
    newSessionCB.setItems(persistance.loadSessions(null));
}

问题根源与修正方案

1. 行索引计算错误

你用parentGridPane.getRowConstraints().size() -3作为新行索引,但该索引是针对parentGridPane的,而daysGridPane的行约束列表是独立的,应该基于daysGridPane的现有行数计算起始索引。

2. 新增行插入顺序错误

连续两次向同一索引插入行约束,会导致行顺序颠倒,破坏跨行列的布局计算逻辑,应将新行追加到daysGridPane行约束的末尾。

3. 不必要的ScrollPane行跨度调整

daysGridPane在ScrollPane内部,调整ScrollPane的行跨度不会影响其内部布局,反而可能破坏parentGridPane的整体布局,应删除该操作。

修正后的代码

@FXML
protected void addIntervall(ActionEvent event) {
    // 基于daysGridPane的现有行数计算新行起始索引
    int newRowIndex = daysGridPane.getRowConstraints().size();

    daysGridPane.setGridLinesVisible(true);
    
    RowConstraints rowC1 = new RowConstraints();
    RowConstraints rowC2 = new RowConstraints();

    // 和FXML中定义的行保持一致的属性
    rowC1.setVgrow(Priority.ALWAYS);
    rowC1.setPrefHeight(30.0);
    rowC1.setFillHeight(true);
    rowC2.setVgrow(Priority.ALWAYS);
    rowC2.setPrefHeight(30.0);
    rowC2.setFillHeight(true);
    
    // 将新行追加到daysGridPane的行约束末尾
    daysGridPane.getRowConstraints().addAll(rowC1, rowC2);
    
    ComboBox<Session> newSessionCB = new ComboBox<>();
    daysGridPane.add(newSessionCB, 0, newRowIndex);
    GridPane.setRowSpan(newSessionCB, 2);
    newSessionCB.setMaxHeight(Double.MAX_VALUE);
    GridPane.setVgrow(newSessionCB, Priority.ALWAYS);
    // 添加和FXML中一致的边距
    GridPane.setMargin(newSessionCB, new Insets(0, 12, 0, 0));
    newSessionCB.setItems(persistance.loadSessions(null));
}

另外,确保daysGridPane的maxHeight已设置为Double.MAX_VALUE(FXML中已配置),这样它能随内容扩展高度,保证ScrollPane正常滚动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 04:49:52