1

I have a simple grid bag layout and when I only use text fields, it works correctly. When I put a JSpinner in, the whole layout gets completely messed up. By this I mean two of my three columns completely disappear, the the second column, the only column that appears, consumes the entire width of the window no matter how the window is sized. The complete code is below.

The problem seems to have something to do with spinners specifically, if I use other kinds of JComponents like JLabel the problem does not manifest itself. What did I do wrong that caused the JSpinner to completely destroy the layout?

package product_data.ui;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;

public class StrippedProductEditor extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 5429511033322948114L;
    private JLabel lblManufacturer;
    private JLabel lblSku;
    private JTextField mfrText;
    private JTextField skuText;
    private JTextArea extraText;
    private JLabel lblListPrice;
    private JSpinner spinner;


    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    new StrippedProductEditor();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

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

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridBagLayout gridBagLayout = new GridBagLayout();
        gridBagLayout.columnWidths = new int[] { 0, 0, 0 };
        gridBagLayout.rowHeights = new int[] { 0, 0, 0, };
        gridBagLayout.columnWeights = new double[] { 0.0, 1.0, 1.0 };
        gridBagLayout.rowWeights = new double[] { 0.0, 0.0, 0.0};
        getContentPane().setLayout(gridBagLayout);

        lblManufacturer = new JLabel("Manufacturer");
        GridBagConstraints gbc_lblManufacturer = new GridBagConstraints();
        gbc_lblManufacturer.insets = new Insets(0, 0, 5, 5);
        gbc_lblManufacturer.gridx = 0;
        gbc_lblManufacturer.gridy = 0;
        getContentPane().add(lblManufacturer, gbc_lblManufacturer);

        mfrText = new JTextField();
        GridBagConstraints gbc_lblMfrText = new GridBagConstraints();
        gbc_lblMfrText.insets = new Insets(0, 0, 5, 5);
        gbc_lblMfrText.fill = GridBagConstraints.HORIZONTAL;
        gbc_lblMfrText.gridx = 1;
        gbc_lblMfrText.gridy = 0;
        getContentPane().add(mfrText, gbc_lblMfrText);

        lblSku = new JLabel("SKU");
        GridBagConstraints gbc_lblSku = new GridBagConstraints();
        gbc_lblSku.insets = new Insets(0, 0, 5, 5);
        gbc_lblSku.gridx = 0;
        gbc_lblSku.gridy = 1;
        getContentPane().add(lblSku, gbc_lblSku);

        skuText = new JTextField();
        GridBagConstraints gbc_textField_1 = new GridBagConstraints();
        gbc_textField_1.insets = new Insets(0, 0, 5, 5);
        gbc_textField_1.fill = GridBagConstraints.HORIZONTAL;
        gbc_textField_1.gridx = 1;
        gbc_textField_1.gridy = 1;
        getContentPane().add(skuText, gbc_textField_1);
        skuText.setColumns(10);

        extraText = new JTextArea();
        JScrollPane dictScrollPane = new JScrollPane(extraText);
        GridBagConstraints gbc_dict = new GridBagConstraints();
        gbc_dict.insets = new Insets(0, 0, 5, 5);
        gbc_dict.gridx = 2;
        gbc_dict.gridy = 0;
        gbc_dict.gridheight = 2;
        gbc_dict.fill = GridBagConstraints.BOTH;

        getContentPane().add(dictScrollPane, gbc_dict);
        lblListPrice = new JLabel("List Price");
        GridBagConstraints gbc_lblListPrice = new GridBagConstraints();
        gbc_lblListPrice.insets = new Insets(0, 0, 5, 5);
        gbc_lblListPrice.gridx = 0;
        gbc_lblListPrice.gridy = 2;
        getContentPane().add(lblListPrice, gbc_lblListPrice);

        double lp = 99.9;
        SpinnerNumberModel m = new SpinnerNumberModel(lp, 0.0d,
                Double.MAX_VALUE, 0.01d);
        spinner = new JSpinner(m);
        GridBagConstraints gbc_spinner = new GridBagConstraints();
        gbc_spinner.fill = GridBagConstraints.HORIZONTAL;
        gbc_spinner.insets = new Insets(0, 0, 5, 5);
        gbc_spinner.gridx = 1;
        gbc_spinner.gridy = 2;
        //commenting out this line will make the layout look 
        //correct, but then the spinner is missing.
        getContentPane().add(spinner, gbc_spinner);

        this.pack();
        this.setVisible(true);
    }

}
zelinka
  • 3,271
  • 6
  • 29
  • 42
  • Even with the spinner commented out, the layout doesn't work quite right for me. When the frame is first displayed, column 2 has zero width. It recovers if I resize the frame. – John Bollinger Oct 06 '14 at 20:39
  • It looks like your weights are wonky. You have only the default weights, no per-component weights, but the row and column weights specified on the layout itself are mostly zero. – John Bollinger Oct 06 '14 at 20:49

3 Answers3

1

So, after digging around the code a bit, I found that the JSpinner.NumberEditor, which is the editor been used to support the SpinnerNumberModel is calculating the fields columns property by using...

try {
    String maxString = formatter.valueToString(model.getMinimum());
    String minString = formatter.valueToString(model.getMaximum());
    ftf.setColumns(Math.max(maxString.length(),
                            minString.length()));
}
catch (ParseException e) {
    // TBD should throw a chained error here
}

Now, as it turns out, maxString equates to 0 (yeah I know), and minString equates to...

179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000

Which equals 411 characters...opps...

Now, you could reduce your models maximum value to something more realistic (like a million for example) or you could adjust the spinners size manually using something like...

((JSpinner.NumberEditor) spinner.getEditor()).getTextField().setColumns(10);

Personally, I prefer option one ;)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

The problem arises because your components and layout are underconstrained, but the key problem seems to be that the Spinner's preferred size is not playing nicely with the other components. Everything was much nicer after I added

spinner.setPreferredSize(new Dimension(128, 16));

though column 2 still ended up with width 0. You should set a preferred size on the JTextArea as well to sort that out. Alternatively, you could set a preferred size on the whole JFrame.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • See [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) for why this answer is likely to be downvoted – MadProgrammer Oct 06 '14 at 22:25
0

If you use eclipse, try it swing plugin http://www.eclipse.org/windowbuilder/ It does all the swing gui stuff for you. Personally it helped me a lot.

Muselc
  • 13
  • 6