javaswingjdialogpreferredsize

JDialog size not suitable, why isn't the PreferredSize used in BoxLayout?


I have a JDialog with only a few simple components, one JTextArea, one JtextField and one JRadioButton. I just want it displayed with a suitable size.

The PreferredSize of the components seems reasonable but everything gets truncated. I'm using BoxLayout with Y_AXIS.

I don't want to have to set explicit sizes, I just want a suitable size for the components that are there.

In particular, why is the PreferredSize for the textarea ignored?

The minimal code that I have created follows:-

It creates the following output:-

0|Name: dialog0, Class: javax.swing.JDialog,  [175, 132], H: 103, W: 132, AlignmentX: 0, AlignmentY: 0
1|-Name: null, Class: javax.swing.JRootPane,  [137, 116], H: 65, W: 116, AlignmentX: 0, AlignmentY: 0
2|--Name: null.glassPane, Class: javax.swing.JPanel,  [10, 10], H: 65, W: 116, AlignmentX: 0, AlignmentY: 0
2|--Name: null.layeredPane, Class: javax.swing.JLayeredPane,  [1, 1], H: 65, W: 116, AlignmentX: 0, AlignmentY: 0
3|---Name: null.contentPane, Class: javax.swing.JPanel,  [137, 116], H: 65, W: 116, AlignmentX: 0, AlignmentY: 0
4|----Name: null, Class: javax.swing.JPanel,  [137, 116], H: 65, W: 116, AlignmentX: 0, AlignmentY: 0
5|-----Name: null, Class: javax.swing.JTextArea,  [94, 116], H: 22, W: 116, AlignmentX: 0, AlignmentY: 0
5|-----Name: null, Class: javax.swing.JRadioButton,  [23, 57], H: 23, W: 57, AlignmentX: 0, AlignmentY: 0
5|-----Name: null, Class: javax.swing.JTextField,  [20, 6], H: 20, W: 116, AlignmentX: 0, AlignmentY: 0

The code follows:-

package testing.example;

import java.awt.Component;
import java.awt.Container;
import javax.swing.BoxLayout;
import static javax.swing.BoxLayout.Y_AXIS;
import javax.swing.ButtonGroup;
import javax.swing.CellRendererPane;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JViewport;
import testing.Panel;
import testing.testPanel;

public class DialogSize {

final private static String LOOKANDFEEL = "Windows";
private static JDialog dialog;
private static JTextArea textArea;
private static JTextField textField;
private static JPanel panel;
private static JRadioButton button;

// <editor-fold defaultstate="collapsed" desc="initLookAndFeel">
private static void initLookAndFeel() {
    if (LOOKANDFEEL != null) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }
        catch (ClassNotFoundException | 
                InstantiationException | 
                IllegalAccessException | 
                javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(BlankBorder.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
    }
} // </editor-fold>

private static void createAndShowDialog() {
    initLookAndFeel();
    dialog = new JDialog();
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, Y_AXIS));
    textArea = new JTextArea();
    textArea.setText("Enter the dribble furble that you wish to frangle from all time.");
    textArea.setLineWrap(true);
    textArea.setWrapStyleWord(true);
    button = new JRadioButton("Button");
    textField = new JTextField();
    panel.add(textArea);
    panel.add(button);
    panel.add(textField);
    dialog.add(panel);
    dialog.setVisible(true);
    dialog.pack();
    analyseComponent(dialog);
}

public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            createAndShowDialog();
        }
    });
}

private static int level = 0;
private static String indent = "|";

public static void analyseFrame(JFrame frame) {
    if (frame == null) return;
    int h = frame.getHeight();
    int w = frame.getWidth();
    Container container = frame.getContentPane();
    analyseComponent(frame);
    System.out.print("\n\n");
}

public static void analyseContainer(Container container) {
    level++;
    indent += "-";
    int componentCount = container.getComponentCount();
    Component[] components = container.getComponents();
    for (int i=0; i < componentCount; i++) {
        Component component = components[i];
        analyseComponent(component);
    }
    indent = indent.replaceAll("(.*)-", "$1");
    level--;
}

public static void analyseComponent(Component component) {
    Class componentClass = component.getClass();
    String className = componentClass.getName();
    int alignmentX = (int) component.getAlignmentX();
    int alignmentY = (int) component.getAlignmentY();
    int h = component.getHeight();
    int w = component.getWidth();
    System.out.print(level+indent+
            "Name: "+component.getName()+", "+
            "Class: "+component.getClass().getName()+", "+
            " ["+(int)component.getPreferredSize().getHeight() +", "+
            (int)component.getPreferredSize().getWidth()+"], "+
            "H: "+h +", "+"W: "+w+", "+
            "AlignmentX: "+alignmentX+", "+
            "AlignmentY: "+alignmentY+
            "\n");
    if (className.contains("Dialog")) {
        analyseContainer((Container)component);
    }
    else if (className.contains("Pane")) {
        analyseContainer((Container)component);
    }
}

}


Solution

  • In particular, why is the PreferredSize for the textarea ignored?

    Good question. I can't explain why it appears to be ignored.

    The default preferred size calculation will try to display all the text on a single line, but for some reason the calculated preferred width is not used when calculating the preferred size of the panel and therefore the dialog.

    All I can suggest is some guidelines for creating the GUI:

    First of all the order of execution should be:

    dialog.pack();
    dialog.setVisible(true);
    

    When you do it the other way around the dialog will initially be displayed at its default size and then when the pack() is done it will be resized. There is a possibility that you could see the dialog painted and the default size and then jump to its larger size.

    When using text components you will want to provide additional information to the component so that it can better determine its preferred size. So you would use something like:

    JTextArea textArea = new JTextArea(3, 20); 
    JTextField textField = new JTextField(10);
    

    This will allow each component to determine its preferred width based on the column value specified. With the text area the rows will provide information to be used to determine the height.

    When you use this approach the preferred size of the text area and text field will be used in the pack() calculation.

    Also you should use:

    panel.add( new JScrollPane( textArea ) );
    

    This will make sure that 3 lines are initially displayed. If more lines are needed to display the text then scrollbars will appear.