2013-03-29 113 views
3

我已经使用其他优秀答案来设计一种方法,该方法使用LineBreakMeasurer返回JTextPane(考虑其内容和宽度)的正确尺寸。使用LineBreakMeasurer计算线条并更改字体大小

问题是,当我尝试不同的字体大小时,它有点小,我找不出原因。它适用于说Arial 12,但不适用于Arial 8或Arial 16,因为然后nextLayout计算长度错误。谁能告诉我为什么?

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Font; 
import java.awt.FontMetrics; 
import java.awt.font.FontRenderContext; 
import java.awt.font.LineBreakMeasurer; 
import java.awt.font.TextLayout; 
import java.text.AttributedCharacterIterator; 
import java.text.AttributedString; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextPane; 
import javax.swing.border.LineBorder; 


public class Example1 { 

static JFrame frame = new JFrame(); 
static JPanel bigPanel = new JPanel(); 
static JTextPane textPane[] = new JTextPane[10]; 



public static void main(String[] args) { 

    frame.setLayout(new FlowLayout()); 
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 

    for(int i=0 ; i<10 ; i++) { 
     textPane[i] = new JTextPane(); 
     textPane[i].setFont(new Font("Arial", 0, 12+i)); 
     textPane[i].setText("This is 10 characters of " + ((Integer)(10+i)).toString() + " points : a b c d e f g h i j"); 
     textPane[i].setPreferredSize(getTextDimension(textPane[i], 100)); 
     textPane[i].setBorder(new LineBorder(Color.BLACK)); 
     frame.add(textPane[i]); 
    } 

    frame.setSize(500, 500); 
    frame.setVisible(true); 

} 

static private Dimension getTextDimension(JTextPane textPane, float width) { 

    FontMetrics fm = textPane.getFontMetrics(textPane.getFont()); 
    int fontHeight = fm.getHeight()+ fm.getDescent(); 
    //int fontHeight = fm.getHeight(); 

    AttributedString text = new AttributedString(textPane.getText()); 
    FontRenderContext frc = textPane.getFontMetrics(textPane.getFont()).getFontRenderContext(); 
    AttributedCharacterIterator styledText = text.getIterator(); 
    LineBreakMeasurer measurer = new LineBreakMeasurer(styledText, frc); 

    float wrappingWidth = width - textPane.getInsets().left - textPane.getInsets().right; 

    int lines = 0; 
    while (measurer.getPosition() < styledText.getEndIndex()) { 
     TextLayout layout = measurer.nextLayout(wrappingWidth); 
     lines++; 
    } 

    return new Dimension((int)Math.round(width), lines * fontHeight); 
} 

}

+3

请引用相关答案并编辑您的问题以包含展示您描述的问题的[sscce](http://sscce.org/)。 – trashgod

+0

我已经编辑了示例到sscce,这表明当字体大小增加时(即使包含字体上升和下降),计算稍微偏离 – whetstone

+0

[sscce] +1(http://sscce.org/)。还要考虑'WindowAdapter'或'setDefaultCloseOperation()'。 – trashgod

回答

3

我由AttributedString的实例后添加以下行固定的字体大小问题:

AttributedString text = new AttributedString(textPane.getText()); 
text.addAttribute(TextAttribute.FONT, textPane.getFont()); 

我猜的属性串需要定义字体,但我认为它由FontRenderContext处理,但至少对我来说不是这样。

+0

辉煌,那就是诀窍!我几乎放弃了这个,谢谢。 – whetstone

1

我不知道这有什么错你getTextDimension(),而是一个更可靠的方法是要求文本组件做计算。 How can I measure/calculate the size aDocumentneeds to render itself?

附录:这是@ camickr的TextPanePerfectSize的变体。

image

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextPane; 
import javax.swing.border.LineBorder; 
import javax.swing.text.BadLocationException; 
import javax.swing.text.SimpleAttributeSet; 
import javax.swing.text.StyleConstants; 
import javax.swing.text.StyledDocument; 

/** 
* @see https://stackoverflow.com/a/15983197/230513 
* @see https://stackoverflow.com/a/3318949/230513 
*/ 
public class Test { 

    private static final int SIZE = 16; 
    private static int size = SIZE; 
    private static JTextPane textPane[] = new JTextPane[SIZE]; 

    public static void main(String[] args) { 
     final JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JPanel buttonPanel = new JPanel(); 
     buttonPanel.add(new JButton(new AbstractAction("Update") { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       for (JTextPane jtp : textPane) { 
        StyledDocument doc = (StyledDocument) jtp.getDocument(); 
        SimpleAttributeSet style = new SimpleAttributeSet(); 
        StyleConstants.setFontFamily(style, "Serif"); 
        StyleConstants.setFontSize(style, size++); 
        try { 
         doc.insertString(doc.getLength(), " one two three", style); 
         Dimension d = jtp.getPreferredSize(); 
         Rectangle r = jtp.modelToView(jtp.getDocument().getLength()); 
         d.height = r.y + r.height; 
         jtp.setPreferredSize(d); 
        } catch (BadLocationException ex) { 
         ex.printStackTrace(System.err); 
        } 
        frame.pack(); 
       } 
      } 
     })); 
     frame.add(buttonPanel, BorderLayout.NORTH); 
     JPanel textPanel = new JPanel(new GridLayout(0, 4)); 
     for (int i = 0; i < textPane.length; i++) { 
      textPane[i] = new JTextPane(); 
      textPane[i].setText("Text pane number " + String.valueOf(i + 1)); 
      textPane[i].setBorder(new LineBorder(Color.BLACK)); 
      textPanel.add(textPane[i]); 
     } 
     frame.add(new JScrollPane(textPanel)); 
     frame.pack(); 
     frame.setVisible(true); 
    } 
} 
+0

注意:['setPreferredSize()'](http://stackoverflow.com/q/7229226/230513)仅用于演示。 – trashgod

+0

谢谢,但我不认为这解决了我的问题。什么'getTextDimension()'试图做的是计算具有给定宽度的文本的高度,所以基本上我的问题是我想使用'setPrefferedSize()',但只设置宽度而不是高度,让文本窗格数字表示自己 – whetstone

+0

该示例依赖于初始宽度;该窗格提供了新的高度。 – trashgod