在我的应用程序中,我使用嵌入在 JScrollPane 中的 JTextPane 来显示使用 HTML 标记格式化的文本。起初我使用 JTextArea,但后来切换到 JTextPane 以便能够使用 HTML 和颜色。然后我需要 JTextPane 来支持基于字母的换行,而不仅仅是默认的空格换行。换句话说,如果内容太长,它应该被包裹起来,JScrollPane 的水平滚动条不应该是可见的。
因此,我在这个答案中找到了一个完美的解决方案:https ://stackoverflow.com/a/6330483/3871673 。它为 JTextPane 使用自定义 HTMLEditorKit。
但是使用这个解决方案,JTextPane 会忽略任何带有 HTML 标记的换行符<br>
。我不得不承认我真的不知道解决方案中的代码是如何工作的。如果有人能找到如何让 HTML 新行<br>
标签与这个解决方案一起工作,那就太好了。
这是一个最小、完整且可验证的示例:
import javax.swing.*;
import javax.swing.text.Element;
import javax.swing.text.ParagraphView;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.InlineView;
import java.awt.*;
public class JTextPaneTest extends JFrame {
public static void main(String[] args) {
new JTextPaneTest();
}
public JTextPaneTest(){
setLayout(new BorderLayout());
JTextPane textPane = new JTextPane();
textPane.setContentType("text/html");
textPane.setEditorKit(new HTMLEditorKitWrapSupport()); // makes JTextPane ignore <br> tag
// example 1 (JTextPane ignores <br> tag when using the custom HTMLEditorKit)
textPane.setText("<html><body style='font-size:22pt'> <p>Line 1 <br> Line 2</p> </body></html>");
// example 2 (the text should be wrapped and the JScrollPane's horizontal bar should not be visible)
//textPane.setText("<html><body style='font-size:25pt'> <p>LONGWORDWITHOUTSPACES_LONGWORDWITHOUTSPACES_LONGWORDWITHOUTSPACES_LONGWORDWITHOUTSPACES_LONGWORDWITHOUTSPACES_</p> </body></html>");
JScrollPane scrollPane = new JScrollPane(textPane);
add(scrollPane, BorderLayout.CENTER);
setSize(new Dimension(500, 500));
setVisible(true);
}
class HTMLEditorKitWrapSupport extends HTMLEditorKit {
@Override
public ViewFactory getViewFactory() {
return new HTMLEditorKit.HTMLFactory() {
public View create(Element element) {
View view = super.create(element);
if (view instanceof InlineView) {
return new InlineView(element) {
@Override
public int getBreakWeight(int axis, float pos, float len) {
return GoodBreakWeight;
}
@Override
public View breakView(int axis, int p0, float pos, float len) {
if (axis == View.X_AXIS) {
checkPainter();
int p1 = getGlyphPainter().getBoundedPosition(this, p0, pos, len);
if (p0 == getStartOffset() && p1 == getEndOffset()) {
return this;
}
return createFragment(p0, p1);
}
return this;
}
};
} else if (view instanceof ParagraphView) {
return new ParagraphView(element) {
protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements sizeRequirements) {
if (sizeRequirements == null) {
sizeRequirements = new SizeRequirements();
}
float pref = layoutPool.getPreferredSpan(axis);
float min = layoutPool.getMinimumSpan(axis);
// Don't include insets, Box.getXXXSpan will include them.
sizeRequirements.minimum = (int) min;
sizeRequirements.preferred = Math.max(sizeRequirements.minimum, (int) pref);
sizeRequirements.maximum = Integer.MAX_VALUE;
sizeRequirements.alignment = 0.5f;
return sizeRequirements;
}
};
}
return view;
}
};
}
}
}