Как подсчитать количество строк в JTextArea, в том числе вызванных накрутка?

у меня есть JTextArea, для которого я установил word-wrap и wrap-style-word в true. Я хочу "упаковать" JTextArea до минимально возможной высоты с заданной шириной.

для этого я планирую вычислить высоту шрифта с помощью...

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

...а затем умножьте это на количество строк, используемых в JTextArea. Проблема в том, что JTextArea.getLineCount () подсчитывает количество возвращаемых строк, игнорируя обернутые строки.

Как я подсчитайте количество строк, используемых в JTextArea, включая те, которые вызваны переносом слов?

вот некоторые демо-код, чтобы сделать игру с этой проблемой проще. У меня есть слушатель, который печатает количество строк при каждом изменении размера окна. На данный момент он всегда печатает 1, но я хочу компенсировать перенос слов и распечатать, сколько строк фактически используется.

EDIT: я включил решение проблемы в код ниже. Статика метод countLines дает решение.

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();                                                                   
      }                                                                                       
    });                                                                                       
  }                                                                                           
}                                                                                             

3 ответов


можно использовать LineBreakMeasurer класса.

класс LineBreakMeasurer позволяет стилизованный текст для разбиения на строки (или сегменты), которые вписываются в особое визуальное продвижение. Это полезно для клиентов, которые хотят отобразить абзац текста, который вписывается в специфическая ширина, вызванная оборачивать ширина.LineBreakMeasurer реализует наиболее часто используемую политику разрыва строк: каждый слово, которое вписывается в обертку ширина помещена на линия. Если сначала слово не подходит, потом все символы, которые вписываются в ширина обертывания размещается на линии. По крайней мере один символ помещается на каждая строка.


Мне кажется,что это не может быть ответом на все. При изменении шрифта и расширении текста linecount становится неправильным.

EDIT: решение вы должны установить шрифт для textarea и для приписываемой строки. Теперь linecount верен. Решение в коде.

package lineBreak;                                                                        

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

public class JTextAreaLineCountDemo extends JPanel {                                          
    JTextArea textArea;      

    static Font f = new Font("Helvetiva", Font.ITALIC, 50);                                                                         

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

    String inputStr = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmo, Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmo, Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmo, 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) {   
          **textArea.setFont(new Font("Arial", Font.BOLD, 22));**
        System.out.println("Line count: " + countLines(textArea));                         
      }                                                                                       
    });                                                                                       
  }                                                                                           

  private static int countLines(JTextArea textArea) {
    AttributedString text = new AttributedString(textArea.getText());
    text.addAttribute(TextAttribute.FONT, f);
    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();                                                                   
      }                                                                                       
    });                                                                                       
  }                                                                                           
}

код countLines метод почти работал для меня, но мне пришлось сделать несколько настроек, чтобы он работал правильно в моем случае. Я предполагаю, что вы используете шрифт по умолчанию и нет границы на JTextArea, но использование шрифта не по умолчанию или наличие границы (или оба, как в моем случае) вызовет ваш countLines метод для возврата неправильного номера. Ниже приведена моя обновленная версия, которая учитывает оба этих фактора (а также использует textArea.getWidth() вместо textArea.getSize().width).

private static int countLines(JTextArea textArea)
{
    AttributedString text = new AttributedString(textArea.getText());
    text.addAttribute(TextAttribute.FONT, textArea.getFont());
    FontRenderContext frc = textArea.getFontMetrics(textArea.getFont()).getFontRenderContext();
    AttributedCharacterIterator charIt = text.getIterator();
    LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(charIt, frc);
    Insets textAreaInsets = textArea.getInsets();
    float formatWidth = textArea.getWidth() - textAreaInsets.left - textAreaInsets.right;
    lineMeasurer.setPosition(charIt.getBeginIndex());

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

    return noLines;
}

все заслуги за признание того, что AttributedString нужно шрифт установить шрифт JTextArea идет к Дженни