javaswingjscrollpane

JScrollPane with GridLayout Panel


I have a JFrame (frame) with a JScrollPane. The JScrollPane contains my ContainerJComponent (DebugPanel). This ContainerJComponent contains JComponentItems (DebugItem). This is an abstracted problem from my project for the purpose of understanding.

FRAME I create a JFrame. The For loop is used to create sample items for the panel.

public class DebugGUI {
    
    private static JFrame frame;
    private static DebugPanel panel = new DebugPanel();
    
    public static void generateGUI() {
        
        
        frame = new JFrame();
        
        
        for (int i = 1; i < 20; i++) {
            panel.addItem(0.2);
        }
        
        frame.setContentPane(new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
                JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
        frame.setVisible(true);
    }

}

PANEL For the sake of simplicity, the panel in this example takes up the entire JFrame area. The panel serves as a container, which in turn contains items - in this example the 20 items added via the For loop.

public class DebugPanel extends JComponent {
    
    private static final long serialVersionUID = -7384855597611519487L;
    private LinkedList<DebugItem> items = new LinkedList<>();
    
    public DebugPanel() {
        GridLayout layout = new GridLayout();
        layout.setRows(1);
        this.setLayout(layout);
    }
    
    public void addItem(double widthRatio) {
        DebugItem item = new DebugItem(widthRatio);
        items.add(item);
        add(item);
    }


    @Override
    protected void paintComponent(Graphics g) {
        this.setPreferredSize(new Dimension((int) getPreferredSize().getWidth(), getParent().getHeight()));
        super.paintComponent(g);
        for (DebugItem item : items) {
            item.resize((int) getPreferredSize().getHeight());
        }
        
    }
}

ITEMS The items should draw something in the panel. In my example, this is a rectangle. This rectangle should fill the full height of the panel and maintain a certain width in relation to the height.

public class DebugItem extends JComponent {

    private static final long serialVersionUID = 1630268284249666775L;
    private double widthRatio;
    private int width;
    
    DebugItem(double widthRatio) {
        this.widthRatio = widthRatio;
    }
    
    void resize(int height) {
        width = (int) (height * widthRatio);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        // TODO Auto-generated method stub
        super.paintComponent(g);
        g.setColor(Color.RED);
        g.drawRect(0, 0, width, getParent().getHeight());
        
    }
}

However, the ratio to be drawn is not taken into account. The JScrollPane is useless because all items always fill the panel. Does anyone know a hint? The classes work in isolation. The code is complete except for the reference to the package and the imports. Simply call generateGUI() in the main method.


Solution

  • It seems to me that you want a panel that completely fills the height of a JScrollPane and the width of the components added to that panel is related to the height. Therefore you will never have a vertical scrollbar.

    If so then I think you can use the Scrollable Panel. This will allow the panel to fill the height of the scroll pane. The width will be determined based on the number of components added and the width ratio. A horizontal scrollbar will appear as required.

    Basic example:

    import java.awt.*;
    import java.util.*;
    import javax.swing.*;
    
    public class DebugGUI {
    
        public static void main(String[] args)
        {
            JFrame frame = new JFrame();
    
            ScrollablePanel panel = new ScrollablePanel( new GridLayout(1, 0) );
            panel.setScrollableHeight( ScrollablePanel.ScrollableSizeHint.FIT );
    
            for (int i = 0; i < 5; i++) {
                panel.add( new DebugItem(0.2) );
            }
    
            frame.setContentPane(new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
                    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
            frame.setSize(400, 400);
            frame.setVisible(true);
        }
    
        static class DebugItem extends JComponent {
    
            private double widthRatio;
    
            DebugItem(double widthRatio) {
                this.widthRatio = widthRatio;
            }
    
            public Dimension getPreferredSize()
            {
                Dimension parent = super.getSize();
    
                return new Dimension((int)(parent.height * widthRatio), parent.height);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                // TODO Auto-generated method stub
                super.paintComponent(g);
                g.setColor(Color.RED);
                g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
            }
        }
    
    }