JTextArea 显示行号

系统:Win10
JDK:1.8.0_333
IDEA:2020.3.4

1.需求描述

最近在做一个 Swing 项目的时候,使用到了 JTextArea 组件,然后需要显示文本处于多少行,在左边需要显示它的行号,并且会随着行号的增加,显示行号的面板的宽度会自动扩展开

2.代码实现

import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import java.awt.*;

/**
 * @ClassName MyTextArea
 * @Description 实现 JTextArea 显示行号
 * @Author Li
 * @Date 2022/8/28 13:55
 * @ModifyDate 2022/8/28 13:55
 * @Version 1.0
 */
public class MyTextArea extends JPanel {
    private LinePanel linePanel;

    private JTextArea textArea;

    private JScrollPane scrollPane;

    public MyTextArea() {
        this.setLayout(new BorderLayout());
        linePanel = new LinePanel();
        linePanel.setPreferredSize(new Dimension(25, 10));
        this.textArea = new JTextArea() {
            public void paint(Graphics g) {
                super.paint(g);
                linePanel.repaint();
            }
        };
        this.scrollPane = new JScrollPane(this.textArea);
        this.add(linePanel, BorderLayout.WEST);
        this.add(scrollPane, BorderLayout.CENTER);
    }

    // 内部类:显示行号的面板
    private class LinePanel extends JPanel {
        @Override
        public void paint(Graphics g) {
            super.paint(g);
            // starting pos in document
            int start = textArea.viewToModel(scrollPane.getViewport().getViewPosition());
            // end pos in doc
            int end = textArea.viewToModel(new Point(scrollPane.getViewport().getViewPosition().x + textArea.getWidth()
                    , scrollPane.getViewport().getViewPosition().y + textArea.getHeight()));

            // translate offsets to lines
            Document doc = textArea.getDocument();
            int startLine = doc.getDefaultRootElement().getElementIndex(start) + 1;
            int endLine = doc.getDefaultRootElement().getElementIndex(end) + 1;

            int fontHeight = g.getFontMetrics(textArea.getFont()).getHeight();
            int fontDesc = g.getFontMetrics(textArea.getFont()).getDescent();
            int starting_y = -1;
            
            try {
                starting_y = textArea.modelToView(start).y -
                        scrollPane.getViewport().getViewPosition().y + fontHeight - fontDesc;
            } catch (BadLocationException ble) {
                ble.printStackTrace();
            }

            for (int line = startLine, y = starting_y; line <= endLine; y += fontHeight, line++) {
                g.drawString(Integer.toString(line), getNumX(line), y);
            }
        }

        // 获取当前行的行号 x 坐标
        private int getNumX(int line) {
            int width = linePanel.getWidth() - 5;
            FontMetrics metrics = linePanel.getFontMetrics(this.getFont());
            int fontHeight = metrics.getHeight();
            int fontWidth = metrics.stringWidth("0");
            int digit = 0;
            while (line > 0) {
                line = line / 10;
                digit++;
            }
            int x = width - digit * fontWidth;
            // 自适应调整宽度
            if (x < 5) {
                linePanel.setPreferredSize(new Dimension(getWidth() + fontWidth, fontHeight));
                linePanel.updateUI();
            }
            return x;
        }
    }

    // 主方法测试
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setTitle("JTextArea显示行号");
        frame.setLayout(new BorderLayout());
        MyTextArea textArea = new MyTextArea();
        frame.getContentPane().add(textArea, BorderLayout.CENTER);
        frame.setSize(new Dimension(400, 300));
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

3.效果演示

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李晋江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值