Search code examples
javaswingjframevertical-alignment

vertically aligned components move together at runtime


I have two components (a textfield and a jList). When they are vertically aligned, they move together at runtime.

enter image description hereenter image description here

As in the pictures there is a lblIcon on the left of the textfield and in initcomponents method below code is working.

lblIcon.setIcon(new ImageIcon(new ImageIcon("icons/yeniNotBtn.png").getImage().getScaledInstance(25, 25, Image.SCALE_DEFAULT)));

When it works textfield floats right a bit and jList moves right too. I think there is something about layout but i cant figure out. It would be good to hear a general advice about layouts. I am a newbie. Thanks in advance.


Solution

  • Generating layout's a little bit of a black art and voodoo, which typically requires a reasonable about of knowledge of the available layout managers.

    One layout manager won't solve all your problems (all of the times) and you tend to resort to using a series of layout managers, each focusing on a particular part of the UI to solve a particular problem.

    For example, your layout could be solved by place the JLabel and JTextField in a JPanel that uses a FlowLayout, then place that, along with the JList onto another JPanel which is using a BorderLayout.

    The approach you take will depend on the bigger picture and would require much more information then is available in your question.

    The most important advice I can give is:

    • Try a few different things, use different layouts
    • Break the UI down into logic units of work and design the layout for those parts, placing them within their own containers as you need to. For me, this also highlights units of work and helps me generate my class hierarchy, rather then ending up with one monolithically class which is responsible for managing the state of a dozen or more components
    • Avoid relying on form editors, they don't teach you the techniques and ideas you will need to truly build complex UIs. Don't get me wrong, I use them in my day to day work, but I spend 10+ years coding my UI's by hand, so I'm not afraid to make a half dozen or so "forms" to generate a single "unified" interface. GroupLayout is also a complete pain, I've seen it fall apart more times then I'd like to recall and I tend to avoid it in favour of other solutions.
    • Use a form editor to experiment with different layout managers or combination of layout managers and their properties, they give quick, visual feedback when you're trying to solve a particular problem, but until you're comfortable with coding a layout by hand, I'd avoid relying on them

    The example below uses a GridBagLayout, which is one of the more flexible but also one of the more complex layout managers, but it allows you to do some pretty amazing things.

    Layout

    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextField;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TestLayout {
    
        public static void main(String[] args) {
            new TestLayout();
        }
    
        public TestLayout() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public TestPane() {
                setLayout(new GridBagLayout());
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.insets = new Insets(8, 8, 2, 8);
                add(new JLabel(new ImageIcon(getClass().getResource("/gender_neutral_user.png"))), gbc);
                gbc.gridx++;
                gbc.insets = new Insets(8, 2, 4, 8);
                gbc.fill = GridBagConstraints.HORIZONTAL;
                add(new JTextField(10), gbc);
    
                JList list = new JList();
                list.setVisibleRowCount(10);
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                gbc.gridx = 0;
                gbc.gridy++;
                gbc.insets = new Insets(4, 8, 8, 8);
                gbc.fill = GridBagConstraints.BOTH;
                add(new JScrollPane(list), gbc);
            }
    
        }
    
    }
    

    Have a look at Laying Out Components Within a Container, How to Use GridBagLayout, How to Use BorderLayout and How to Use FlowLayout for some more details