JTextAreaに行番号を表示

編集者:Terai Atsuhiro
作成日:2006-02-20
更新日:2021-04-09 (金) 19:42:12

概要

JTextAreaに行番号を表示します。

http://terai.xrea.jp/swing/linenumber/screenshot.png

サンプルコード

class LineNumberView extends JComponent {
  private static final int MARGIN = 5;
  private final JTextArea text;
  private final FontMetrics fontMetrics;
  private final int topInset;
  private final int fontAscent;
  private final int fontHeight;
  public LineNumberView(JTextArea textArea) {
    text = textArea;
    fontMetrics = getFontMetrics(text.getFont());
    fontHeight  = fontMetrics.getHeight();
    fontAscent  = fontMetrics.getAscent();
    topInset    = text.getInsets().top;
    text.getDocument().addDocumentListener(new DocumentListener() {
      public void insertUpdate(DocumentEvent e) {
        repaint();
      }
      public void removeUpdate(DocumentEvent e) {
        repaint();
      }
      public void changedUpdate(DocumentEvent e) {}
    });
    text.addComponentListener(new ComponentAdapter() {
      public void componentResized(ComponentEvent e) {
        revalidate();
        repaint();
      }
    });
    setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.GRAY));
  }
  private int getComponentWidth() {
    Document doc  = text.getDocument();
    Element root  = doc.getDefaultRootElement();
    int lineCount = root.getElementIndex(doc.getLength());
    int maxDigits = Math.max(3, String.valueOf(lineCount).length());
    return maxDigits*fontMetrics.stringWidth("0")+MARGIN*2;
  }
  private int getLineAtPoint(int y) {
    Element root = text.getDocument().getDefaultRootElement();
    int pos = text.viewToModel(new Point(0, y));
    return root.getElementIndex(pos);
  }
  public Dimension getPreferredSize() {
    return new Dimension(getComponentWidth(), text.getHeight());
  }
  public void paintComponent(Graphics g) {
    Rectangle clip = g.getClipBounds();
    g.setColor(getBackground());
    g.fillRect(clip.x, clip.y, clip.width, clip.height);
    g.setColor(getForeground());
    int base  = clip.y - topInset;
    int start = getLineAtPoint(base);
    int end   = getLineAtPoint(base+clip.height);
    int y = topInset-fontHeight+fontAscent+start*fontHeight;
    for(int i=start;i<=end;i++) {
      String text = String.valueOf(i+1);
      int x = getComponentWidth()-MARGIN-fontMetrics.stringWidth(text);
      y = y + fontHeight;
      g.drawString(text, x, y);
    }
  }
}

解説

Java Forums - Line Number in JTextPaneを参考にして、JTextAreaに行番号を表示しています。

上記のサンプルで使用するJTextAreaは、行の高さはすべて一定で、フォントや余白などは変更されないものと想定しています。

参考リンク

コメント