Search code examples
javaswingjscrollpanegridbaglayout

JScrollPane setHorizontalScrollBarPolicy as_needed without resizing content


I noticed an issue with the setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED) resizes the height content when the scrollbar gets added (due to the content going over the width).

The Code...

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

public class TestGui extends JFrame {
    //**************************************************************************************
    //************************************* Constructor ************************************
    //**************************************************************************************
    private TestGui() {
        add(createTopScrollPane(), BorderLayout.NORTH);
        add(createCenterScrollPane(), BorderLayout.CENTER);

        setSize(800,600);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    //**************************************************************************************
    //*********************************** Support Method ***********************************
    //**************************************************************************************
    private static GridBagConstraints setGbc(int gridx, int gridy, int gridWidth, int gridHeight, int ipadx, int ipady, String anchorLocation, double weightx, double weighty, Insets insets, boolean fillCell){
        GridBagConstraints gbc = new GridBagConstraints();

        if (anchorLocation.toUpperCase().equals("NORTHWEST")){
            gbc.anchor = GridBagConstraints.NORTHWEST;
        } else if (anchorLocation.toUpperCase().equals("NORTH")){
            gbc.anchor = GridBagConstraints.NORTH;
        } else if (anchorLocation.toUpperCase().equals("NORTHEAST")){
            gbc.anchor = GridBagConstraints.NORTHEAST;
        } else if (anchorLocation.toUpperCase().equals("WEST")){
            gbc.anchor = GridBagConstraints.WEST;
        } else if (anchorLocation.toUpperCase().equals("EAST")){
            gbc.anchor = GridBagConstraints.EAST;
        } else if (anchorLocation.toUpperCase().equals("SOUTHWEST")){
            gbc.anchor = GridBagConstraints.SOUTHWEST;
        } else if (anchorLocation.toUpperCase().equals("SOUTH")){
            gbc.anchor = GridBagConstraints.SOUTH;
        } else if (anchorLocation.toUpperCase().equals("SOUTHEAST")){
            gbc.anchor = GridBagConstraints.SOUTHEAST;
        } else {
            gbc.anchor = GridBagConstraints.CENTER;
        }

        gbc.gridx = gridx; // column
        gbc.gridy = gridy; // row
        gbc.gridwidth = gridWidth; // number of columns
        gbc.gridheight = gridHeight; // number of rows
        gbc.ipadx = ipadx; // width of object
        gbc.ipady = ipady; // height of object
        gbc.weightx = weightx; // shifts columns to side of set anchor
        gbc.weighty = weighty; // shifts rows to side of set anchor
        gbc.insets = insets; // placement inside cell
        if (fillCell){
            gbc.fill = GridBagConstraints.BOTH;
        }

        return gbc;
    }

    //**************************************************************************************
    //************************************ Panel Methods ***********************************
    //**************************************************************************************
    private JPanel createTopFrame() {
        JPanel pnl = new JPanel();

        Border lineBorder = BorderFactory.createMatteBorder(0, 0, 0, 5, Color.BLUE);
        JLabel lineSplitter = new JLabel();
        lineSplitter.setBorder(lineBorder);

        pnl.setLayout(new GridBagLayout());
        pnl.add(new JLabel("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),setGbc(0,0, 1,1, 0,0,"CENTER", 0, 0, new Insets(10, 10, 10, 10), false));
        pnl.add(new JLabel("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),setGbc(0,1, 1,1, 0,0,"CENTER", 0, 0, new Insets(10, 10, 10, 10), false));
        pnl.add(lineSplitter, setGbc(1,0,1,2,0,0,"CENTER",0,0,new Insets(0,0,0,0),true));
        pnl.add(new JLabel("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),setGbc(2,0, 1,1, 0,0,"CENTER", 0, 0, new Insets(10, 10, 10, 10), false));
        pnl.add(new JLabel("XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"),setGbc(2,1, 1,1, 0,0,"CENTER", 0, 0, new Insets(10, 10, 10, 10), false));

        return pnl;
    }

    private JScrollPane createTopScrollPane(){
        JScrollPane scrollPane = new JScrollPane();
        Border raisedBevel = BorderFactory.createRaisedBevelBorder();
        Border lineBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(224,224,224));
        Border loweredBevel = BorderFactory.createLoweredBevelBorder();
        Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
        Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);

        //scrollPane.setPreferredSize(new Dimension(0, 160));
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
        scrollPane.setBorder(compoundFinal);
        scrollPane.getViewport().setView(createTopFrame());
        return scrollPane;
    }

    private JScrollPane createCenterScrollPane(){
        JScrollPane scrollPane = new JScrollPane();
        Border raisedBevel = BorderFactory.createRaisedBevelBorder();
        Border lineBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(224,224,224));
        Border loweredBevel = BorderFactory.createLoweredBevelBorder();
        Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
        Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);

        scrollPane.setBorder(compoundFinal);
        return scrollPane;
    }

    //**************************************************************************************
    //************************************ Start Program ***********************************
    //**************************************************************************************
    public static void main(String[] args) {
        new TestGui();
    }
}

Note: If I use setPreferredSize, it adds spacing between borders when maximizing the window, and I don't want that.

As you can see, the 2nd row gets cut off, is there anyway to have it not resize (other than setting it to HORIZONTAL_SCROLLBAR_ALWAYS, which still shows the bar if you maximize the window)?


Solution

  • You need to override the methothd getPreferredSize() of your scroll pane. Also you need provide revalidation when component changed.

    private TestGui() {
        add(createTopScrollPane(), BorderLayout.NORTH);
        add(createCenterScrollPane(), BorderLayout.CENTER);
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        revalidate();
                        repaint();
                    }
                });
            }
        });
    
        setSize(800,600);
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    // another stuff
    
    private JScrollPane createTopScrollPane(){
        JScrollPane scrollPane = new JScrollPane() {
            @Override
            public Dimension getPreferredSize() {
                Dimension size = super.getPreferredSize();
                if (getHorizontalScrollBar() != null && getHorizontalScrollBar().isVisible()) {
                    size.height += getHorizontalScrollBar().getHeight();
                }
                return size;
            }
        };
        Border raisedBevel = BorderFactory.createRaisedBevelBorder();
        Border lineBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, new Color(224,224,224));
        Border loweredBevel = BorderFactory.createLoweredBevelBorder();
        Border compoundSetup = BorderFactory.createCompoundBorder(raisedBevel, lineBorder);
        Border compoundFinal = BorderFactory.createCompoundBorder(compoundSetup, loweredBevel);
    
        //scrollPane.setPreferredSize(new Dimension(0, 160));
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
        scrollPane.setBorder(compoundFinal);
        scrollPane.getViewport().setView(createTopFrame());
        return scrollPane;
    }