Advanced   Java   Services
LineWrapping bei JTextPane
Back Next Up Home

JTextPane selbst ist nicht scrollfähig, sondern muß in eine JScrollPane eingebettet werden, was am Einfachsten im Konstruktor von JScrollPane geschieht (siehe Beispiel unten). Die Voreinstellung für ein JTextPane ist (leider) genau umgekehrt wie für eine JTextArea. Per Default gibt es hier also einen Zeilenumbruch und damit kein waagrechtes Scrollen und die Frage ist, wie schaltet man den Zeilenumbruch ab. Im Gegensatz zu JTextArea stellt JTextPane dafür leider keine Methoden bereit. Auch in der neuesten Version 1.4 haben ist diese Schwachstelle nicht beseitigt worden. Es gibt jedoch zwei Tricks, mit denen man den Zeilenumbruch abschalten kann. Die zweite hier vorgestellte Methode läßt sich auch so ausbauen, daß man in einer eigenen Unterklasse von JTextPane dann sogar eine Methode void setLineWrap(boolean wrap) schreiben kann.

JTextPane in ein JPanel in ein JScrollPane


TextPane tp = new JTextPane() ;
JPanel pan = new JPanel();
pan.setLayout( new BorderLayout() );
pan.add(tp);
JScrollPane sp = new JScrollPane(pan);

Das funktioniert allerdings nicht mit dem DefaultFlowLayout von JPanel. Hier muß man das Layout auf BorderLayout oder auch GridLayout setzen. Das folgende Beispiel demonstriert diesen Trick.

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

public class LineWrapping2a extends JFrame
{
   private JTextPane tp ;
   private Container conPane;
   private JScrollPane sp;
   private JMenuBar mb ;

   // --------------------------- Konstruktor -------------------------\\
   public LineWrapping2a()
   {
      conPane = getContentPane();
      initCenter() ;
      initFrame() ;
   }

   // ---------------------------- initCenter --------------------------\\
   private void initCenter()
   {
      tp = new JTextPane() ;

      JPanel pan = new JPanel();
      pan.setLayout( new GridLayout() );
      pan.add(tp);

      sp = new JScrollPane(pan);
      conPane.add(sp);
   }

   // ------------------------------ initFrame -------------------------\\
   private void initFrame()
   {
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
      this.setTitle(" LineWrapping2b");
      this.setSize(300,250);
      this.setLocation(200,100);
      this.setVisible(true);
   }

   // ------------------------------- main --------------------------\\
   public static void main(String args[])
   {
      LineWrapping2a wnd = new LineWrapping2a() ;
   }

}


Überschreiben von   getScrollableTracksViewportWidth()   und   setSize()


Die beiden Methoden müssen wie folgt überschrieben werden.

public boolean getScrollableTracksViewportWidth()
{
   return false ;
}


public void setSize(Dimension d)
{
   if (d.width < getParent().getSize().width)
   {
      d.width = getParent().getSize().width;
   }
   super.setSize(d);
}

Im nächsten Beispiel geschieht das sehr elegant mit Hilfe einer anonymen Klasse.

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

public class LineWrapping2b extends JFrame
{
   private JTextPane tp ;
   private Container conPane;
   private JScrollPane sp;
   private JMenuBar mb ;

   // --------------------------- Konstruktor -------------------------\\
   public LineWrapping2b()
   {
      conPane = getContentPane();
      initCenter() ;
      initFrame() ;
   }

   // ---------------------------- initCenter --------------------------\\
   private void initCenter()
   {
      tp = new JTextPane()   // Hier beginnt die anonyme Klasse
               {
                  public boolean getScrollableTracksViewportWidth()
                  {
                     return false ;
                  }
                  public void setSize(Dimension d)
                  {
                     if (d.width < getParent().getSize().width)
                     {
                        d.width = getParent().getSize().width;
                     }
                     super.setSize(d);
                  }
               };

      sp = new JScrollPane(tp);
      conPane.add(sp);
   }

   // ------------------------------ initFrame -------------------------\\
   private void initFrame()
   {
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
      this.setTitle(" LineWrapping2b");
      this.setSize(300,250);
      this.setLocation(200,100);
      this.setVisible(true);
   }

   // ------------------------------- main --------------------------\\
   public static void main(String args[])
   {
      LineWrapping2b wnd = new LineWrapping2b() ;
   }

}


Eine eigene Klasse JTextPane2


Die zweite Idee wird nun verwendet um eine kleine Erweiterung von JTextPane zu schreiben, die wie bei JTextArea über eine Methode void setLineWrap(boolean wrap) verfügt. Das Beispiel übernimmt die Defaulteinstellung von JTextPane, d.h. der Zeilenumbruch ist voreingestellt. JTextPane2 bietet (for convenience) die gleichen Konstruktoren an wie JTextPane und arbeitet mit einer booleschen Variablen wrap, die auch über einen eigenen Konstruktor gesetzt werden kann. Man muß allerdings das JTextPane dazu zwingen, den jeweils neuen Zustand anzuzeigen. Dies geschieht mit setVisible(), ein validate() allein reicht nicht !

// Default ist : Zeilenumbruch, also kein waagrechtes scrollen.

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

class JTextPane2 extends JTextPane
{
   boolean wrap=true ;

   public JTextPane2()
   {
      // impliziter Aufruf von super()
   }

   public JTextPane2(boolean wrap)
   {
      // impliziter Aufruf von super()
      this.wrap = wrap;
   }

   public JTextPane2(StyledDocument doc)
   {
      super(doc);
   }

   public boolean getScrollableTracksViewportWidth()
   {
      if (wrap)
         return super.getScrollableTracksViewportWidth() ;
      else
         return false ;
   }

   public void setSize(Dimension d)
   {
      if(!wrap)
      {
         if (d.width < getParent().getSize().width)
            d.width = getParent().getSize().width;
      }
      super.setSize(d);
   }

   //Sets the line-wrapping policy of the JTextPane2
   //By default this property is true, d.h. Zeilenumbruch
   void setLineWrap(boolean wrap)
   {
      setVisible(false);  // alten Zustand verschwinden lassen (notwendig)
      this.wrap = wrap ;
      setVisible(true);   // neuen Zustand anzuzeigen (notwendig)
   }
}

top Back Next Up Home