Nadar Nadar - 1 month ago 25
Java Question

How do I get JTextArea with word-wrap to shrink with FormLayout?

I need a non-editable word-wrappable text label/field/area without scrollbars that will resize with its parent without scrollbars. It will be used to display texts of various size, but there will "always" be enough space to display the full text. In the rare event that a user resizes the windows so small that it won't fit, I'd want it to truncate lines/vertically.

I've been searching quite a lot and read any relevant question I can find here without getting to the root of the problem. I've opted for

JTextArea
because of its word-wrapping capability. I've also tried custom extensions of
JLabel
but the problem remains the same, so I figure I can just as well stick to
JTextArea
. The HTML approach is something I'd really like to avoid for multiple reasons. This isn't the first time I've bumped into this problem, and I've solved it previously by compromising the layout (designing the form in a different way). It certainly won't be the last time I face this issue, so I figured I need to find a way instead of keep compromising.

The problem is that while this works as intended initially and when the window is resized to be horizontally larger, horizontally shrinking the window doesn't update the word-wrapping and thus the
JTextArea
is truncated horizontally.

My testing has shown that this is only true for some layout managers, but I'm not sure at "what level" the problem actually lies. I've also read somewhere that the problem only exists on Windows, but I haven't verified/tested that. I'm using Windows for development, so all I know is that the problem is here for me and exists both with Java 7 and Java 8.

Testing different layout managers has shown:


  • FormLayout: Doesn't re-wrap when shrinking.

  • MigLayout: Doesn't re-wrap when shrinking.

  • GridBagLayout: It does re-wrap when shrinking, but not correctly so some of the text is hidden.

  • BorderLayout: Works as expected.

  • BoxLayout: Works as expected if axis is set to
    Y_AXIS
    . When set to
    X_AXIS
    behaves like FormLayout or MigLayout.

  • GridLayout: Works as expected.

  • CardLayout: Works as expected.



The existing application uses FormLayout extensively, and I can't change that without doing a lot of rewriting if at all. Wrapping the
JTextArea
with a
JPanel
with one of the working layouts, e.g
BorderLayout
doesn't help as long as one of the "broken" layouts are used further up in the hierarchy. It seems like there is some signal that is lost and doesn't reach the children, so I'm stuck as I can't realisticly get rid of
FormLayout
all the way to the top of the hierarchy.

There are several existing questions here that is very similar, but many are about
JTextArea
in combination with
JScrollPane
or some other slight variation and none has helped me find a working solution. By narrowing the issue down as much as possible and supplying a working SCCEE I'm hoping not to be rejected as a duplicate.

SCCEE:

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.RowSpec;
import javax.swing.JTextArea;



public class MainFrame {

private JFrame frame;

/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

public void run() {
try {
MainFrame window = new MainFrame();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

/**
* Create the application.
*/
public MainFrame() {
initialize();
}

/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

final JPanel panel = new JPanel(new FormLayout(
new ColumnSpec[] {ColumnSpec.decode("pref:grow"),},
new RowSpec[] {RowSpec.decode("pref:grow"),}
));
frame.getContentPane().add(panel, BorderLayout.CENTER);
final JTextArea textArea = new JTextArea();
panel.add(textArea, "1, 1, fill, fill");
textArea.setLineWrap(true);
textArea.setText("Lorem ipsum dolor sit amet, ut eum assum debet tacimates, mei nisl electram moderatius ei, veri semper cotidieque eu pri. In quot noster vocent usu, ne augue voluptaria quo. Ex per malis vocibus. Consequat mediocritatem no vel.");
}
}

Answer

You can maybe set the column size... but you can also set setPreferredSize of the text area to 0,0:

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;

public class Test extends JFrame {
    final JPanel panel;
    final JTextArea textArea;
    final FormLayout fl;
    public Test() {
        this.setBounds(100, 100, 450, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fl = new FormLayout(
                new ColumnSpec[] {ColumnSpec.decode("pref:grow"), 
//                      ColumnSpec.decode("pref:grow")
                        },
                new RowSpec[] {RowSpec.decode("pref:grow"), 
//                      RowSpec.decode("pref:grow")
                        }
            );
        panel = new JPanel(fl);
        this.getContentPane().add(panel, BorderLayout.CENTER);
        textArea = new JTextArea();
        textArea.setPreferredSize(new Dimension());

        panel.add(new JPanel().add(textArea), "1, 1, fill, fill");
//        panel.add(new JPanel().add(new JLabel("test")), "1, 2, fill, fill");
//        panel.add(new JPanel().add(new JLabel("test")), "2, 1, fill, fill");
        textArea.setLineWrap(true);
//        textArea.setWrapStyleWord(true);
        textArea.setText("Lorem ipsum dolor sit amet, ut eum assum "
                + "debet tacimates, mei nisl electram moderatius ei, veri semper cotidieque eu pri. In quot noster vocent usu, "
                + "ne augue voluptaria quo. Ex per malis vocibus. Consequat mediocritatem no vel.");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Test().setVisible(true);
            }
        });
    }
}
Comments