2

I'm trying to reliably count the number of lines (including those from line wraps and line breaks) in a JTextArea given a set width. I'm using this information to set the height of other components in my GUI (for example, for n lines, set n*height of a component).

I stumbled across this solution (reproduced below) but there is a problem with this. Sometimes it would miss a line if there isn't too much text on that line. For example, if a JTextArea of width 100 has 3 lines of text and on the 3rd line it only has say around width 15 of text, then it will only count 2 lines instead of 3.

public class MyTextArea extends JTextArea {

    //...

    public int countLines(int width) {

        AttributedString text = new AttributedString(this.getText());
        FontRenderContext frc = this.getFontMetrics(this.getFont()).getFontRenderContext();
        AttributedCharacterIterator charIt = text.getIterator();
        LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc);
        lineMeasurer.setPosition(charIt.getBeginIndex());

        int noLines = 0;
        while (lineMeasurer.getPosition() < charIt.getEndIndex()) {
            lineMeasurer.nextLayout(width);
            noLines++;
        }

        System.out.print("there are " + noLines + "lines" + System.getProperty("line.separator"));
        return noLines;
    }
}

Any idea what might be causing this issue? Are there any alternatives to counting lines in a JTextArea? Thanks.

Community
  • 1
  • 1
Chun
  • 1,968
  • 3
  • 17
  • 18
  • 1
    Calculating the size based on content will really only work with a fixed width font. *"Are there any alternatives to counting lines in a JTextArea?"* It depends what you are actually trying to achieve. See [`FixedWidthText`](http://stackoverflow.com/a/5767825/418556) for one (possible) alternative using styled HTML in a `JLabel`. – Andrew Thompson Jun 09 '13 at 00:44
  • Basically I want to use this information to set the sizes of components around the JTextArea depending on the size of the JTextArea. Say one line is 10 pixels tall. If the JTextArea has two lines, I want a component next to it be 20 pixels tall. If the JTextArea has four lines, I want the component now to be 40 pixels tall. The JTextArea text is variable, so depending on the number of lines it has, I want that component to be 10*n pixels tall. – Chun Jun 09 '13 at 01:04
  • For equal sizing, `GridLayout` may be an option. – trashgod Jun 09 '13 at 01:05
  • I'm actually using a GridBagLayout-- the component next to the JTextArea must have an equal height, but I'm also setting a preferred width. – Chun Jun 09 '13 at 01:11
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Jun 09 '13 at 01:13

2 Answers2

2

I'm using this information to set the height of other components in my GUI.

Instead, let each component adopt its preferred size and pack() the enclosing container. As shown here, you can add the text area to a scroll pane whose size is limited, perhaps to a convenient multiple of the line height. More generally, you can implement the Scrollable interface as outlined here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
2

So I came up with a simple solution that uses FontMetrics to calculate the display width of the text, and by splitting the text into string tokens, I can count how many lines there will be.

public int countLines(int width) {

        FontMetrics fontMetrics = this.getFontMetrics(this.getFont());
        String text = this.getText();
        String[] tokens = text.split(" ");
        String currentLine = "";
        boolean beginningOfLine = true;
        int noLines = 1;

        for (int i = 0; i < tokens.length; i++) {
            if (beginningOfLine) {
                beginningOfLine = false;
                currentLine = currentLine + tokens[i];
            } else {
                currentLine = currentLine + " " + tokens[i];
            }

            if (fontMetrics.stringWidth(currentLine) > width) {
                currentLine = "";
                beginningOfLine = true;
                noLines++;
            }
        }

        System.out.print("there are " + noLines + "lines" + System.getProperty("line.separator"));
        return noLines;
}
Chun
  • 1,968
  • 3
  • 17
  • 18