2012-06-12 11 views
14

Ich habe zwei verschiedene Editoren mit JTextPane mit seltsamen Fehlern in Java 7, die nicht mit den früheren JVM-Versionen aufgetreten sind. Es passiert mit langen Zeilen, die formatierten Text oder Komponenten enthalten.Seltsame Textumbruch mit formatierten Text in JTextPane mit Java 7

Hier ist ein Beispiel, das diesen Fehler demonstriert. In diesem Beispiel wird der Standardstil für den gesamten Text jedes Mal angewendet, wenn ein Zeichen eingefügt wird. Ich habe es mit dem JDK 1.7.0_04 getestet.

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(); 
    } 
} 

Meine Frage ist: Ist etwas in meinem Code falsch, oder ist es tatsächlich ein neuer Fehler in Java 7 eingeführt? Und wenn es sich um einen neuen JVM-Fehler handelt, gibt es einen Workaround?

Es könnte verwandt sein mit question 8666727, aber das Problem liegt hier in der falschen Verpackung und nicht das Aussehen einer Bildlaufleiste.

+0

Sie recht, sah ich, dass und einen Unterschied zu vergleichen kann, keine Ahnung über Änderungen in Java7 (mein Upgrade in Java 1.7.0_15 und mehr verlassen) – mKorbel

+0

Es wird wahrscheinlich nicht helfen, aber rufen 'Pack() 'unmittelbar vor' setSize (200, 200); '(Ich habe Java 7 nicht verfügbar, um es zu testen). –

+0

@Andrew Thompson Ich habe alle guten Swing-Rulles hinzugefügt, ohne irgendwelche Änderungen, bitte sehen Sie in meinem Post hier – mKorbel

Antwort

16

für Futures-Leser, bug is still present in JDK 1.7.0_04.,

Vergleich Java7 und mit stabiler Java6,

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

enter image description here < ------ Java7 vs. Java6 --->enter image description here

enter image description here < ------ Java7 vs. Java6 --->

enter image description here < ------ Java7 vs. Java6 --->enter image description here

von Code

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 vs. Java6 ---> 'Das geht die extra Meile. +1 –

+0

@Andrew Thompson hehehe dies ist der gleiche Modus, weil ich nicht gut in HTML bin, und nicht in der Lage, Lücke zwischen zwei Bildern – mKorbel

+0

Ich hoffe, als besser, bitte sehen Sie mein Update ... :-) – mKorbel

7

diese Sucht. Der Grund ist das breakSpot-Caching. Sieht aus wie LabelView speichert sie und nicht Offsets auf früheren Text bearbeiten neu berechnen. Wenn ich sie manuell zurücksetze, passiert der Fehler nicht.

Eine Abhilfe (sehr schmutzig, weil die privaten breakSpots Felder) folgen

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(); 
     } 
    } 

} 

Weniger Hack ohne Reflexion. Basierend auf dem üblichen Zurücksetzen von breakSpots beim Modellwechsel.

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); 
     } 
    } 
} 

UPDATE: Dieser behebt auch TextSamplerDemo. Ich setze alle Punkte für alle Etikettenansichten zurück.

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/provisorische Lösung von (@StanislavL) für Java7 & JTextArea] (http://stackoverflow.com/a/14218102/714968) – mKorbel

+0

Vielen Dank für diese Problemumgehung. Es funktioniert gut für den Test. Es verbessert auch das Verhalten in einem Editor, der JComponent und Stile in der Textfläche verwendet, obwohl es immer noch seltsame Dinge gibt (wie zum Beispiel Zeilenumbrüche, die manchmal ohne Grund passieren). Leider funktioniert diese Problemumgehung bei Java-Applets überhaupt nicht. – Damien

+0

@Damien bitte SSCCE für die verbleibenden Probleme und ich werde versuchen, herauszufinden, was los ist. – StanislavL