Как подсчитать количество строк в JTextArea, в том числе вызванных переносом? - PullRequest
10 голосов
/ 16 июня 2011

У меня есть 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, но я хочу компенсировать перенос слов и распечатать, сколько строк фактически используется.

РЕДАКТИРОВАТЬ: я включил решение проблемыв коде ниже.Статический метод 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 ]

5 голосов
/ 16 июня 2011

Вы можете использовать LineBreakMeasurer Класс.

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

1 голос
/ 03 июня 2015

Ваш 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, идет к Jenny

1 голос
/ 07 ноября 2013

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

РЕДАКТИРОВАТЬ: Решение Необходимо установить шрифт для текстовой области и для приписанной строки.Теперь счетчик строк правильный.Решение в коде.

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