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

JavaFX中GridPane内TextFlow溢出重叠问题求助

JavaFX GridPane内TextFlow文本溢出重叠问题

问题背景

使用JavaFX 21开发时,GridPane单元格内的TextFlow出现文本溢出重叠情况,推测可能是未定义prefHeight导致,但不知道如何计算并设置或绑定该高度。需求是让TextFlow自动占用足够高度完整显示文本,且整个GridPane处于ScrollPane中,需确认这是否为问题根源,或是存在其他问题。

溢出重叠截图

FXML定义

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

<?import java.lang.String?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>

<fx:root stylesheets="@../styles/main.css" type="BorderPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
    <styleClass>
      <String fx:value="binocles-pane" />
      <String fx:value="book-pane" />
  </styleClass>
   <center>
        <VBox fx:id="bookZoneVBox" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
              <Text fx:id="bookTitle" strokeType="OUTSIDE" strokeWidth="0.0" styleClass="main-title" text="Book title">
               <font>
                  <Font size="14.0" />
               </font>
            </Text>
              <ScrollPane fx:id="bookZoneScroll" fitToHeight="true" fitToWidth="true" focusTraversable="false" hbarPolicy="NEVER" minHeight="224.0" minWidth="300.0" prefHeight="233.0" prefWidth="310.0" styleClass="edge-to-edge" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
               <content>
                  <GridPane fx:id="bookGrid" minHeight="150.0" minWidth="300.0" prefHeight="215.0" prefWidth="300.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
                    <columnConstraints>
                      <ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
                      <ColumnConstraints hgrow="ALWAYS" minWidth="200.0" />
                    </columnConstraints>
                    <rowConstraints>
                      <RowConstraints minHeight="10.0" prefHeight="22.0" vgrow="ALWAYS" />
                      <RowConstraints minHeight="10.0" prefHeight="21.0" vgrow="ALWAYS" />
                      <RowConstraints minHeight="10.0" prefHeight="24.0" vgrow="NEVER" />
                      <RowConstraints minHeight="10.0" prefHeight="138.0" vgrow="SOMETIMES" />
                    </rowConstraints>
                     <children>
                        <Label text="Synopsis" GridPane.valignment="TOP" />
                        <Label text="Description" GridPane.rowIndex="1" GridPane.valignment="TOP" />
                        <Label text="Metadata" GridPane.rowIndex="2" GridPane.valignment="BOTTOM" />
                        <TableView fx:id="bookMetadataTable" focusTraversable="false" maxHeight="150.0" maxWidth="300.0" prefHeight="150.0" prefWidth="300.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" GridPane.columnSpan="2147483647" GridPane.hgrow="ALWAYS" GridPane.rowIndex="3">
                          <columns>
                            <TableColumn editable="false" prefWidth="75.0" sortable="false" text="Field" />
                            <TableColumn editable="false" prefWidth="215.0" sortable="false" text="Value" />
                          </columns>
                           <padding>
                              <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
                           </padding>
                        </TableView>
                        <TextFlow fx:id="bookSynopsisField" minWidth="200.0" textAlignment="JUSTIFY" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" />
                        <TextFlow fx:id="bookDescriptionField" minWidth="200.0" textAlignment="JUSTIFY" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" />
                     </children>
                  </GridPane>
               </content>
               <padding>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </padding>
              </ScrollPane>
         </children>
      </VBox>
   </center>
</fx:root>

Java代码

package com.github.sylordis.binocles.ui.views;

import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.ResourceBundle;

import com.github.sylordis.binocles.model.text.Book;
import com.github.sylordis.binocles.ui.javafxutils.FXFormatUtils;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;

/**
 * Pane component for a book.
 */
public class BookView extends BorderPane implements Initializable, BinoclesTabPane {

    private Book book;

    @FXML
    private Text bookTitle;
    @FXML
    private VBox bookZoneVBox;
    @FXML
    private TextFlow bookSynopsisField;
    @FXML
    private TextFlow bookDescriptionField;
    @FXML
    private GridPane bookGrid;
    @FXML
    private ScrollPane bookZoneScroll;
    @FXML
    private TableView<Map.Entry<String, String>> bookMetadataTable;

    private ObservableList<Map.Entry<String, String>> bookMetadataTableData;

    public BookView(Book book) {
        super();
        this.book = book;
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("book_view.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }

    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // Set content
        bookTitle.setText(book.getTitle());
        bookSynopsisField.getChildren().add(new Text(book.getSynopsis()));
        bookDescriptionField.getChildren().add(new Text(book.getDescription()));
        bookMetadataTable.setPlaceholder(new Label("No metadata provided"));
        bookMetadataTable.setItems(FXCollections.observableArrayList(book.getMetadata().entrySet()));
        bookMetadataTable.refresh();
        // Format
        FXFormatUtils.bindToParent(bookGrid);
        bookSynopsisField.setMaxWidth(Double.MAX_VALUE);
        bookSynopsisField.setMaxHeight(Double.MAX_VALUE);
        bookDescriptionField.setMaxWidth(Double.MAX_VALUE);
        bookDescriptionField.setMaxHeight(Double.MAX_VALUE);
        bookGrid.maxWidthProperty().bind(bookZoneScroll.widthProperty().subtract(5));
        bookGrid.prefWidthProperty().bind(bookZoneScroll.widthProperty().subtract(5));
        bookGrid.getColumnConstraints().forEach(c -> c.setMaxWidth(Double.MAX_VALUE));
        // Debug
        bookSynopsisField.setStyle("-fx-border-color: #FF0000");
        bookDescriptionField.setStyle("-fx-border-color: #00FF00");
        
    }

    @Override
    public Object getItem() {
        return book;
    }

}

问题根源与解决方案

核心问题

  1. GridPane行约束固定高度:FXML中前两行RowConstraints设置了固定prefHeight(22、21),限制了行的可扩展空间,即使TextFlow内容需要更多高度,行也无法自动适配,导致文本溢出重叠。
  2. ScrollPane强制适配高度:fitToHeight="true"会强制内容高度适配ScrollPane可视区域,而非让内容自然展开后通过滚动查看,进一步压缩了TextFlow的可用空间。

修复步骤

1. 调整GridPane行约束

移除前两行RowConstraints的固定prefHeight,保留vgrow="ALWAYS"让行高度完全由内容决定:

<rowConstraints>
  <RowConstraints minHeight="10.0" vgrow="ALWAYS" />
  <RowConstraints minHeight="10.0" vgrow="ALWAYS" />
  <RowConstraints minHeight="10.0" prefHeight="24.0" vgrow="NEVER" />
  <RowConstraints minHeight="10.0" prefHeight="138.0" vgrow="SOMETIMES" />
</rowConstraints>

2. 修改ScrollPane适配属性

将fitToHeight="true"改为fitToHeight="false",让ScrollPane尊重内容实际高度,超出可视区域时自动显示垂直滚动条:

<ScrollPane fx:id="bookZoneScroll" fitToHeight="false" fitToWidth="true" focusTraversable="false" hbarPolicy="NEVER" minHeight="224.0" minWidth="300.0" prefHeight="233.0" prefWidth="310.0" styleClass="edge-to-edge" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">

3. 绑定TextFlow宽度确保换行

在initialize方法中添加代码,将TextFlow宽度绑定到对应列的宽度,确保文本正确换行并计算出合适高度:

// 绑定TextFlow宽度到第二列的可用宽度
bookSynopsisField.prefWidthProperty().bind(bookGrid.getColumnConstraints().get(1).widthProperty());
bookDescriptionField.prefWidthProperty().bind(bookGrid.getColumnConstraints().get(1).widthProperty());

4. 移除GridPane固定高度

删除bookGrid的prefHeight="215.0",让GridPane根据内容自动计算整体高度:

<GridPane fx:id="bookGrid" minHeight="150.0" minWidth="300.0" prefWidth="300.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">

额外优化

  • 可移除TextFlow的maxHeight设置,默认值即为Double.MAX_VALUE,无需显式声明。
  • 确保GridPane在ScrollPane中可垂直扩展,保证内容能完整显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:40:54