JScrollPane水平调整大小时动态RowHeader与Viewport不同步如何解决
问题根因
该滚动不同步问题由两点原因导致:
- 调用
JTextPane#setText()更新行号内容时,组件默认会将滚动位置跳转至内容末尾,和主JTextArea的视口位置不匹配 - 原有实现仅监听了组件尺寸变化事件,未监听主文本区的滚动事件,也未在文本内容更新时主动触发行号刷新
修复方案
新增以下逻辑即可解决:
- 每次行号内容更新后,手动同步行号组件与主文本区的视口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
相关产品推荐
相关产品推荐

