2011-06-16 100 views
10

我有一個JTextArea,我爲其設置了自動換行和換行樣式字爲true。我想將JTextArea「打包」到指定寬度的最小可能高度。如何計算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();                 
     }                      
    });                      
    }                       
}                        
+0

參見[如何計算的行...在JTextArea的數量?(http://stackoverflow.com/questions/5979795)。 – trashgod 2011-06-16 03:46:41

+0

在這個解決方案中,如果文本是空的,會拋出錯誤:'java.lang.IllegalArgumentException:文本必須至少包含一個字符'我建議用_try捕捉新'LineBreakMeasurer(charIt,frc)' – CarlosRos 2016-02-29 10:39:26

+0

另外,此方法不會將'\ n'字符視爲新行。 – CarlosRos 2016-02-29 10:52:10

回答

5

您可以使用LineBreakMeasurer類。

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.

+0

感覺應該有一個更簡單的方法來做到這一點。儘管你的建議讓我走上了正確的軌道,並且我已經爲該問題添加了解決方案。 – peskal 2011-06-16 04:55:57

1

在我看來,這不可能是所有的答案。 如果更改字體並擴展文本,則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();                 
     }                      
    });                      
    }                       
} 
1

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