简体   繁体   中英

Prevent Vertical Centering of FlowLayout

I have a JPanel using a FlowLayout layout manager and contains components with different sizes.

EDIT : I want to use the FlowLayout because it allows the components to wrap to a new line when the container is resized and they no longer fit next to each other.

The following image depicts the vertical alignment of the FlowLayout on the different components:

FlowLayout如何对齐组件

How can I modify the FlowLayout to align the top of components as depicted in the following image:

我希望FlowLayout如何对齐组件

Here is a code example of the problem:

JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel flowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
frame.getContentPane().add(flowPanel);

JButton firstComp = new JButton("First");
firstComp.setPreferredSize(new Dimension(200, 300));
flowPanel.add(firstComp);

JButton secondComp = new JButton("Second");
secondComp.setPreferredSize(new Dimension(160, 180));
flowPanel.add(secondComp);

frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

FlowLayout does not by itself support alignment, so unless you actually need the multiple rows behaviour of it, it is better to use a layout manager that supports alignment (such as BoxLayout ). It is possible to somewhat work around the issue though, by using the baseline alignment, that FlowLayout can do:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Align {
    private static final int PREF_HEIGHT = 100;

    Align() {
        JFrame frame = new JFrame("Align test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel bg = new JPanel();
        ((FlowLayout) bg.getLayout()).setAlignOnBaseline(true);
        frame.add(bg);
        JPanel left = new JPanel();
        left.setBackground(Color.BLUE);
        left.setPreferredSize(new Dimension(100, PREF_HEIGHT));
        bg.add(left);

        JPanel right = new JPanel() {
            @Override
            public int getBaseline(int width, int height) {
                return PREF_HEIGHT;
            }
        };
        right.setBackground(Color.GREEN);
        right.setPreferredSize(new Dimension(100, 50));
        bg.add(right);

        frame.pack();
        frame.setVisible(true);
    }

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

Results in:

在此处输入图片说明

This is, unfortunately, anything but flawless. There's firstly the semi magical way of getting the baseline, which depends on the height of the other components in the panel. Secondly, FlowLayout will reserve too much space for the component when it's moved to a row by it's own - it takes the same amount of space as if it was as high as the other panel. (This can be seen if you add more panels after right ). At that point it might be easier to use nested layout for placing the smaller panel than messing with baselines.

Basically, you're better using some other layout manager unless you really can't avoid FlowLayout .

The FlowLayout is the only standard JDK layout manager that supports wrapping components to a new line. (There may be third party layout, like MigLayout that support this).

If you don't like the default functionality then you can customize the layout manager. Here is a simple example that lets the FlowLayout do the default layout and then it resets each component to the top of the line:

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

public class TopFlowLayout extends FlowLayout
{
    @Override
    public void layoutContainer(Container container)
    {
        super.layoutContainer(container);

        Component c = container.getComponent(0);

        int lineStart = getVgap();
        int lineHeight = lineStart + c.getSize().height;

        for (int i = 0; i < container.getComponentCount(); i++)
        {
            c = container.getComponent(i);

            Point p = c.getLocation();
            Dimension d = c.getSize();

            if (p.y < lineHeight) // still on current line
            {
                p.y = lineStart;
                lineHeight = Math.max(lineHeight, lineStart + d.height);
            }
            else  // start a new line
            {
                lineStart = lineHeight + getVgap();
                p.y = lineStart;
                lineHeight = lineStart + d.height;
            }

            p.y = lineStart;
            c.setLocation(p);
        }
    }

    private static void createAndShowGUI()
    {
        TopFlowLayout layout = new TopFlowLayout();
        layout.setAlignment(FlowLayout.LEFT);
        JPanel flowPanel = new JPanel( layout );

        Random random = new Random();

        for (int i = 0; i < 10; i++)
        {
            flowPanel.add( createButton(i + "", random.nextInt(100), random.nextInt(100)) );
        }

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( flowPanel );
        frame.setLocationByPlatform( true );
        frame.setSize(400, 400);
        frame.setVisible( true );
    }

    private static JButton createButton(String text, int width, int height)
    {
        JButton button = new JButton(text);
        Dimension size = new Dimension(width + 50, height + 50);
        button.setPreferredSize(size);

        return button;
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

You may also want to consider extending the Wrap Layout which is also based on the FlowLayout but adds additional functionality.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM