Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count the number of lines in a JTextArea, including those caused by wrapping?

I have a JTextArea for which I have set word-wrap and wrap-style-word to true. I want to "pack" the JTextArea to the minimum possible height given a specified width.

To do this, I'm planning calculating the height of the font using...

  Font font = jTextArea.getFont();
  FontMetrics fontMetrics = jTextArea.getFontMetrics(font);
  int lineHeight = fontMetrics.getAscent() + fontMetrics.getDescent();

...and then multiply this by the number of lines used in the JTextArea. The problem is that JTextArea.getLineCount() counts the number of line returns ignoring the wrapped lines.

How do I count the number of lines used in a JTextArea including those that are caused by word wrap?

Here's some demo code to make toying with this problem easier. I have a listener that prints out the number of lines each time the window is resized. At the moment, it always prints 1, but I want to to compensate for the word wrap and print out how many lines are actually being used.

EDIT: I've included the solution to the problem in the code below. The static countLines method gives the solution.

package components;                                                                           

import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.text.*;
import javax.swing.*;

public class JTextAreaLineCountDemo extends JPanel {                                          
  JTextArea textArea;                                                                         

  public JTextAreaLineCountDemo() {                                                           
    super(new GridBagLayout());                                                               

    String inputStr = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmo";
    textArea = new JTextArea(inputStr);                                                       
    textArea.setEditable(false);                                                              
    textArea.setLineWrap(true);                                                               
    textArea.setWrapStyleWord(true);                                                          

    // Add Components to this panel.                                                          
    GridBagConstraints c = new GridBagConstraints();                                          
    c.gridwidth = GridBagConstraints.REMAINDER;                                               

    c.fill = GridBagConstraints.BOTH;                                                         
    c.weightx = 1.0;                                                                          
    c.weighty = 1.0;                                                                          
    add(textArea, c);                                                                         

    addComponentListener(new ComponentAdapter() {                                             
      @Override                                                                               
      public void componentResized(ComponentEvent ce) {                 
        System.out.println("Line count: " + countLines(textArea));                         
      }                                                                                       
    });                                                                                       
  }                                                                                           

  private static int countLines(JTextArea textArea) {
    AttributedString text = new AttributedString(textArea.getText());
    FontRenderContext frc = textArea.getFontMetrics(textArea.getFont())
        .getFontRenderContext();
    AttributedCharacterIterator charIt = text.getIterator();
    LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc);
    float formatWidth = (float) textArea.getSize().width;
    lineMeasurer.setPosition(charIt.getBeginIndex());

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

    return noLines;
  }

  private static void createAndShowGUI() {                                                    
    JFrame frame = new JFrame("JTextAreaLineCountDemo");                                      
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                                     

    frame.add(new JTextAreaLineCountDemo());                                                  

    frame.pack();                                                                             
    frame.setVisible(true);                                                                   
  }                                                                                           

  public static void main(String[] args) {                                                    
    javax.swing.SwingUtilities.invokeLater(new Runnable() {                                   
      public void run() {                                                                     
        createAndShowGUI();                                                                   
      }                                                                                       
    });                                                                                       
  }                                                                                           
}                                                                                             
like image 970
peskal Avatar asked Jun 16 '11 03:06

peskal


People also ask

What is line wrap in JTextArea?

To wrap the lines of JTextArea we need to call the setLineWrap(boolean wrap) method and pass a true boolean value as the parameter. The setWrapStyleWord(boolean word) method wrap the lines at word boundaries when we set it to true .

Can you use basic editing operations when entering text in JTextField or JTextArea?

By default, JTextField and JTextArea are editable; you can type and edit in both text components. They can be changed to output-only areas by calling setEditable(false) .

What is the default found for JTextArea?

Constructs a new TextArea. A default model is set, the initial string is null, and rows/columns are set to 0.


1 Answers

You can use LineBreakMeasurer Class.

The LineBreakMeasurer class allows styled text to be broken into lines (or segments) that fit within a particular visual advance. This is useful for clients who wish to display a paragraph of text that fits within a specific width, called the wrapping width.LineBreakMeasurer implements the most commonly used line-breaking policy: Every word that fits within the wrapping width is placed on the line. If the first word does not fit, then all of the characters that fit within the wrapping width are placed on the line. At least one character is placed on each line.

like image 192
Saurabh Gokhale Avatar answered Nov 04 '22 23:11

Saurabh Gokhale