+3  A: 

Here is an adaptation of your code, doing what you want. But it needs a little trick to calculate the size of the label and set its preferred Size.

I found the solution here

import static javax.swing.GroupLayout.DEFAULT_SIZE;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;
import javax.swing.text.View;

public class TextSizeProblem extends JFrame {
    public TextSizeProblem() {

     String dummyString = "";
     for (int i = 0; i < 100; i++) {
      dummyString += " word" + i; // Create a long text
     }
     JLabel text = new JLabel();
     text.setText("<html>" + dummyString + "</html>");

     Dimension prefSize = getPreferredSize(text.getText(), true, 400);

     JButton packMeButton = new JButton("pack");
     packMeButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
       pack();
      }
     });



     GroupLayout layout = new GroupLayout(this.getContentPane());
     getContentPane().setLayout(layout);
     layout.setVerticalGroup(layout.createParallelGroup().addComponent(packMeButton)
       .addComponent(text,DEFAULT_SIZE, prefSize.height, prefSize.height));
     layout.setHorizontalGroup(layout.createSequentialGroup().addComponent(packMeButton)
       .addComponent(text, DEFAULT_SIZE, prefSize.width, prefSize.width) // Lock the width to 400
       );

     pack();
    }

    public static void main(String args[]) {
     SwingUtilities.invokeLater(new Runnable() {
      public void run() {
       JFrame frame = new TextSizeProblem();
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setVisible(true);
      }
     });
    }

    private static final JLabel resizer = new JLabel();

    /**
     * Returns the preferred size to set a component at in order to render an html string. You can
     * specify the size of one dimension.
     */
    public static java.awt.Dimension getPreferredSize(String html, boolean width, int prefSize) {

     resizer.setText(html);

     View view = (View) resizer.getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey);

     view.setSize(width ? prefSize : 0, width ? 0 : prefSize);

     float w = view.getPreferredSpan(View.X_AXIS);
     float h = view.getPreferredSpan(View.Y_AXIS);

     return new java.awt.Dimension((int) Math.ceil(w), (int) Math.ceil(h));
    }
}
Laurent K
Yes, this solution works!
Lennart Schedin
+1  A: 

I found a solution to my problem. By replacing the JLabel with a JTextArea:

JTextArea text = new JTextArea();
text.setText(dummyString);
text.setLineWrap(true);
text.setWrapStyleWord(true);

And calling pack() followed by an invocation to the layout manager to layout the components again followed by another pack:

pack();
layout.invalidateLayout(this.getContentPane());
pack();

This will cause the layout manager to adapt to the width.

The complete code:

import static javax.swing.GroupLayout.DEFAULT_SIZE;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class TextSizeProblem3 extends JFrame {
  public TextSizeProblem3() {

    String dummyString = "";
    for (int i = 0; i < 100; i++) {
      dummyString += " word" + i;  //Create a long text
    }
    JTextArea text = new JTextArea();
    text.setText(dummyString);
    text.setLineWrap(true);
    text.setWrapStyleWord(true);

    JButton packMeButton = new JButton("pack");
    packMeButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        pack();
      }
    });

    GroupLayout layout = new GroupLayout(this.getContentPane());
    getContentPane().setLayout(layout);
    layout.setVerticalGroup(layout.createParallelGroup()
        .addComponent(packMeButton)
        .addComponent(text)
    );
    layout.setHorizontalGroup(layout.createSequentialGroup()
        .addComponent(packMeButton)
        .addComponent(text, DEFAULT_SIZE, 400, 400) //Lock the width to 400
    );

    pack();
    layout.invalidateLayout(this.getContentPane());
    pack();
  }

  public static void main(String args[]) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        JFrame frame = new TextSizeProblem3();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
      }
    });
  }
}

(you can add some customization (border, color etc) so it looks just like the JLabel but I have omitted that)

Lennart Schedin