Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swing: vertically stacked components without MigLayout

I finally got the behavior I want for vertically stacking components that have a preferred height that changes with time. But I needed to use MigLayout.

Is there a way to do this w/o MigLayout? (It's for a library and I don't want to force the dependency unless I have to)

Here's the behavior I'm looking for (which my test program achieves):

enter image description here

In vertical order, there's a resize button, "empty space" (well, a JLabel marked as such), a red rectangle, and a green square. The resize button has fixed height. The red square has a random size that can change at arbitrary times. The green square sets its preferred height to match its width, and I want to expand its width to fill the container. The empty space expands horizontally and vertically to fill the remaining space in the container.

What would work instead of MigLayout?

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;

public class AutoResizeDemo extends JPanel
{   
    static private class ResizingPanel extends JPanel
    {
        final private Color color;

        private Dimension dpref = new Dimension(100,100);

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int w = getWidth();
            int h = getHeight();
            g.setColor(this.color);
            g.fillRect(0, 0, w, h);
            g.setColor(Color.BLACK);
            g.drawRect(0, 0, w-1, h-1); 
            String s = this.dpref.width+"x"+this.dpref.height;
            FontMetrics fm = g.getFontMetrics();
            g.drawString(s, 0, fm.getHeight());
        }

        public ResizingPanel(Color color, boolean isSquare)
        {
            this.color = color;
            if (isSquare)
            {
                addComponentListener(new ComponentAdapter() {
                    @Override public void componentResized(ComponentEvent e) {
                        doResize(getWidth(), getWidth());
                    }               
                });
            }
        }

        @Override public Dimension getPreferredSize() {
            return this.dpref;
        } 

        public void doResize(int w, int h)
        {
            this.dpref = new Dimension(w, h);
            revalidate();
        }
    }

    public AutoResizeDemo()
    {
        super(new MigLayout("","[grow]",""));
        setPreferredSize(new Dimension(200, 800));

        final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
        ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
        JPanel buttonPanel = new JPanel(new FlowLayout());

        final Random rand = new Random();
        addButton(buttonPanel, "resize",new Runnable() {
            @Override public void run() {
                resizingPanelRandom.doResize(
                        rand.nextInt(100)+100,
                        rand.nextInt(100)+100
                        );
            }           
        });
        add(buttonPanel, "wrap");
        JLabel spaceLabel = new JLabel("empty space");
        spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        add(spaceLabel, "push, grow, wrap");
        add(resizingPanelRandom, "wrap");
        add(resizingPanelSquare,"pushx, growx, wrap");
    }

    private void addButton(JPanel panel, String title, final Runnable r) {
        JButton button = new JButton(title);
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                r.run();
            }           
        });
        panel.add(button);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame(AutoResizeDemo.class.getSimpleName());
        frame.setContentPane(new AutoResizeDemo());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

}
like image 295
Jason S Avatar asked Feb 06 '26 08:02

Jason S


1 Answers

Use a BoxLayout.

You would use Box.createVerticalGlue() for the empty space.

BoxLayout respects the maximum size of a component, so you would probably need to override the getMaximumSize() method to return the preferred size for the red and green boxes.

For the green box you would also need to Override getPreferredSize() to keep the height in sync with the width.

like image 177
camickr Avatar answered Feb 07 '26 21:02

camickr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!