【问题标题】:How to count the number of lines in a JTextArea, including those caused by wrapping?如何计算 JTextArea 中的行数,包括由换行引起的行数?
【发布时间】:2011-09-16 01:02:45
【问题描述】:

我有一个 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();                                                                   
      }                                                                                       
    });                                                                                       
  }                                                                                           
}                                                                                             

【问题讨论】:

  • 在这个解决方案中,如果文本为空会抛出错误:java.lang.IllegalArgumentException: Text must contain at least one character我建议用try catch包围new LineBreakMeasurer(charIt, frc)
  • 另外,这个方法不考虑\n作为换行符。

标签: java textarea awt jtextarea


【解决方案1】:

您可以使用LineBreakMeasurer 类。

LineBreakMeasurer 类允许 样式化的文本被分成几行 (或段)适合 特别的视觉进步。这是 对希望展示的客户有用 一段文本,适合 特定宽度,称为环绕 width.LineBreakMeasurer 实现了最常用的换行策略:Every 适合包装的单词 宽度放在线上。如果 第一个词不合适,然后全部 适合的字符 换行宽度都放在线上。 至少一个字符被放置在 每一行。

【讨论】:

  • 感觉应该有更简单的方法来做到这一点。不过,您的建议使我走上了正确的道路,并且我已将解决方案添加到问题中。
【解决方案2】:

在我看来,这不可能是全部答案。 如果更改字体并扩展文本,则行数会变得不正确。

编辑:解决方案 您必须为 textarea 和属性字符串设置字体。现在行数是正确的。代码中的解决方案。

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

【讨论】:

    【解决方案3】:

    您的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;
    }
    

    All credit for recognizing that the AttributedString needed to have its font set to the font of the JTextArea goes to Jenny

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 2011-08-24
      • 1970-01-01
      相关资源
      最近更新 更多