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

JScrollPane水平调整大小时动态RowHeader与Viewport不同步如何解决

问题根因

该滚动不同步问题由两点原因导致:

  1. 调用JTextPane#setText()更新行号内容时,组件默认会将滚动位置跳转至内容末尾,和主JTextArea的视口位置不匹配
  2. 原有实现仅监听了组件尺寸变化事件,未监听主文本区的滚动事件,也未在文本内容更新时主动触发行号刷新

修复方案

新增以下逻辑即可解决:

  • 每次行号内容更新后,手动同步行号组件与主文本区的视口Y坐标
  • 监听主视口的滚动事件,用户滚动文本时同步行号位置
  • 文本内容赋值方法中主动触发行号刷新

完整修改后代码

package main;

import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collections;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Utilities;

public class SequenceAreaExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(150, 200);

        SequenceArea sequenceArea = new SequenceArea();
        frame.add(sequenceArea);

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        
        frame.setVisible(true);
        sequenceArea.setText(String.join("", Collections.nCopies(200, "a")));
    }
}

class SequenceArea extends JScrollPane implements ComponentListener {
    private static final long serialVersionUID = 1L;

    private JTextArea text;
    private JTextPane numbers;

    SequenceArea() {
        text = new JTextArea();
        text.setLineWrap(true);
        text.setEnabled(true);
        text.addComponentListener(this);

        numbers = new JTextPane();
        numbers.setEnabled(false);

        setViewportView(text);
        setRowHeaderView(numbers);
        
        // 监听主视口滚动事件,同步行号位置
        getViewport().addChangeListener(e -> syncRowHeaderPosition());
    }
    
    // 同步行号组件与主文本区的视口位置
    private void syncRowHeaderPosition() {
        if (getRowHeader() != null) {
            Point viewPos = getViewport().getViewPosition();
            getRowHeader().setViewPosition(new Point(0, viewPos.y));
        }
    }

    void updateNumbers() {
        StringBuilder newNumbers = new StringBuilder();

        int length = text.getText().length();
        int index = 0;

        while (index < length) {
            try {
                int start = Utilities.getRowStart(text, index);
                int end = Utilities.getRowEnd(text, index);

                newNumbers.append(start);
                newNumbers.append('\n');

                index = end + 1;
            } catch (BadLocationException e) {
                break;
            }
        }

        numbers.setText(newNumbers.toString());
        // 行号更新后同步位置
        syncRowHeaderPosition();
    }

    void setText(String t) {
        text.setText(t);
        // 文本内容更新后主动刷新行号
        updateNumbers();
    }

    @Override
    public void componentResized(ComponentEvent e) {
        updateNumbers();
    }

    @Override
    public void componentMoved(ComponentEvent e) {}

    @Override
    public void componentShown(ComponentEvent e) {}

    @Override
    public void componentHidden(ComponentEvent e) {}
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:15:02