2012-06-12 1 views
14

У меня есть два разных редактора, использующих JTextPane со странными ошибками в Java 7, которые не встречались с предыдущими версиями JVM. Это происходит с длинными строками, содержащими стилизованный текст или компоненты.Странная перенос текста со стилизованным текстом в JTextPane с Java 7

Вот пример, демонстрирующий эту ошибку. В этом примере стиль по умолчанию применяется для всего текста каждый раз, когда вводится символ. Я тестировал его с помощью JDK 1.7.0_04.

import java.awt.BorderLayout; 
import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.text.*; 

public class BugWrapJava7 extends JFrame { 

    JTextPane jtp; 
    StyledDocument doc; 

    public BugWrapJava7() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setLayout(new BorderLayout()); 
     jtp = new JTextPane(); 
     add(jtp, BorderLayout.CENTER); 
     jtp.setText("\ntype some text in the above empty line and check the wrapping behavior"); 
     doc = jtp.getStyledDocument(); 
     doc.addDocumentListener(new DocumentListener() { 
      public void insertUpdate(DocumentEvent e) { 
       insert(); 
      } 
      public void removeUpdate(DocumentEvent e) { 
      } 
      public void changedUpdate(DocumentEvent e) { 
      } 
     }); 
     setSize(200, 200); 
     setVisible(true); 
    } 
    public void insert() { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE); 
       doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false); 
      } 
     }); 
    } 
    public static void main(String[] args) { 
     new BugWrapJava7(); 
    } 
} 

Мой вопрос: есть ли что-то не так в моем коде, или это действительно новая ошибка введена в Java 7? И если это новая ошибка JVM, есть ли обходной путь?

Это может быть связано с question 8666727, но проблема здесь заключается в неправильной упаковке, а не в виде полосы прокрутки.

+0

вы правы, я увидел, что и может сравнивать разницу +1, ни малейшего представления об изменениях в Java7 (не оставляя мое обновление в Java 1.7.0_15 и более) – mKorbel

+0

Это, вероятно, не поможет, но назвать 'пакет() 'непосредственно перед' setSize (200, 200); '(у меня нет Java 7 для тестирования). –

+0

@Andrew Thompson Я добавил все хорошие правила Swing, без каких-либо изменений, см. В моем сообщении здесь – mKorbel

ответ

16

для фьючерсных читателей, bug is still present in JDK 1.7.0_04.,

сравнения Java7 и со стабильным Java6,

enter image description here < ------ Java7 В.С. Java6 --->enter image description here

enter image description here < ------ Java7 v.s. Java6 --->enter image description here

enter image description here < ------ Java7 v.s. Java6 --->enter image description here

enter image description here < ------ Java7 v.s. Java6 --->enter image description here

из кода

import java.awt.Dimension; 
import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.text.*; 

public class BugWrapJava7 { 

    private JFrame frame = new JFrame(); 
    private JTextPane jtp; 
    private StyledDocument doc; 

    public BugWrapJava7() { 
     jtp = new JTextPane(); 
     jtp.setText("\ntype some text in the above empty line and check the wrapping behavior"); 
     doc = jtp.getStyledDocument(); 
     doc.addDocumentListener(new DocumentListener() { 

      public void insertUpdate(DocumentEvent e) { 
       insert(); 
      } 

      public void removeUpdate(DocumentEvent e) { 
       insert(); 
      } 

      public void changedUpdate(DocumentEvent e) { 
       insert(); 
      } 

      public void insert() { 
       SwingUtilities.invokeLater(new Runnable() { 

        public void run() { 
         Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE); 
         doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false); 
        } 
       }); 
      } 
     }); 
     JScrollPane scroll = new JScrollPane(jtp); 
     scroll.setPreferredSize(new Dimension(200, 200)); 
     frame.add(scroll); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       BugWrapJava7 bugWrapJava7 = new BugWrapJava7(); 
      } 
     }); 
    } 
} 
+0

'<------ Java7 v.s. Java6 ---> 'Это идет лишняя миля. +1 –

+0

@ Andrew Thompson hehehe это тот же режим, потому что я плохо разбираюсь в Html и не могу создать разрыв между двумя изображениями – mKorbel

+0

Надеюсь, что лучше, пожалуйста, см. Мое обновление ... :-) – mKorbel

7

Исследовал это. Причина - кэширование breakSpots. Похож на то, что LabelView хранит их и не пересчитывает смещения по тексту текста. Если я сброшу их вручную, ошибка не произойдет.

Обходной (очень грязная из частных полей breakSpots) следит за

import java.awt.Dimension; 
import java.lang.reflect.Field; 
import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.text.*; 

public class BugWrapJava7 { 

    private JFrame frame = new JFrame(); 
    private JTextPane jtp; 
    private StyledDocument doc; 

    public BugWrapJava7() { 
     jtp = new JTextPane(); 
     jtp.setEditorKit(new MyStyledEditorKit()); 
     jtp.setText("\ntype some text in the above empty line and check the wrapping behavior"); 
     doc = jtp.getStyledDocument(); 
     doc.addDocumentListener(new DocumentListener() { 

      public void insertUpdate(DocumentEvent e) { 
       insert(); 
      } 

      public void removeUpdate(DocumentEvent e) { 
       insert(); 
      } 

      public void changedUpdate(DocumentEvent e) { 
       insert(); 
      } 

      public void insert() { 
       SwingUtilities.invokeLater(new Runnable() { 

        public void run() { 
         Style defaultStyle = jtp.getStyle(StyleContext.DEFAULT_STYLE); 
         doc.setCharacterAttributes(0, doc.getLength(), defaultStyle, false); 
        } 
       }); 
      } 
     }); 
     JScrollPane scroll = new JScrollPane(jtp); 
     scroll.setPreferredSize(new Dimension(200, 200)); 
     frame.add(scroll); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       BugWrapJava7 bugWrapJava7 = new BugWrapJava7(); 
      } 
     }); 
    } 
} 

class MyStyledEditorKit extends StyledEditorKit { 
    private MyFactory factory; 

    public ViewFactory getViewFactory() { 
     if (factory == null) { 
      factory = new MyFactory(); 
     } 
     return factory; 
    } 
} 

class MyFactory implements ViewFactory { 
    public View create(Element elem) { 
     String kind = elem.getName(); 
     if (kind != null) { 
      if (kind.equals(AbstractDocument.ContentElementName)) { 
       return new MyLabelView(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 MyLabelView extends LabelView { 
    public MyLabelView(Element elem) { 
     super(elem); 
    } 
    public View breakView(int axis, int p0, float pos, float len) { 
     if (axis == View.X_AXIS) { 
      resetBreakSpots(); 
     } 
     return super.breakView(axis, p0, pos, len); 
    } 

    private void resetBreakSpots() { 
     try { 
      // HACK the breakSpots private fields 
      Field f=GlyphView.class.getDeclaredField("breakSpots"); 
      f.setAccessible(true); 
      f.set(this, null); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

Меньше хак без отражения. На основе обычного сброса breakSpots при изменении модели.

class MyLabelView extends LabelView { 

    boolean isResetBreakSpots=false; 

    public MyLabelView(Element elem) { 
     super(elem); 
    } 
    public View breakView(int axis, int p0, float pos, float len) { 
     if (axis == View.X_AXIS) { 
      resetBreakSpots(); 
     } 
     return super.breakView(axis, p0, pos, len); 
    } 

    private void resetBreakSpots() { 
     isResetBreakSpots=true; 
     removeUpdate(null, null, null); 
     isResetBreakSpots=false; 

//  try { 
//   Field f=GlyphView.class.getDeclaredField("breakSpots"); 
//   f.setAccessible(true); 
//   f.set(this, null); 
//  } catch (Exception e) { 
//   e.printStackTrace(); 
//  } 
    } 

    public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { 
     super.removeUpdate(e, a, f); 
    } 

    public void preferenceChanged(View child, boolean width, boolean height) { 
     if (!isResetBreakSpots) { 
      super.preferenceChanged(child, width, height); 
     } 
    } 
} 

ОБНОВЛЕНИЕ: Этот исправляет также TextSamplerDemo. Я сбросил все точки для всех видов ярлыков.

class MyStyledEditorKit extends StyledEditorKit { 
    private MyFactory factory; 

    public ViewFactory getViewFactory() { 
     if (factory == null) { 
      factory = new MyFactory(); 
     } 
     return factory; 
    } 
} 

class MyFactory implements ViewFactory { 
    public View create(Element elem) { 
     String kind = elem.getName(); 
     if (kind != null) { 
      if (kind.equals(AbstractDocument.ContentElementName)) { 
       return new MyLabelView(elem); 
      } else if (kind.equals(AbstractDocument.ParagraphElementName)) { 
       return new MyParagraphView(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 MyParagraphView extends ParagraphView { 

    public MyParagraphView(Element elem) { 
     super(elem); 
    } 
public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { 
    super.removeUpdate(e, a, f); 
    resetBreakSpots(); 
} 
public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) { 
    super.insertUpdate(e, a, f); 
    resetBreakSpots(); 
} 

private void resetBreakSpots() { 
    for (int i=0; i<layoutPool.getViewCount(); i++) { 
     View v=layoutPool.getView(i); 
     if (v instanceof MyLabelView) { 
      ((MyLabelView)v).resetBreakSpots(); 
     } 
    } 
} 

} 

class MyLabelView extends LabelView { 

    boolean isResetBreakSpots=false; 

    public MyLabelView(Element elem) { 
     super(elem); 
    } 
    public View breakView(int axis, int p0, float pos, float len) { 
     if (axis == View.X_AXIS) { 
      resetBreakSpots(); 
     } 
     return super.breakView(axis, p0, pos, len); 
    } 

    public void resetBreakSpots() { 
     isResetBreakSpots=true; 
     removeUpdate(null, null, null); 
     isResetBreakSpots=false; 
    } 

    public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) { 
     super.removeUpdate(e, a, f); 
    } 

    public void preferenceChanged(View child, boolean width, boolean height) { 
     if (!isResetBreakSpots) { 
      super.preferenceChanged(child, width, height); 
     } 
    } 
} 
+0

[similair hack/workaround by (@StanislavL) для Java7 & JTextArea] (http://stackoverflow.com/a/14218102/714968) – mKorbel

+0

Благодарим вас за это обходное решение. Это хорошо работает для теста. Он также улучшает поведение в редакторе с использованием JComponent и стилей в текстовой области, хотя все еще происходят странные вещи (например, разрывы строк происходят иногда без причины). К сожалению, это обходное решение вообще не работает с Java-апплетами. – Damien

+0

@Damien, пожалуйста, предоставьте SSCCE для оставшихся вопросов, и я попытаюсь выяснить, что не так. – StanislavL

 Смежные вопросы

  • Нет связанных вопросов^_^