2011-12-29 7 views
16

We wszystkich wersjach Javy do 6 domyślnym zachowaniem JTextPane umieszczonym wewnątrz JScrollPane było: zawijanie linii na granicach słów, jeśli to możliwe. Jeśli nie, to i tak je zawiń.Zawijanie długich słów w JTextPane (Java 7)

W JDK 7 domyślnym zachowaniem wydaje się być: zawijanie wierszy do granic wyrazów, jeśli to możliwe. Jeśli nie, po prostu rozwiń szerokość JTextPane (nigdy nie zawijaj długich słów).

Jest to łatwe do odtworzenia tego, tutaj jest 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); 
    } 

} 

Wystarczy go uruchomić w JDK 6 oraz w JDK 7, napisać kilka małych słowa i napisać długiego słowa, a ujrzycie różnica.

Moje pytanie jest proste ... nowe domyślne zachowanie w JDK 7 całkowicie zakłóca mój program (powinny one być bardziej ostrożne w Oracle przy zmianie tego rodzaju domyślnych ustawień ... wydają się nieistotne, ale kiedy używasz JTextPane do wyświetlania danych, które zwykle zawierają bardzo długie ciągi liter, nie są tak nieważne - w rzeczywistości mam zamiar złożyć raport o błędzie, ale chciałbym mieć obejście,/jeśli nie rozwiązują to). Jakikolwiek sposób powrócić do poprzedniego zachowania?

Zauważ, że mam zaznaczone odpowiedź na pytanie powiązanego How is word-wrapping implemented in JTextPane, and how do I make it wrap a string without spaces? ale to nie jest odpowiedź na to pytanie - zapewnia sposób dokonywania wrap JTextPane bez żadnego względu na wszystko dla białych znaków, ale dla mnie to pożądane zachowanie jest podzielona linie w białych znakach, jeśli to możliwe, i gdzie indziej, jeśli nie jest to możliwe (jak w poprzednich wersjach Java).

+0

Czy używając [ 'invokeLater()'] (http://download.oracle.com/javase/tutorial/uiswing/concurrency/ initial.html) pomóc? –

+0

Nie ... ten sam efekt. –

+0

Mam dokładnie ten sam problem. Powiązane: https://forums.oracle.com/forums/thread.jspa?threadID=2374090 (brak odpowiedzi ...) Plakat tam już sporządził raport o błędzie, ale został zamknięty jako "nie błąd", bez słowo wyjaśnienia ... – PhiLho

Odpowiedz

1
+0

Dzięki, jest niezwykle podobny ... ale niestety nie wygląda na to, że jest to ten sam błąd (ma to związek z zestawami atrybutów i został naprawiony dawno temu):/ –

+0

Cóż, myślę, że to jest powiązany, chociaż zachowanie w 1.6 nie zostało zmienione. Spójrz na komentarz: "Należy zauważyć, że domyślne zachowanie dzielenia (łamanie GlyphView w dowolnym miejscu, gdy BreakIterator nie wykrywa żadnego ważnego punktu przerwania) jest okropnie złe i nie powinno być przywracane w żadnym wydaniu JDK, ani przyszłym, ani przeszłym." Wygląda na to, że musimy teraz wykonać więcej pracy ... – PhiLho

1

Hi miałem ten sam problem, ale okazało się obejść:

wystarczy utworzyć rozszerzoną klasę JTextPane np

 MyWrapJTextPane extends JTextPane 

i zastąpić następującą metodę - to działa ;-)

 public boolean getScrollableTracksViewportWidth() { 
      return true; 
     } 
+0

Niestety: nie działa! rozwiązuje to tylko problem z długimi liniami (zawierającymi białe przestrzenie) - są one teraz prawidłowo zapakowane - ale długie słowa nadal nie są zapakowane :-( – Thomwiesel

2

dobry połów z @ dk89, ale niestety podanych obejścia nie działają: JDK 7 najwyraźniej nadal nie oferują czekaj, aby ustawić niestandardowy BreakIterator na JTextComponent; nawet na GlyphView, gdzie generowanie BreakIteratora jest prywatne. A jeśli wstawimy ciąg znaków char, to nadal nie działa: Przypuszczam, że kolejne przebiegi tekstu o identycznym stylu (AttributeSet) są zwinięte razem.

Spędziłem dwa dni próbując zrobić niestandardowy EditorKit, jak zalecono w innym miejscu, ale nie działa dobrze (z JDK 1.7.0_4 co najmniej) jako tekst.

Próbowałem rozwiązanie podane w How to word wrap text stored in JTextPanes which are cells in a JList i wariant znaleziono w http://www.experts-exchange.com/Programming/Languages/Java/Q_20393892.html

Ale okazało się, że breakView nie jest wywoływana, gdy JTextPane jest mniejszy niż najdłuższy wyraz w zdaniu. Nie działa więc wcale, gdy istnieje tylko jedno (długie) słowo. Tak jest w naszym przypadku, ponieważ wyświetlamy dostarczone przez użytkownika łańcuchy identyfikujące, często bez spacji, w raczej małych przestrzeniach.

W końcu znalazłem proste rozwiązanie, zaczerpnięte z sugestii w raporcie o błędzie: rzeczywiście, wstaw ciąg znaków char, ale alternatywne style! Zatem mamy tyle segmentów, ile mamy znaków, a ciąg jest zawijany na granicach char. Aż do następnej "poprawki błędu"?

Fragmenty kodu:

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

Jak stwierdzono w błąd, powinny one dostarczyły łatwy sposób (być może jakąś właściwość, lub jakieś rzeczy do iniekcji), aby powrócić do starego zachowania.

11

Dla mnie prace fix (testowane pod 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); 
      } 
     } 

    } 
} 
+0

+1 dla Java7 :-), interesujące ViewFactory – mKorbel

+1

W rzeczywistości wszystko czego potrzebujemy jest aby getMinimumSpan() z LabelView zwrócił 0 dla X_AXIS. ViewFactory jest sposobem na zastąpienie domyślnej wersji LabelView – StanislavL

+0

, którą widzę i otrzymuję, dziękuję, całkiem poprawnie działa dla 'jtp.setComponentOrientation (RTL);' too – mKorbel