Home > Enterprise >  Adding JScrollPane to a JFrame
Adding JScrollPane to a JFrame

Time:02-02

I want to add JPanel containers to a JScrollPane and add this scroll pane to a JFrame. But when I add multiple panels to the scroll pane this happens. The gap between the scroll pane and the top bar increases. I use BoxLayout as layout manager for all the components that I use.

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class ScrollPaneGUI {

    public ScrollPaneGUI() {
        initGUI();
    }

    private void initGUI() {
        JScrollPane scroll = new JScrollPane();

        String title = "Title";
        Border eBorder = BorderFactory.createEtchedBorder();
        Border eTitledBorder = BorderFactory.createTitledBorder(eBorder, title);

        JPanel panel = new JPanel();

        BoxLayout boxlayout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);

        panel.setLayout(boxlayout);
        JButton button1 = new JButton("Button1");

        panel.add(Box.createRigidArea(new Dimension(0, 5)));
        panel.add(button1);
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        scroll.setViewportView(panel);
        scroll.setBorder(eTitledBorder);
        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        panel.add(Box.createRigidArea(new Dimension(0, 5)));
        panel.add(new JButton("Button2"));
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        scroll.updateUI();

        JFrame frame = new JFrame();
        frame.getContentPane().add(scroll, BorderLayout.CENTER);
        frame.setSize(600, 600);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                new ScrollPaneGUI();
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

This is the desired layout:

enter image description here

CodePudding user response:

enter image description here

Here is my take on laying out this GUI. Some notes:

  • Rather than use a BoxLayout in the JScrollPane it puts a GridLayout in the PAGE_START of a BorderLayout. This is fine for when it's OK to stretch the elements in the scroll pane to the full width of the GUI. Stick to a BoxLayout (which I rarely use) or a GridBagLayout if it's necessary to keep the elements at their preferred size.
  • This strategy of layout is basically 'divide and conquer' in that it starts with the smallest sub-divisions of the GUI (e.g. the FlowLayout for the buttons) and then adds those containers to larger containers with different layouts and constraints (e.g. adding that button panel to the LINE_END of a BorderLayout - to push I to the right of the GUI) as needed for the overall effect.
  • I'd also consider using a JList (using a panel for the renderer) in the scroll pane. It depends on the use as to whether that makes sense.
  • Note that this code is an MRE. An MRE should have everything that's needed (including imports, a class structure and the main method) for another person to compile and run the code.

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;

// ref: https://stackoverflow.com/a/70934802/418556
public class ScrollPaneTestGUI {

    int elementCount = 1;
    JPanel elementsPanel = new JPanel(new GridLayout(0,1,2,2));

    public ScrollPaneTestGUI() {
        initGUI();
    }

    private void initGUI() {
        // this will become the content pane of the frame
        JPanel gui = new JPanel(new BorderLayout(4,4));
        gui.setBorder(new EmptyBorder(4,4,4,4));

        JPanel pageStartPanel = new JPanel(new BorderLayout(2,2));
        gui.add(pageStartPanel, BorderLayout.PAGE_START);
        pageStartPanel.add(new JLabel("LINE START label"), BorderLayout.LINE_START);
        // default flow layout is good for this one
        JPanel buttonPanel = new JPanel();
        pageStartPanel.add(buttonPanel, BorderLayout.LINE_END);
        buttonPanel.add(new JButton("Does Nothing"));
        Action addToScrollAction = new AbstractAction("Add to scrollPane") {
            @Override
            public void actionPerformed(ActionEvent e) {
                elementsPanel.add(getPanelForScroll());
                elementsPanel.revalidate();
            }
        };
        JButton addToScrollButton = new JButton(addToScrollAction);
        buttonPanel.add(addToScrollButton);

        JPanel scrollPanel = new JPanel(new BorderLayout());
        scrollPanel.add(elementsPanel, BorderLayout.PAGE_START);
        gui.add(new JScrollPane(scrollPanel,
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
        );
        for (int ii=0; ii<2; ii  ) {
            elementsPanel.add(getPanelForScroll());
        }

        JFrame frame = new JFrame("ScrollPane GUI");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setContentPane(gui);
        frame.pack(); // sets the GUI to the exact size needed
        frame.setMinimumSize(frame.getSize());
        frame.setVisible(true);
    }

    private JPanel getPanelForScroll() {
        JPanel p = new JPanel();
        p.add(new JLabel("Panel "   elementCount  ));
        p.setBorder(new EmptyBorder(10,200,10,200));
        p.setBackground(Color.GREEN);
        return p;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                new ScrollPaneTestGUI();
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
  •  Tags:  
  • Related