2012-06-12 17 views
14

Ho due diversi editor che usano JTextPane con strani bug in Java 7 che non si sono verificati con le precedenti versioni di JVM. Succede con le linee lunghe contenenti testo o componenti in stile.Strange text wrapping con testo in stile in JTextPane con Java 7

Ecco un esempio che illustra questo errore. In questo esempio, lo stile predefinito viene applicato a tutto il testo ogni volta che viene inserito un carattere. L'ho provato con il 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(); 
    } 
} 

La mia domanda è: c'è qualcosa di sbagliato nel mio codice, o è davvero un nuovo bug introdotto in Java 7? E se si tratta di un nuovo bug JVM, c'è una soluzione?

Potrebbe essere correlato a question 8666727, ma il problema si trova nell'involucro errato piuttosto che nell'aspetto di una barra di scorrimento.

+0

hai ragione, ho visto che il confronto e possono differenza +1, nessuna idea dei cambiamenti nella Java7 (lasciando il mio aggiornamento in Java 1.7.0_15 e più) – mKorbel

+0

Probabilmente non aiuterà, ma chiamano 'pacchetto() 'immediatamente prima di' setSize (200, 200); '(Non ho Java 7 disponibile per testarlo). –

+0

@Andrew Thompson Ho aggiunto tutti i buoni comandi Swing, senza alcuna modifica, per favore vedi nel mio post qui – mKorbel

risposta

16

per i lettori dei futures, bug is still present in JDK 1.7.0_04.,

confrontando Java7 e con java6 stabile,

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

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

dal codice

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 ---> 'Questo sta facendo il miglio supplementare. +1 –

+0

@Andrew Thompson hehehe questa è la stessa modalità, perché non sono bravo in Html, e non sono in grado di creare spazi tra due immagini – mKorbel

+0

Spero che meglio, per favore vedi il mio aggiornamento ... :-) – mKorbel

7

indagato su questo. Il motivo è il caching di breakSpots. Sembra che lo LabelView li memorizzi e non ricalcoli gli offset sulla modifica del testo precedente. Se li ripristino manualmente il bug non si verifica.

Una soluzione (molto sporco a causa di campi breakSpots private) sta seguendo

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

} 

Meno mod senza la riflessione. Basato sul solito reset di breakSpot sul cambio di modello.

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

AGGIORNAMENTO: questo risolve anche TextSamplerDemo. Ho ripristinato tutti i punti per tutte le visualizzazioni di etichette.

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 di (@StanislavL) per Java7 e JTextArea] (http://stackoverflow.com/a/14218102/714968) – mKorbel

+0

Grazie per questa soluzione. Funziona bene per il test. Migliora anche il comportamento in un editor usando JComponent e gli stili nel testo, anche se ci sono ancora cose strane che accadono (come le interruzioni di riga a volte senza motivo). Sfortunatamente, questa soluzione alternativa non funziona affatto con le applet Java. – Damien

+0

@Damien, si prega di fornire SSCCE per i problemi rimanenti e cercherò di capire cosa c'è che non va. – StanislavL

Problemi correlati