Preventing Overlay Layout from shifting background

2019-07-31 12:37发布

问题:

I have a JFrame with a panel on it with Overlay Layout because I want to set a JLabel with an image as the background and put stuff over top of it. I set the size of the frame equal to the size of the image and when I put only that on it fits perfectly, but if I add anything over top of it it shifts the image to the right by the width of the component that I add and cuts it off to the right. It does this even though the component isn't in the region that is shifted over. The component is to the right and its properly displayed over the label but the image is still shifted over.

    import java.awt.*;       
    import java.*;
    import java.io.*;
    import javax.swing.*;
    import javax.swing.text.*;
    import java.awt.event.*;
    import javax.imageio.*;
    import java.awt.image.*;

    public class MainScreen extends JFrame{  
        JButton button;
        JPanel backgroundPanel, p, panel;

        public MainScreen(ArrayList<Character> c){                  
        JLabel label = new JLabel(new ImageIcon("house.jpg"));
        button = new JButton("Button");

        backgroundPanel = new JPanel();
        p = new JPanel();
        panel = new JPanel();

        p.add(button);  
        panel.add(p);

        panel.setOpaque(false);
        p.setOpaque(false); 

        LayoutManager overlay = new OverlayLayout(backgroundPanel);
        backgroundPanel.setLayout(overlay);

        backgroundPanel.add(panel); 
        backgroundPanel.add(label);        

        add(backgroundPanel);      
        setLocationRelativeTo(null);                 
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(false);
        setSize(1200, 700);
        setVisible(true);   
        }

        public static void main(String[] args){
        MainScreen ms = new MainScreen(new ArrayList<Character>());
        }
    }

回答1:

but if I add anything over top of it it shifts the image to the right by the width of the component that I add and cuts it off to the right

You need to play with the alignmentX/Y properties of the two components to get your desired layout.

Start by setting them all to 0.5f.

Here is a little demo program that allows you to change the properties to see the effect:

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

public class OverlayLayoutTest extends JPanel
    implements ActionListener
{
    JPanel green;
    JPanel red;
    JLabel greenLabel;
    JLabel redLabel;
    JComboBox  greenAlignmentX;
    JComboBox  greenAlignmentY;
    JComboBox  redAlignmentX;
    JComboBox  redAlignmentY;

    public OverlayLayoutTest()
    {
        setLayout( new BorderLayout(10, 10) );
        add(createNorthPanel(), BorderLayout.NORTH);
        add(createCenterPanel(), BorderLayout.CENTER);
        add(createSouthPanel(), BorderLayout.SOUTH);
    }

    private JPanel createNorthPanel()
    {
        JPanel panel = new JPanel();

        panel.add( new JLabel("Green:") );
        greenLabel = new JLabel();
        panel.add( greenLabel );

        panel.add( new JLabel("Red:") );
        redLabel = new JLabel();
        panel.add( redLabel );

        return panel;
    }

    private JPanel createCenterPanel()
    {

        JPanel panel = new JPanel();
        panel.setLayout( new OverlayLayout(panel) );
        panel.setBackground( Color.ORANGE );
        panel.setPreferredSize( new Dimension(200, 200) );

        red = new JPanel();
        red.setBackground( Color.RED );
        red.setPreferredSize( new Dimension(50, 50) );
        red.setMaximumSize( red.getPreferredSize() );
        red.setMinimumSize( red.getPreferredSize() );
        panel.add( red );

        green = new JPanel();
        green.setBackground( Color.GREEN );
        green.setPreferredSize( new Dimension(100, 100) );
        green.setMaximumSize( green.getPreferredSize() );
        green.setMinimumSize( green.getPreferredSize() );
        panel.add( green );

        JPanel wrap = new JPanel();
        wrap.add( panel );
        return wrap;
    }

    private JPanel createSouthPanel()
    {
        JPanel panel = new JPanel( new GridLayout(1, 0, 10, 10) );

        JPanel green = new JPanel(new GridLayout(0, 2, 5, 5) );
        green.setBorder( new TitledBorder("Green Alignment") );
        green.add( new JLabel("X Alignment:") );
        greenAlignmentX = createComboBox();
        green.add( greenAlignmentX );
        green.add( new JLabel("Y Alignment:") );
        greenAlignmentY = createComboBox();
        green.add( greenAlignmentY );
        panel.add( green );

        JPanel red = new JPanel(new GridLayout(0, 2, 5, 5) );
        red.setBorder( new TitledBorder("Red Alignment") );
        red.add( new JLabel("X Alignment:") );
        redAlignmentX = createComboBox();
        red.add( redAlignmentX );
        red.add( new JLabel("Y Alignment:") );
        redAlignmentY = createComboBox();
        red.add( redAlignmentY );
        panel.add( red );

        JButton reset = new JButton("Reset Alignment");
        reset.addActionListener( this );
        panel.add( reset );


        return panel;
    }

    public void actionPerformed(ActionEvent e)
    {
        green.setAlignmentX( ((Float)greenAlignmentX.getSelectedItem()) );
        green.setAlignmentY( ((Float)greenAlignmentY.getSelectedItem()) );
        red.setAlignmentX( ((Float)redAlignmentX.getSelectedItem()) );
        red.setAlignmentY( ((Float)redAlignmentY.getSelectedItem()) );
        JPanel parent = (JPanel)green.getParent();
        parent.revalidate();
/*
        System.out.print(green.getAlignmentX() + " : ");
        System.out.print(green.getAlignmentY() + " : ");
        System.out.print(red.getAlignmentX() + " : ");
        System.out.print(red.getAlignmentY() + " : ");
        System.out.println();
*/
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                greenLabel.setText( green.getLocation().toString() );
                redLabel.setText( red.getLocation().toString() );
            }
        });

    }

    private JComboBox createComboBox()
    {
        JComboBox<Float> comboBox = new JComboBox<Float>();

        comboBox.addItem( new Float(0f) );
        comboBox.addItem( new Float(0.25f) );
        comboBox.addItem( new Float(0.5f) );
        comboBox.addItem( new Float(0.75f) );
        comboBox.addItem( new Float(1.0f) );
        comboBox.setSelectedItem(0.5f);

        return comboBox;
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("OverlayLayoutTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new OverlayLayoutTest() );
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

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

Another option is to just set the layout of the JLabel to whatever you want (BorderLayout, GridBagLayout, FlowLayout). Then you can add components directly to the label, like you would for any panel. Any component you add must be fully contained within the label. This will give you more flexibility than using the OverlayLayout.