2012-06-12 12 views
14

Mam dwa różne edytory używające JTextPane z dziwnymi błędami w Javie 7, które nie wystąpiły w poprzednich wersjach JVM. Dzieje się tak z długimi liniami zawierającymi stylizowany tekst lub komponenty.Dziwne zawijanie tekstu za pomocą stylizowanego tekstu w JTextPane z Javą 7

Oto przykład demonstrujący ten błąd. W tym przykładzie domyślny styl jest stosowany do całego tekstu za każdym razem, gdy wstawiany jest znak. Przetestowałem to z 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(); 
    } 
} 

Moje pytanie brzmi: czy coś jest nie tak w moim kodzie, czy jest to rzeczywiście nowy błąd wprowadzony w Javie 7? A jeśli jest to nowy błąd JVM, czy istnieje obejście?

Może to być związane z question 8666727, ale problem polega na niewłaściwym zawijaniu, a nie na pojawieniu się paska przewijania.

+0

masz rację, widziałem, że i można porównać różnicę +1, nie wiem o zmianach w Java7 (pozostawiając moje uaktualnienia Java 1.7.0_15 i więcej) – mKorbel

+0

Prawdopodobnie nie pomoże, ale zadzwonić 'paczka() 'bezpośrednio przed' setSize (200, 200); '(Nie mam dostępnej Java 7, aby ją przetestować). –

+0

@Andrew Thompson Dodałem wszystkie dobre huśtawki Swing, bez żadnych zmian, zobacz w moim poście tutaj – mKorbel

Odpowiedz

16

dla futures czytelników, bug is still present in JDK 1.7.0_04.,

porównując Java7 oraz stabilnych java6,

enter image description here < ------ Java7 V.S. Java6 --->enter image description here

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

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

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

z kodu

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.s. Java6 ---> 'To idzie dalej. +1 –

+0

@Andrew Thompson hehehe to jest ten sam tryb, ponieważ nie jestem dobry w HTML i nie jestem w stanie stworzyć luki między dwoma obrazami – mKorbel

+0

Mam nadzieję, że niż lepiej, zobacz moją aktualizację ... :-) – mKorbel

7

Badane to. Powodem jest buforowanie breakSpots. Wygląda na to, że przechowuje je LabelView i nie oblicza ponownie przesunięć w poprzedniej edycji tekstu. Jeśli zresetuję je ręcznie, błąd nie nastąpi.

Obejście (bardzo brudna z powodu prywatnych pól breakSpots) obserwuje

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

} 

Mniej siekać bez refleksji. Na podstawie zwykłego resetowania breakSpotów przy zmianie modelu.

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

AKTUALIZACJA: Ta poprawka również TextSamplerDemo. Zresetowałem wszystkie miejsca dla wszystkich widoków etykiet.

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/obejście przez (@StanislavL) dla Java7 i JTextArea] (http://stackoverflow.com/a/14218102/714968) – mKorbel

+0

Dziękujemy za obejście tego problemu. Działa dobrze na próbę. Poprawia również zachowanie w edytorze przy użyciu JComponent i stylów w tekście, chociaż wciąż zdarzają się dziwne rzeczy (takie jak przerwy w linii zdarzające się czasami bez powodu). Niestety, obejście to w ogóle nie działa z apletami Java. – Damien

+0

@Damien proszę podać SSCCE dla pozostałych problemów, a ja postaram się dowiedzieć, co jest nie tak. – StanislavL

Powiązane problemy