0

Please can you help me understand window and component sizing. I have read through this forum, tutorial and reference documentation and have come to the conclusion that if I am using Swing I use LayoutManagers, setPreferredSize on components and Pack() the frame after setting it up. This works fine and I get the following:

enter image description here

However, when I make the window smaller I get this:

enter image description here

If I wish to change the size of my components as the window size changes do I need to introduce listeners to capture the change and act accordingly?

To me the best thing is that the window can be made smaller but the top level Panel does not change so contained components do not need resizing?

Any views?

EDIT - Code as requested - complete MVCE

package mvc;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JPanel;

import javax.swing.JScrollPane;


import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.LookAndFeel;

import java.awt.Insets;
import java.util.Calendar;

import javax.swing.JComboBox;

public class BudgetValuesWindow extends JFrame
{
        private JList<String> listIncomeMissing;
        private JList<String> listExpenseMissing;
        private JList<String> listIncomeSelect;
        private JList<String> listExpenseSelect;
        public String strBudget;
        public String strFileName;
        /*
         * Screen fields
         */
        private JButton btnGenerate;
        private JButton btnClose;
        private JButton btnSave;
        private JButton btnChoose;
        private JComboBox<String> boxBudget;
        private JCheckBox chkRoll;
        private JTextField txtFileName;
        @SuppressWarnings("unused")
        private LookAndFeel previousLF;
        /*
         *  date fields
         */
        public static int iFiscalYear;
        public static int iYear;
        public static int iFiscalMonth;
        public static int iFiscalDay;
        public static Calendar dtWeekStart;


        private JPanel panScreen;   
        private JPanel panTop;
        private JPanel panMid;
        private JScrollPane spExpenseMissing;
        private JScrollPane spExpenseSelected;
        private JScrollPane spIncomeMissing;
        private JScrollPane spIncomeSelected;
        private JButton btnESelect;
        private JButton btnEDeselect;
        private JButton btnISelect;
        private JButton btnIDeselect;
    public BudgetValuesWindow() {
        String [] data1 = {"Line 1","Line 2","Line 3"};
        String [] data2 = {"Line 4","Line 5","Line 6","Line 7"};
        String [] data3 = {"Line 8","Line 9"};
        String [] data4 = {"Line 10","Line 11","Line 12"};
        listIncomeMissing = new JList<String>(data1);
        listExpenseMissing = new JList<String>(data2);
        listIncomeSelect = new JList<String>(data3);
        listExpenseSelect = new JList<String>(data4);
        /*
         * start of screen
         */ 
        panScreen = new JPanel();
        this.add(panScreen);
        panScreen.setLayout(new BorderLayout());
        /*
         * Top panel
         */
        panTop = new JPanel();
        panTop.setPreferredSize(new Dimension(Constants.TOPWIDTH,Constants.TOPDEPTH));
        GridBagLayout gbl_panTop = new GridBagLayout();
        gbl_panTop.columnWidths = new int[]{100, 80, 100, 80, 100,30};
        panTop.setLayout(gbl_panTop);

        GridBagConstraints conBudgl = new GridBagConstraints();
        conBudgl.insets = new Insets(10, 10,10,10);
        conBudgl.gridx=0;
        conBudgl.gridy = 0;
        conBudgl.fill = GridBagConstraints.HORIZONTAL;
        conBudgl.anchor = GridBagConstraints.LINE_END;
        // Budget
        JLabel lblAccountsName = new JLabel("Budget:");
        panTop.add(lblAccountsName,conBudgl);

        GridBagConstraints conBudg = new GridBagConstraints();
        conBudg.insets = new Insets(10, 10,10,10);
        conBudg.gridx = 1;
        conBudg.gridy = 0;
        conBudg.fill = GridBagConstraints.HORIZONTAL;
        conBudg.anchor = GridBagConstraints.LINE_START;
        String strNames[] = {"Budget","Budget 2"};
        boxBudget = new JComboBox<String> (strNames);
        panTop.add(boxBudget,conBudg);
        /*
         * parameter file
         */
        JLabel lblFileName = new JLabel("Parameters : ");
        GridBagConstraints gbc_lblFileName = new GridBagConstraints();
        gbc_lblFileName.insets = new Insets(10, 10, 10, 10);
        gbc_lblFileName.gridx = 0;
        gbc_lblFileName.gridy = 1;
        gbc_lblFileName.fill = GridBagConstraints.HORIZONTAL;
        gbc_lblFileName.anchor = GridBagConstraints.LINE_END;
        panTop.add(lblFileName, gbc_lblFileName);

        txtFileName = new JTextField();
        txtFileName.setText("File3");
        GridBagConstraints gbc_txtFileName = new GridBagConstraints();
        gbc_txtFileName.insets = new Insets(10,0, 10, 0);
        gbc_txtFileName.gridx = gbc_lblFileName.gridx+1;
        gbc_txtFileName.gridy = gbc_lblFileName.gridy;
        gbc_txtFileName.gridwidth=3;
        gbc_txtFileName.fill = GridBagConstraints.HORIZONTAL;
        gbc_txtFileName.anchor = GridBagConstraints.LINE_START;
        txtFileName.setColumns(20);
        txtFileName.setText(strFileName);
        panTop.add(txtFileName, gbc_txtFileName);

        btnChoose = new JButton();
        btnChoose.setText("Find");
        GridBagConstraints gbc_btnChoose = new GridBagConstraints();
        gbc_btnChoose.insets = new Insets(10, 0, 0, 0);
        gbc_btnChoose.gridx = gbc_txtFileName.gridx+gbc_txtFileName.gridwidth;
        gbc_btnChoose.gridy = gbc_txtFileName.gridy;
        panTop.add(btnChoose, gbc_btnChoose);
        /*
         * Start Date
         */
        JLabel lblDatesStart = new JLabel("Dates - Start :");
        GridBagConstraints gbc_lblDateStart = new GridBagConstraints();
        gbc_lblDateStart.insets = new Insets(10,10,10,10);
        gbc_lblDateStart.gridx = gbc_lblFileName.gridx;
        gbc_lblDateStart.gridy = gbc_lblFileName.gridy+1;
        gbc_lblDateStart.anchor = GridBagConstraints.LINE_END;
        panTop.add(lblDatesStart, gbc_lblDateStart);
        JLabel jdtStartDate = new JLabel("02/12/2015");
        GridBagConstraints gbc_txtStartDate = new GridBagConstraints();
        gbc_txtStartDate.anchor = GridBagConstraints.LINE_START;
        gbc_txtStartDate.insets = new Insets(10,10,10,10);
        gbc_txtStartDate.gridx = gbc_lblDateStart.gridx+1;
        gbc_txtStartDate.gridy = gbc_lblDateStart.gridy;
        panTop.add(jdtStartDate, gbc_txtStartDate);

        /*
         * End Date
         */
        JLabel lblEnd = new JLabel("End :");
        GridBagConstraints gbc_lblEnd = new GridBagConstraints();
        gbc_lblEnd.insets = new Insets(10,10,10,10);
        gbc_lblEnd.gridx = gbc_txtStartDate.gridx+1;
        gbc_lblEnd.gridy = gbc_txtStartDate.gridy;
        gbc_lblEnd.anchor = GridBagConstraints.LINE_END;
        panTop.add(lblEnd, gbc_lblEnd);

        JLabel jdtEndDate = new JLabel("02/02/2016");
        GridBagConstraints gbc_txtEndDate = new GridBagConstraints();
        gbc_txtEndDate.insets = new Insets(10,10,10,10);
        gbc_txtEndDate.gridx = gbc_lblEnd.gridx+1;
        gbc_txtEndDate.gridy = gbc_lblEnd.gridy;
        gbc_txtEndDate.anchor = GridBagConstraints.LINE_START;
        panTop.add(jdtEndDate, gbc_txtEndDate);

        /*
         * Roll Up
         */
        JLabel lblRoll = new JLabel("Roll Up? :");
        GridBagConstraints gbc_lblRoll = new GridBagConstraints();
        gbc_lblRoll.insets = new Insets(10,10,10,10);
        gbc_lblRoll.gridx = gbc_txtEndDate.gridx+1;
        gbc_lblRoll.gridy = gbc_txtEndDate.gridy;
        gbc_lblRoll.anchor = GridBagConstraints.LINE_END;
        panTop.add(lblRoll, gbc_lblRoll);

        chkRoll = new JCheckBox();
        GridBagConstraints gbc_cbRoll = new GridBagConstraints();
        gbc_cbRoll.insets = new Insets(10,10,10,10);
        gbc_cbRoll.gridx = gbc_lblRoll.gridx+1;
        gbc_cbRoll.gridy = gbc_lblRoll.gridy;
        gbc_cbRoll.anchor = GridBagConstraints.LINE_START;
        chkRoll.setSelected(true);
        panTop.add(chkRoll, gbc_cbRoll);
        /*
         * Button 1 - Save
         */
        GridBagConstraints gbcbt1 = new GridBagConstraints();
        gbcbt1.gridx = gbc_lblDateStart.gridx;
        gbcbt1.gridy = gbc_lblDateStart.gridy+1;
        gbcbt1.anchor = GridBagConstraints.LINE_START;
        gbcbt1.insets = new Insets(5,5,5,5);
        btnSave = new JButton("Save Parameters");
        panTop.add(btnSave,gbcbt1);

        /*
         * Button 2 - Generate values
         */
        GridBagConstraints gbcbt2 = new GridBagConstraints();
        gbcbt2.gridx = gbcbt1.gridx+1;
        gbcbt2.gridy = gbcbt1.gridy;
        gbcbt2.anchor = GridBagConstraints.LINE_START;
        gbcbt2.insets = new Insets(5,5,5,5);
        btnGenerate = new JButton("Generate");
        panTop.add(btnGenerate,gbcbt2);

        /*
         * Button 3 - Close
         */
        GridBagConstraints gbcbt3 = new GridBagConstraints();
        gbcbt3.gridx = gbcbt2.gridx+1;
        gbcbt3.gridy = gbcbt2.gridy;
        gbcbt3.anchor = GridBagConstraints.LINE_START;
        gbcbt3.insets = new Insets(5,5,5,5);
        btnClose = new JButton("Close");
        panTop.add(btnClose,gbcbt3);
        panTop.setPreferredSize(new Dimension(Constants.TOPWIDTH,Constants.TOPDEPTH));      

        panScreen.add(panTop, BorderLayout.PAGE_START);

        /*
         * Middle panel - table
         */
        panMid = new JPanel(new GridBagLayout());
        JLabel lblIncome = new JLabel("Income Categories :");
        GridBagConstraints gbc_lblIncome = new GridBagConstraints();
        gbc_lblIncome.insets = new Insets(0,10,0,0);
        gbc_lblIncome.gridx = 0;
        gbc_lblIncome.gridy = 0;
        gbc_lblIncome.anchor = GridBagConstraints.FIRST_LINE_START;
        panMid.add(lblIncome, gbc_lblIncome);
        JLabel lblIncmis = new JLabel("Available");
        GridBagConstraints gbc_lblIncmis = new GridBagConstraints();
        gbc_lblIncmis.gridx = gbc_lblIncome.gridx;
        gbc_lblIncmis.gridy = gbc_lblIncome.gridy+1;
        gbc_lblIncmis.anchor = GridBagConstraints.CENTER;
        panMid.add(lblIncmis, gbc_lblIncmis);
        JLabel lblIncsel = new JLabel("Selected");
        GridBagConstraints gbc_lblIncsel = new GridBagConstraints();
        gbc_lblIncsel.gridx = gbc_lblIncmis.gridx+2;
        gbc_lblIncsel.gridy = gbc_lblIncmis.gridy;
        gbc_lblIncsel.anchor = GridBagConstraints.CENTER;
        panMid.add(lblIncsel, gbc_lblIncsel);
        spIncomeMissing = new JScrollPane(listIncomeMissing);   
        GridBagConstraints gbc_spIncmis = new GridBagConstraints();
        gbc_spIncmis.insets = new Insets(0,10,0,0);
        gbc_spIncmis.gridx = gbc_lblIncome.gridx;
        gbc_spIncmis.gridy = gbc_lblIncmis.gridy+1;
        gbc_spIncmis.gridheight = 2;
        spIncomeMissing.setPreferredSize(new Dimension(Constants.PANELWIDTH,Constants.PANELHEIGHT));
        panMid.add(spIncomeMissing, gbc_spIncmis);
        btnISelect = new JButton("Sel");
        GridBagConstraints gbc_btISelect = new GridBagConstraints();
        gbc_btISelect.insets = new Insets(40,5,5,5);
        gbc_btISelect.gridx = gbc_spIncmis.gridx+1;
        gbc_btISelect.gridy = gbc_spIncmis.gridy;
        gbc_btISelect.anchor = GridBagConstraints.PAGE_END;
        gbc_btISelect.fill = GridBagConstraints.HORIZONTAL;
        panMid.add(btnISelect, gbc_btISelect);
        btnIDeselect = new JButton("Des");
        GridBagConstraints gbc_btIDeselect = new GridBagConstraints();
        gbc_btIDeselect.insets = new Insets(0,5,5,5);
        gbc_btIDeselect.gridx = gbc_btISelect.gridx;
        gbc_btIDeselect.gridy = gbc_btISelect.gridy+1;
        gbc_btIDeselect.anchor = GridBagConstraints.PAGE_START;
        gbc_btIDeselect.fill = GridBagConstraints.HORIZONTAL;
        panMid.add(btnIDeselect, gbc_btIDeselect);
        spIncomeSelected = new JScrollPane(listIncomeSelect);   
        GridBagConstraints gbc_spIncsel = new GridBagConstraints();
        gbc_spIncsel.insets = new Insets(0,0,0,10);
        gbc_spIncsel.gridx =gbc_btISelect.gridx+1;
        gbc_spIncsel.gridy = gbc_spIncmis.gridy;
        gbc_spIncsel.gridheight = 2;
        spIncomeSelected.setPreferredSize(new Dimension(Constants.PANELWIDTH,Constants.PANELHEIGHT));
        panMid.add(spIncomeSelected, gbc_spIncsel);

        JLabel lblExpense = new JLabel("Expense Categories :");
        GridBagConstraints gbc_lblExpense = new GridBagConstraints();
        gbc_lblExpense.insets = new Insets(0,10,0,0);
        gbc_lblExpense.gridx = gbc_lblIncome.gridx;
        gbc_lblExpense.gridy = gbc_lblIncmis.gridy+gbc_spIncmis.gridheight+1;
        gbc_lblExpense.anchor = GridBagConstraints.FIRST_LINE_START;
        panMid.add(lblExpense, gbc_lblExpense);
        JLabel lblExpmis = new JLabel("Available");
        GridBagConstraints gbc_lblExpmis = new GridBagConstraints();
        gbc_lblExpmis.gridx = gbc_lblExpense.gridx;
        gbc_lblExpmis.gridy = gbc_lblExpense.gridy+1;
        gbc_lblExpmis.anchor = GridBagConstraints.CENTER;
        panMid.add(lblExpmis, gbc_lblExpmis);
        JLabel lblExpsel = new JLabel("Selected");
        GridBagConstraints gbc_lblExpsel = new GridBagConstraints();
        gbc_lblExpsel.gridx = gbc_lblExpmis.gridx+2;
        gbc_lblExpsel.gridy = gbc_lblExpmis.gridy ;
        gbc_lblExpsel.anchor = GridBagConstraints.CENTER;
        panMid.add(lblExpsel, gbc_lblExpsel);
        spExpenseMissing = new JScrollPane(listExpenseMissing); 
        GridBagConstraints gbc_spExpmis = new GridBagConstraints();
        gbc_spExpmis.insets = new Insets(0,10,10,0);
        gbc_spExpmis.gridx = gbc_lblExpense.gridx;
        gbc_spExpmis.gridy = gbc_lblExpsel.gridy+1;
        gbc_spExpmis.gridheight = 2;
        spExpenseMissing.setPreferredSize(new Dimension(Constants.PANELWIDTH,Constants.PANELHEIGHT));
        panMid.add(spExpenseMissing, gbc_spExpmis);
        btnESelect = new JButton("Sel");
        GridBagConstraints gbc_btESelect = new GridBagConstraints();
        gbc_btESelect.insets = new Insets(40,5,5,5);
        gbc_btESelect.gridx = gbc_spExpmis.gridx+1;
        gbc_btESelect.gridy = gbc_spExpmis.gridy;
        gbc_btESelect.anchor = GridBagConstraints.PAGE_END;
        gbc_btESelect.fill = GridBagConstraints.HORIZONTAL;
        panMid.add(btnESelect, gbc_btESelect);
        btnEDeselect = new JButton("Des");
        GridBagConstraints gbc_btEDeselect = new GridBagConstraints();
        gbc_btEDeselect.insets = new Insets(0,5,5,5);
        gbc_btEDeselect.gridx = gbc_btESelect.gridx;
        gbc_btEDeselect.gridy = gbc_btESelect.gridy+1;
        gbc_btEDeselect.anchor = GridBagConstraints.PAGE_START;
        gbc_btEDeselect.fill = GridBagConstraints.HORIZONTAL;
        panMid.add(btnEDeselect, gbc_btEDeselect);
        spExpenseSelected = new JScrollPane(listExpenseSelect); 
        GridBagConstraints gbc_spExpsel = new GridBagConstraints();
        gbc_spExpsel.insets = new Insets(0,0,10,10);
        gbc_spExpsel.gridx = gbc_btESelect.gridx+1;
        gbc_spExpsel.gridy = gbc_spExpmis.gridy;
        gbc_spExpsel.gridheight = 2;
        spExpenseSelected.setPreferredSize(new Dimension(Constants.PANELWIDTH,Constants.PANELHEIGHT));
        panMid.add(spExpenseSelected, gbc_spExpsel);

        panMid.setPreferredSize(new Dimension(Constants.MIDWIDTH,Constants.MIDDEPTH));
        panScreen.add(panMid,BorderLayout.CENTER);
        /*
         * Set dirty back to false so real changes are caught
         */
        this.pack();
    }

}

package mvc;

public abstract class Constants {

    /*
     * Screen Size Parameters
     */
    public static final int FRAMEWIDTH =800;
    public static final int FRAMEDEPTH = 800;
    public static final int TOPWIDTH = FRAMEWIDTH-40;
    public static final int TOPDEPTH = 200;
    public static final int MIDWIDTH = FRAMEWIDTH-40;
    public static final int MIDDEPTH = FRAMEDEPTH - TOPDEPTH;
    public static final int ADDSCREENWIDTH = 350;
    public static final int ADDSCREENHEIGHT =300;
    public static final int PANELWIDTH = 300;
    public static final int PANELHEIGHT= 200;
    public static final int GENSCREENWIDTH = 1000;
    public static final int GENSCREENHEIGHT = 800;
    /*
     * Generate screen panel sizes
     */
    public static final int GENBOTWIDTH = GENSCREENWIDTH-50;
    public static final int GENBOTDEPTH = (GENSCREENHEIGHT)/8;
    public static final int GENTOPWIDTH = GENSCREENWIDTH-50;
    public static final int GENTOPDEPTH = (GENSCREENHEIGHT)/8;
    public static final int GENMIDWIDTH = GENSCREENWIDTH-50;
    public static final int GENMIDDEPTH = GENSCREENHEIGHT-GENTOPDEPTH-GENBOTDEPTH-50;
    public static final int GENCATPREFWIDTH = 200;
    public static final int GENCATMINWIDTH = 100;
    public static final int GENAMOUNTWIDTH = 80;
}

package mvc;

import javax.swing.JFrame;

public class MVC {
        /**
         * Create the GUI and show it.  For thread safety,
         * this method should be invoked from the
         * event-dispatching thread.
         */
        private static void createAndShowGUI() {
            //Create and set up the window.
            JFrame frame = new BudgetValuesWindow();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }

        public static void main(String[] args) {
            //Schedule a job for the event-dispatching thread:
            //creating and showing this application's GUI.
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }

}
  • 3
    Seems problem with `setPreferedSize(...)` on some components, show your code. Also read that [topic](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi). – alex2410 Feb 20 '15 at 13:26
  • 1
    For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). – Andrew Thompson Feb 20 '15 at 13:37
  • 1
    I am fairly new to this forum. When constructing an MCVE do you hard code data to reduce the code required? –  Feb 20 '15 at 13:54
  • *"do you hard code data.."* If data is really necessary, yes, hard code it. – Andrew Thompson Feb 20 '15 at 13:58
  • One point worth noting is that when the program is started for the first time the Available lists (left hand side) are empty. I introduced the preferred sizes to ensure scroll panes were the same size. –  Feb 20 '15 at 13:58
  • *"Code as requested - not complete"* Nope. 1) That wasn't a request, but advice. 2) The first word in MCVE is **minimal,** and at almost 500 LOC, that is ..not minimal. 3) And the 2nd word is **complete!** – Andrew Thompson Feb 20 '15 at 14:01
  • Thanks everyone, I am editing this post to add the MVCE. Thanks durron597 I will investigate GroupLayout. –  Feb 20 '15 at 14:29

2 Answers2

1

Why are you using "static" for your variables? You don't use static for the components and don't need static for the variables.

However, when I make the window smaller I get this:

The basic answer to your question is that when using a GridBagLayout, if there is not enough space for a component to be displayed at its preferred size, then the component is displayed at its "minimum size". In the case of a scroll pane the minimum is (0, 0).

So the solution is to provide your scroll panes with a reasonable minimum size.

Also, it is not necessary to create a new GridBagConstraint for every component. In many cases where the parameters are similar you can reuse the same constraint and just change a specific property, for example, the gridx or gridy.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Thanks for explaining the reason. I know about the reuse of GridBagConstraint. I have been playing with WindowBuilder which creates a separate variable for each component. –  Feb 21 '15 at 10:31
0

Do NOT use GridBagLayout.

The best way to do components that can resize appropriately in Java is to use GroupLayout.

GroupLayout:

  • Properly respects specified sizes
  • Investigates inherited sizes from child components
  • Supports gaps to which you can assign ranges

This is definitely your best bet for fixing this problem; I understand it will be a lot of work to relayout your entire page, but trust me, it is worth it.

One piece of advice I have for you to make the code more manageable: make custom components and break the JFrame into multiple classes. For example, these sections should be broken into their own class (and then you populate two instances of them):

Boxed form

Doing this will:

  • Eliminate redundant code
  • Make the controls easier to lay out (because each piece is less complicated)
  • Make the code easier to maintain in the future
durron597
  • 31,968
  • 17
  • 99
  • 158
  • 1
    1) *Do NOT use GridBagLayout.* Why? It's not my favorite but I wouldn't say *don't use it*. I'd say there are better choices. 2) *The best way ... is to use GroupLayout* Strange advice, given is one of the most inflexible and complex layout managers out there. Besides it is designed to be used by GUI builders which use is discouraged (plenty of reasons exposed in SO). 3) There are better layout managers [listed here](http://stackoverflow.com/a/18749449/1795530) 4) For complex GUI a [Nested layout](http://stackoverflow.com/a/5630271/1795530) approach sounds like a good match. – dic19 Feb 20 '15 at 15:31
  • 1
    Having looked at GroupLayout I agree with dic19. GridBagLayout has some defects but on the whole is quite useable. GroupLayout is quite complex and though I could use it if starting from scratch, I will not change my existing code to use it. I have solved my problem by using setMinimumSize, as suggested by camickr, which the layout manager respects. –  Feb 22 '15 at 10:49