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

Java Swing如何固定JTextArea的百分比占比避免尺寸变动?

GridBagLayout下JTextArea因DocumentListener导致尺寸异常的解决方案

问题分析

你遇到的核心问题是:DocumentListener触发文本更新时,会间接触发容器的布局重绘,而GridBagLayout在未明确约束组件最小/首选尺寸的情况下,会根据RSyntaxTextArea随内容变化的首选大小重新计算布局,导致左侧文本区域宽度异常拉伸或收缩。同时初始布局的权重设置比例错误,也加剧了布局计算的混乱。

解决步骤

1. 统一左侧组件布局

把两个文本区域放到同一个JPanel中,作为一个整体参与主布局,避免单个组件的尺寸变化影响整体40%的占比。

2. 锁定左侧容器尺寸

为左侧容器设置最小宽度和首选宽度(按窗口40%比例初始化),确保文本内容变化时不会突破宽度限制。

3. 修正布局权重比例

主布局中左侧容器weightx设为0.4,右侧列表设为0.6,严格对应40%/60%的占比需求。

4. 优化文本更新逻辑

在DocumentListener中用SwingUtilities.invokeLater延迟更新字数标签,避免同步触发布局重绘。

修改后的完整代码

package jlist.demo;

import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;

public class TestWinFrame2 extends JFrame {

    RTextArea textArea;
    RTextScrollPane scrollForTextArea;

    RTextArea textArea2;
    RTextScrollPane ScrollForTextArea2;

    JPanel leftPanel; // 左侧统一容器

    JList jList;
    JScrollPane listScrollPane;

    JLabel wordNumberLabel;
    JToolBar toolBar;

    public TestWinFrame2() {
        GridBagLayout gridBagLayout = new GridBagLayout();
        setLayout(gridBagLayout);

        // 工具栏布局
        toolBar = new JToolBar(JToolBar.HORIZONTAL);
        GridBagConstraints bag = new GridBagConstraints();
        bag.anchor = GridBagConstraints.NORTHWEST;
        bag.gridx = 0;
        bag.gridy = 0;
        bag.gridheight = 1;
        bag.gridwidth = 2;
        bag.weightx = 1.0;
        bag.fill = GridBagConstraints.HORIZONTAL;
        wordNumberLabel = new JLabel("word-count");
        toolBar.add(wordNumberLabel);
        add(toolBar, bag);

        // 左侧容器布局
        leftPanel = new JPanel(new GridBagLayout());
        GridBagConstraints leftGbc = new GridBagConstraints();
        leftGbc.fill = GridBagConstraints.BOTH;
        leftGbc.weightx = 1.0;
        leftGbc.weighty = 0.5;
        leftGbc.gridx = 0;

        // 第一个文本区域
        textArea = new RSyntaxTextArea();
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        scrollForTextArea = new RTextScrollPane(textArea);
        leftGbc.gridy = 0;
        leftPanel.add(scrollForTextArea, leftGbc);

        // 第二个文本区域
        textArea2 = new RSyntaxTextArea();
        textArea2.setLineWrap(true);
        textArea2.setWrapStyleWord(true);
        ScrollForTextArea2 = new RTextScrollPane(textArea2);
        leftGbc.gridy = 1;
        leftPanel.add(ScrollForTextArea2, leftGbc);

        // 锁定左侧容器最小宽度
        int initLeftWidth = (int) (1200 * 0.4);
        leftPanel.setMinimumSize(new Dimension(initLeftWidth, 0));
        leftPanel.setPreferredSize(new Dimension(initLeftWidth, 0));

        // 左侧容器加入主布局
        GridBagConstraints gbcLeftPanel = new GridBagConstraints();
        gbcLeftPanel.anchor = GridBagConstraints.WEST;
        gbcLeftPanel.fill = GridBagConstraints.BOTH;
        gbcLeftPanel.gridx = 0;
        gbcLeftPanel.gridy = 1;
        gbcLeftPanel.gridheight = 2;
        gbcLeftPanel.gridwidth = 1;
        gbcLeftPanel.weightx = 0.4d;
        gbcLeftPanel.weighty = 1.0d;
        add(leftPanel, gbcLeftPanel);

        // 右侧列表布局
        jList = new JList();
        listScrollPane = new JScrollPane(jList);
        GridBagConstraints gbc_listScrollPane = new GridBagConstraints();
        gbc_listScrollPane.anchor = GridBagConstraints.WEST;
        gbc_listScrollPane.fill = GridBagConstraints.BOTH;
        gbc_listScrollPane.gridx = 1;
        gbc_listScrollPane.gridy = 1;
        gbc_listScrollPane.gridheight = 2;
        gbc_listScrollPane.gridwidth = 1;
        gbc_listScrollPane.weightx = 0.6d;
        gbc_listScrollPane.weighty = 1.0d;
        add(listScrollPane, gbc_listScrollPane);

        // 添加文本监听
        textAreaAddInsertListener();

        setSize(1200, 800);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public void textAreaAddInsertListener() {
        textArea.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateWordCount();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateWordCount();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                updateWordCount();
            }

            private void updateWordCount() {
                SwingUtilities.invokeLater(() -> {
                    wordNumberLabel.setText(String.valueOf(textArea.getText().length()));
                });
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(TestWinFrame2::new);
    }
}

关键修改说明

  • 用leftPanel统一管理左侧两个文本区域,避免单个组件尺寸变化干扰整体布局比例。
  • 为leftPanel设置固定最小宽度,阻止文本内容变化引发的宽度异常。
  • 修正主布局weightx比例,确保左右区域严格按40%/60%分配宽度。
  • 延迟更新字数标签,避免在文档事件处理中同步触发布局重绘,减少不必要的布局计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 10:27:09