Search code examples
javaswinglayout-managerborder-layout

Table is at the bottom of the frame


I have coded up a simple swing gui. However, my problem is that my table is on the bottom of my page. I would like to have with some space below my buttons and also more space down to the bottom. Here is a short program, what I am doing:

public class minimumExample extends JFrame {

    private JTabbedPane tabbedPane;
    private FilteredTabPanel filteredTabPanel;

    public void createTabBar() {

        tabbedPane = new JTabbedPane(JTabbedPane.TOP);

        filteredTabPanel = new FilteredTabPanel();
        tabbedPane.addTab("Test", filteredTabPanel.createLayout());

        add(tabbedPane);
        tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
    }

    private void makeLayout() {

        setTitle("Test App");
        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(1000, 500));
        createTabBar();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);

    }

    public void start() {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                makeLayout();   
            }
        });
    }

    public static void main(String[] args) throws IOException {
        minimumExample ex = new minimumExample();
        ex.start();
    }

    public class FilteredTabPanel extends JPanel {

        private JPanel selectionArea;
        private JLabel lCity;
        private JComboBox cityBox;
        private JTable filterTable;
        String[] columnNames = {"Cities"};
        String[][] data = {
                {"NY"}, {"NY"}, {"NY"}, {"NY"}, {"LA"}, {"LA"},{"Columbia"},{"DC"},{"DC"},{"DC"},{"DC"},{"DC"},{"DC"}
        };

        private JScrollPane scrollPane;

        public JPanel createLayout() {
            JPanel panel = new JPanel(new GridLayout(0, 1));
            //add panels to the layout
            panel.add(addButtons());    
            panel.add(showTable());

            repaint();
            revalidate();

            return panel;
        }

        public JPanel addButtons(){

            selectionArea = new JPanel(new FlowLayout(FlowLayout.LEFT));

            lCity = new JLabel("City");

            String[] fillings = {"NY", "LA", "Columbia", "DC"};
            cityBox = new JComboBox(fillings);

            cityBox.addActionListener(new ActionListener() {

                private String cityFilter;

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    //2. get data
                    cityFilter = cityBox.getSelectedItem().toString();
                }
            });

            selectionArea.add(lCity);
            selectionArea.add(cityBox);

            selectionArea.repaint();

            return selectionArea;
        }

        private JScrollPane showTable() {

            filterTable =new JTable(data, columnNames);
            filterTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

            scrollPane = new JScrollPane(filterTable);

            scrollPane.repaint();
            scrollPane.validate();

            return scrollPane;
        }
    }
}

This is how the page looks like:

enter image description here

Any recommendations how to fix that?


Solution

  • What you are trying to do is nesting simple layout managers to create your layout. I think that the official Swing tutorial is doing a disservice to the programmers by introducing these simple layout managers first. I recommend to avoid them and invest some time into more powerful managers. FlowLayout, BorderLayout and Gridlayout are really very simple managers but they cannot do much.

    I recommend to use these two managers:

    • MigLayout

    • GroupLayout

    (JGoodies's FormLayout is also a good option.)

    Not only are these managers more powerful, they also cope with more advanced requirements where others fail. (Resolution independence, adherence to OS design principles etc.)

    Before I present my two code examples, I want to say a few points to your code. You are unnecessarily calling repaint() and revalidate() methods.

    setPreferredSize(new Dimension(1000, 500));
    

    Specifying sizes in pixels is not portable. You better rely on the pack() method.

    setLayout(new BorderLayout());
    

    The JFrame's default layout manager (more precisely its content pane's) is BorderLayout. Therefore, this line is not needed.

    The following two examples are solutions with MigLayout and GroupLayout.

    MigLayout solution

    MigLayout is a third-party layout manager, so you need to download and add additional jar to your project.

    package com.zetcode;
    
    import java.awt.EventQueue;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTable;
    import net.miginfocom.swing.MigLayout;
    
    public class MigLayoutEx extends JFrame {
    
        private JComboBox cityBox;
        private JTable filterTable;
    
        public MigLayoutEx() {
    
            initUI();
        }
    
        private void initUI() {
    
            JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
            add(tabbedPane);
    
            filterTable = createTable();
            cityBox = createCityBox();
    
            JPanel pnl = new JPanel(new MigLayout(""));
            pnl.add(new JLabel("City"), "split 2");
            pnl.add(cityBox, "wrap");
    
            pnl.add(new JScrollPane(filterTable));
    
            tabbedPane.addTab("Test", pnl);
            pack();
    
            setTitle("MigLayout example");
            setLocationRelativeTo(null);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        private JTable createTable() {
    
            String[] columnNames = {"Cities"};
            String[][] data = {
                {"NY"}, {"NY"}, {"NY"}, {"NY"}, {"LA"}, {"LA"}, {"Columbia"},
                {"DC"}, {"DC"}, {"DC"}, {"DC"}, {"DC"}, {"DC"}
            };
    
            JTable table = new JTable(data, columnNames);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    
            return table;
        }
    
        private JComboBox createCityBox() {
    
            String[] fillings = {"NY", "LA", "Columbia", "DC"};
            JComboBox box = new JComboBox(fillings);
    
            return box;
        }
    
        public static void main(String[] args) {
    
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    MigLayoutEx ex = new MigLayoutEx();
                    ex.setVisible(true);
                }
            });
        }
    }
    

    MigLayout example

    GroupLayout solution

    GroupLayout is a built-in layout manager, no need to add additional jars.

    package com.zetcode;
    
    import java.awt.EventQueue;
    import javax.swing.GroupLayout;
    import static javax.swing.GroupLayout.Alignment.BASELINE;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTable;
    
    public class GroupLayoutEx extends JFrame {
    
        private JComboBox cityBox;
        private JTable filterTable;
    
        public GroupLayoutEx() {
    
            initUI();
        }
    
        private void initUI() {
    
            JPanel pnl = new JPanel();
            GroupLayout gl = new GroupLayout(pnl);
            pnl.setLayout(gl);
    
            JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
            add(tabbedPane);
    
            JLabel cityLbl = new JLabel("City");
            filterTable = createTable();
            JScrollPane spane = new JScrollPane(filterTable);
            cityBox = createCityBox();
    
            gl.setAutoCreateGaps(true);
            gl.setAutoCreateContainerGaps(true);
    
            gl.setHorizontalGroup(gl.createParallelGroup()
                    .addGroup(gl.createSequentialGroup()
                            .addComponent(cityLbl)
                            .addComponent(cityBox))
                    .addComponent(spane)
            );
    
            gl.setVerticalGroup(gl.createSequentialGroup()
                    .addGroup(gl.createParallelGroup(BASELINE)
                            .addComponent(cityLbl)
                            .addComponent(cityBox))
                    .addComponent(spane)
            );
    
            tabbedPane.addTab("Test", pnl);
            pack();
    
            setTitle("GroupLayout example");
            setLocationRelativeTo(null);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        private JTable createTable() {
    
            String[] columnNames = {"Cities"};
            String[][] data = {
                {"NY"}, {"NY"}, {"NY"}, {"NY"}, {"LA"}, {"LA"}, {"Columbia"},
                {"DC"}, {"DC"}, {"DC"}, {"DC"}, {"DC"}, {"DC"}
            };
    
            JTable table = new JTable(data, columnNames);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    
            return table;
        }
    
        private JComboBox createCityBox() {
    
            String[] fillings = {"NY", "LA", "Columbia", "DC"};
            JComboBox box = new JComboBox(fillings);
    
            return box;
        }
    
        public static void main(String[] args) {
    
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    GroupLayoutEx ex = new GroupLayoutEx();
                    ex.setVisible(true);
                }
            });
        }
    }
    

    I recommend to study both managers and to choose your favourite.