在JTextPane中包装长单词(Java 7)

在最多6个Java的所有版本中,放置在JScrollPane中的JTextPane的默认行为是:如果可能,在字边界处换行。 如果没有,那么无论如何都要包裹它们。

在JDK 7中,默认行为似乎是:如果可能,在字边界处换行。 如果没有,只需展开JTextPane的宽度(永远不要换长字)。

很容易重现这个,这是一个SSCCE:

public class WrappingTest extends JFrame { public static void main ( String[] args ) { new WrappingTest(); } public WrappingTest () { setSize(200,200); getContentPane().setLayout(new BorderLayout()); JTextPane jtp = new JTextPane(); JScrollPane jsp = new JScrollPane(jtp); jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); getContentPane().add(jsp,BorderLayout.CENTER); setVisible(true); } } 

只需在JDK 6和JDK 7中运行它,写一些小字,然后写一个长字,你就会看到差异。

我的问题很简单…… JDK 7中的新默认行为完全混淆了我的程序(他们应该更加小心Oracle更改这种默认值……它们似乎不重要但是当你使用JTextPane显示时通常包含非常长的字母串的数据,它们并不是那么不重要 – 实际上我要提交错误报告,但是我想在/如果它们不解决它的情况下有一个解决方法)。 有什么方法可以回到以前的行为?

请注意,我已经检查了相关问题的答案。 如何在JTextPane中实现自动换行,以及如何使其包含没有空格的字符串? 但它没有回答这个问题 – 它提供了一种使JTextPane包装完全不考虑空白的方法,但对我来说,如果可能的话,所需的行为是在空白处分割行,如果不可能则在其他地方(如以前的Java中那样)版本)。

对我来说,修复工作(在1.7.0_09下测试)

 import javax.swing.*; import javax.swing.text.*; import java.awt.*; public class WrapTestApp extends JFrame { public static void main ( String[] args ) { new WrapTestApp(); } public WrapTestApp () { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(200,200); getContentPane().setLayout(new BorderLayout()); JTextPane jtp = new JTextPane(); jtp.setEditorKit(new WrapEditorKit()); JScrollPane jsp = new JScrollPane(jtp); jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); getContentPane().add(jsp, BorderLayout.CENTER); jtp.setText("ExampleOfTheWrapLongWordWithoutSpaces"); setVisible(true); } class WrapEditorKit extends StyledEditorKit { ViewFactory defaultFactory=new WrapColumnFactory(); public ViewFactory getViewFactory() { return defaultFactory; } } class WrapColumnFactory implements ViewFactory { public View create(Element elem) { String kind = elem.getName(); if (kind != null) { if (kind.equals(AbstractDocument.ContentElementName)) { return new WrapLabelView(elem); } else if (kind.equals(AbstractDocument.ParagraphElementName)) { return new ParagraphView(elem); } else if (kind.equals(AbstractDocument.SectionElementName)) { return new BoxView(elem, View.Y_AXIS); } else if (kind.equals(StyleConstants.ComponentElementName)) { return new ComponentView(elem); } else if (kind.equals(StyleConstants.IconElementName)) { return new IconView(elem); } } // default to text display return new LabelView(elem); } } class WrapLabelView extends LabelView { public WrapLabelView(Element elem) { super(elem); } public float getMinimumSpan(int axis) { switch (axis) { case View.X_AXIS: return 0; case View.Y_AXIS: return super.getMinimumSpan(axis); default: throw new IllegalArgumentException("Invalid axis: " + axis); } } } } 

来自@ dk89的好收获,但唉,给定的解决方法不起作用:JDK 7显然仍然没有提供等待在JTextComponent上设置自定义BreakIterator; 甚至没有GlyphView,其中BreakIterator的生成是私有的。 如果我们通过char插入字符串char,它仍然不起作用:我想连续运行具有相同样式(AttributeSet)的文本将被折叠在一起。

我花了两天的时间尝试做一个自定义的EditorKit,正如其他地方所建议的那样,但它不能正常工作(至少使用JDK 1.7.0_4)作为文本。

我尝试了如何自动换行存储在JTextPanes中的文本的解决方案,这些文本是JList中的单元格和http://www.experts-exchange.com/Programming/Languages/Java/Q_20393892.html中的变体。

但我发现当JTextPane小于句子中最长的单词时,不再调用breakView。 因此,当只有一个(长)字时,它根本不起作用。 这是我们的情况,因为我们在相当小的空间中显示用户提供的类似标识符的字符串,通常没有空格。

我终于找到了一个简单的解决方案,它源自bug报告中的建议:实际上,通过char插入字符串char,但是替换样式! 因此,我们拥有与chars一样多的段,并且字符串包含在char bounds中。 直到下一个“错误修复”?

代码片段:

 private JTextPane tp; private SimpleAttributeSet sas = new SimpleAttributeSet(); tp= new JTextPane(); sas.addAttribute( "A", "C" ); // Arbitrary attribute names and value, not used actually // Set the global attributes (italics, etc.) tp.setParagraphAttributes(styleParagraphAttributes, true); Document doc = tp.getDocument(); try { doc.remove(0, doc.getLength()); // Clear for (int i = 0; i < textToDisplay.length(); i++) { doc.insertString(doc.getLength(), textToDisplay.substring(i, i+1), // Change attribute every other char i % 2 == 0 ? null : sas); } } catch (BadLocationException ble) { log.warn("Cannot happen...", ble); } 

正如bug中所述,他们应该提供一种简单的方法(可能是一些属性,或者一些可注入的东西)来恢复旧的行为。

嗨,我遇到了同样的问题,但找到了解决办法:

只需创建一个扩展的JTextPane类,例如

  MyWrapJTextPane extends JTextPane 

并覆盖以下方法 – 它的工作原理;-)

  public boolean getScrollableTracksViewportWidth() { return true; }