Search code examples
javaswingjtextpane

An one-directional expanding JTextPane


I am trying to create a JTextPane which will act like JTextArea in example below:

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

public class SampleTextArea {
    public static void main(String[] args){
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        JTextArea textArea = new JTextArea(72,75);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        panel.add(textArea);
        JScrollPane scrollPane = new JScrollPane(panel);
        frame.getContentPane().add(BorderLayout.CENTER, scrollPane);

        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(1200,600);
        frame.setVisible(true);
    }
}

I want to create JTextPane with:

  • fixed width,
  • height which can dynamically expand from beginning value,
  • size independent from frame size,
  • scroll bar which react on JTextPane content, however placed on an inner side of frame instead of edge of JTextPane

When TextArea is created by number of rows and columns, and wrap lines and words is enabled,then it works exactly like i want - but it doesn't work with JTextPane.

I tried:

  • adding JTextPane inside JScrollPane - but JTextPane change its size with a JScrollPane,
  • setPrefferedSize for JTextPane - but then it doesn't expand horizontally,
  • insert a JScrollPane with a JTextPane on a JPanel, and then add the JPanel to another JScrollPane - it looks very bad,
    • solution from first answer - it depends how i use it, it either gives fixed width AND height or both are changeable,

I would be grateful for any suggestions.


Solution

  • You will need to override the getPreferredSize() of your JTextPane to implement your requirement.

    You can start by looking at the getPreferredSize() method of JTextArea:

    public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d = (d == null) ? new Dimension(400,400) : d;
        Insets insets = getInsets();
    
        if (columns != 0) {
            d.width = Math.max(d.width, columns * getColumnWidth() +
                    insets.left + insets.right);
        }
        if (rows != 0) {
            d.height = Math.max(d.height, rows * getRowHeight() +
                                insets.top + insets.bottom);
        }
        return d;
    }
    

    JTextPane doesn't support the concept of row/column size so you will need to add your own logic to come up with a default preferred size.

    Using hard coded values I came up with the following that replicates the behaviour of a JTextArea:

    JTextPane textArea = new JTextPane()
    {
        @Override
        public Dimension getPreferredSize()
        {
            Dimension d = super.getPreferredSize();
            d = (d == null) ? new Dimension(400,400) : d;
            Insets insets = getInsets();
    
            d.width = Math.max(d.width, 300 + insets.left + insets.right);
            d.height = Math.max(d.height, 300 + insets.top + insets.bottom);
    
            return d;
        }
    };