5

im trying to build a GUI for my Java application. I dynamically add JPanels, which are a "row" in my GUI. Under the List of the Panels there is a button to add a new Panel. As the List grows, it reaches the end of the parent Container. Then I want to use scrollbars, so that the user is able to reach every panel in the List.

So far I experimented with JScrollPanes and Layouts but I have no Idea how to get it working.

Can you give me some advice?

this.setLayout(new BorderLayout());
JPanel listContainer = new JPanel();
listContainer.setLayout(BoxLayout(listContainer, BoxLayout.Y_AXIS);

this.add(new JScrollPane(listContainer), BorderLayout.CENTER);
this.add(new JButton(), BorderLayout.PAGE_END);

//then i add panels to the listContainer. this wont work, when the space is complettly used there is no scrollbar.
Horstinator
  • 548
  • 1
  • 5
  • 18

2 Answers2

13

It's difficult to assertain from your code snippet exactly where you might be having problems.

enter image description here

public class DynamicPanelList {

    public static void main(String[] args) {
        new DynamicPanelList();
    }

    public DynamicPanelList() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JPanel mainList;

        public TestPane() {
            setLayout(new BorderLayout());

            mainList = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weightx = 1;
            gbc.weighty = 1;
            mainList.add(new JPanel(), gbc);

            add(new JScrollPane(mainList));

            JButton add = new JButton("Add");
            add.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JPanel panel = new JPanel();
                    panel.add(new JLabel("Hello"));
                    panel.setBorder(new MatteBorder(0, 0, 1, 0, Color.GRAY));
                    GridBagConstraints gbc = new GridBagConstraints();
                    gbc.gridwidth = GridBagConstraints.REMAINDER;
                    gbc.weightx = 1;
                    gbc.fill = GridBagConstraints.HORIZONTAL;
                    mainList.add(panel, gbc, 0);

                    validate();
                    repaint();
                }
            });

            add(add, BorderLayout.SOUTH);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }
}

You really need to provide a SSCCE which would allow us to diagnose the problems you are having.

Personally, and this will depend on you requirements, a better layout manager might be VerticalLayout from SwingLabs SwingX libraries.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • +1. Funny how we came to almost the same conclusion and even almost the same example ;-) – Guillaume Polet Jan 30 '13 at 23:53
  • @GuillaumePolet Experience guides :D +1 to you answer as well. – MadProgrammer Jan 30 '13 at 23:54
  • Is it possible to break text in JLabel as it grows horizontally. – digz6666 Dec 04 '16 at 09:48
  • @digz6666 Generally, yes, there are several ways, personally, I wrap the text in HTML tags – MadProgrammer Dec 04 '16 at 10:01
  • @MadProgrammer Any other way than HTML tags? I've asked the question here: http://stackoverflow.com/questions/40957446/make-jlabel-text-breaks-in-gridbaglayout – digz6666 Dec 04 '16 at 10:03
  • @digz6666 Not really, for [example](http://stackoverflow.com/questions/26747610/how-to-format-jlabel-jtextfield-so-text-wraps/26747718#26747718) and [example](http://stackoverflow.com/questions/14737810/jlabel-show-longer-text-as-multiple-lines/14738193#14738193). Alternatively, you could strip down a `JTextArea`, make it read only and use it instead – MadProgrammer Dec 04 '16 at 10:12
4

You probably forgot to call revalidate() on your listContainer (and you made a bunch of syntax errors). BoxLayout does not do a great job in my opinion, but that is not the matter here.

Here is a small demo code which seems to work quite well:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestScollpane {
    private int i;
    private JPanel listContainer;

    private void initUI() {
        final JFrame frame = new JFrame(TestScollpane.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        listContainer = new JPanel();
        listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));

        frame.add(new JScrollPane(listContainer), BorderLayout.CENTER);
        JButton button = new JButton("Add");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                final JPanel newPanel = new JPanel();
                newPanel.add(new JLabel("Label " + i++));
                listContainer.add(newPanel);
                listContainer.revalidate();
                // Scroll down to last added panel
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        newPanel.scrollRectToVisible(newPanel.getBounds());
                    }
                });
            }
        });
        frame.add(button, BorderLayout.PAGE_END);

        frame.setSize(300, 200);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestScollpane().initUI();
            }
        });
    }
}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • Okay, your demo works for me, too. But i dont see what i did differently in my code. As far as i can tell i did everything similar to your example: http://nopaste.info/719313cd1b.html – Horstinator Jan 31 '13 at 11:20
  • @Horstinator Hard to tell without seeing what you have in `ShowPanel`, `ShowFrame` and `Show`. – Guillaume Polet Jan 31 '13 at 11:47
  • I uploaded the whole source to my server, if its not too much asked you could take a look at it: http://176.28.8.235/shows.tar – Horstinator Jan 31 '13 at 13:32
  • @Horstinator Rookie mistake: you have `this.add(new JScrollPane(panelContainer), BorderLayout.CENTER);` which wraps panelContainer in a JScrollPane and add the scrollPane to the `MainPanel`. Later on, you have: `this.add(panelContainer);` which removes panelContainer from the scrollpane and adds it directly to the MainPanel. Drop the second call and it will work as expected. – Guillaume Polet Jan 31 '13 at 13:40
  • geez thanks! didnt see that. i tested so much, i guess i got confused. Thanks for the help! – Horstinator Jan 31 '13 at 14:13
  • 1
    @Horstinator the usage of a debugger comes pretty handy in those situation. You can see immediately the parenting issue. – Guillaume Polet Jan 31 '13 at 14:15