我使用其他优秀的答案来设计一个方法,使用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);
}
}
答案 0 :(得分:3)
我通过在AttributedString实例化后添加以下行来修复字体大小问题:
AttributedString text = new AttributedString(textPane.getText());
text.addAttribute(TextAttribute.FONT, textPane.getFont());
我猜Attributed String需要定义的字体,虽然我认为它是由FontRenderContext处理的,但至少对我而言,它不是。
答案 1 :(得分:1)
我不确定你的getTextDimension()
有什么问题,但更可靠的方法是让文本组件进行计算。 How can I measure/calculate the size a Document
needs to render itself?
附录:这是@ camickr的TextPanePerfectSize
的变体。
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);
}
}