2

Is there a widget for Swing that behaves like a JLabel, that automatically reflows the text if its dimensions have changed? For example:

Large horizontal space available:
+--------------+
| Foo bar baz  |
+--------------+

Small horizontal space available:
+---------+
| Foo bar |
| baz     |
+---------+

I am currently using JEditorPane with setContentType("text/html") and HTML content. This works, but it does not use the System's default label font for displaying the text. Also, I would rather not put HTML tags into my text - at best, \n characters would be transformed into line breaks and everything else would be displayed as text.

skaffman
  • 398,947
  • 96
  • 818
  • 769
nd.
  • 8,699
  • 2
  • 32
  • 42

3 Answers3

7

You can use JTextArea, a multi-line plain-text widget.

JavaDoc: http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/JTextArea.html

    JTextArea ta = new JTextArea("A JTextArea containing a long text");
    ta.setLineWrap(true);
    ta.setWrapStyleWord(true);
    ta.setOpaque(false);
    ta.setEditable(false);
    ta.setFocusable(false);
  • setLineWrap(true) enables the wrapping
  • setWrapStyleWord(true) changes wrapping from character- to word-based
  • setOpaque(true) renders it opaque, like a normal label
  • setEditable(false) hides the caret and disables the user to change the text
  • setFocusable(false) disables the user to select the text

It look like a nornal JLabel, but it will wrap the text, whenever the width is too small.

Sven Lilienthal
  • 6,396
  • 4
  • 29
  • 25
  • At least in my case (Java 1.5 or Java 1.6), the line wrap does not behave as expected: it wraps the text at character level, not at word lebel. So in the above example, that could also produce something like "foo bar b(newline)az" – nd. Dec 17 '09 at 10:17
  • 1
    @nd: You need to call 'setWrapStyleWord(true)' in order to get word-level line wrap. – uckelman Dec 17 '09 at 11:23
  • Oh, totally overlooked the wrapStyleWord property in the documentation. Thank you. – nd. Dec 17 '09 at 14:10
  • If you have borders which are not completely opaque (e.g. a rounded border) you need to over-ride paintComponent() to prevent the background from painting in the insets area. – Justin Jun 30 '10 at 21:11
  • If you are using MIGLayout, and you are puzzled as to why the JTextArea grows but does not shrink, add "wmin 10" to the constraints. See [this answer](http://stackoverflow.com/questions/2475787/miglayout-jtextarea-is-not-shrinking-when-used-with-linewrap-true) for more details. – Robert B Dec 29 '11 at 22:28
  • And you need a layout manager that forces the width - e.g. BorderLayout (either CENTER or NORTH or SOUTH) or GridBagLayout with fill set to HORIZONTAL or BOTH, etc. – Pixel Apr 11 '12 at 14:43
  • You should also be copying the foreground and background colours, the font and the border at a bare minimum. – Hakanai Jul 07 '14 at 23:45
4

I'm not sure of this, but I think it's worth a try:

You can set a JLabel's text using HTML. This should take care of the font issue. Simply do something like

lbl.setText("<html><body>Foo bar baz</body></html>");

See how the text behaves then.

If that works for you, you can override JLabel's setText() method to convert \n into <br/> and wrap html and body tags around the text.

Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
2

I have made a custom UI delegate for JLabel to support multiple lines. It will wrap your text to fit the available space and also respect hard line breaks. The wrapped text should reflow when the component size changes. The UI delegate listens for changes to the component's dimension and recalculates the line breaks automatically.

Using the UI delegate is as straight forward as:

JLabel label = new JLabel("Text that'll wrap if necessary");
label.setUI(MultiLineLabelUI.labelUI);

Or alternatively use the custom MultiLineLabel class that in addition to wrapping text supports vertical and horizontal text alignment.

Here's the project: https://github.com/sasjo/multiline

If you compile and try the demo, it should reflow fine on OS X. If I remember correctly there's some problem with reflowing upon resizing the frame on Windows. Didn't look in to it at the time, but it seemed that the resized event never propagated to the label.

Samuel Sjöberg
  • 719
  • 5
  • 12
  • Very nice, that is even better than I wished for (w/ shadows) – nd. Dec 17 '09 at 14:09
  • I can confirm there are problems on Windows, in my case I had to invoke `MLL.revalidate(); MLL.repaint();` in order to get long text to actually wrap without resizing the window. Problem seems to be that the MLL must be in a visible container before it works. – Justin Jun 29 '10 at 17:53