java 如何使用 setLayout(null) 和背景图像将 JPanel 绝对定位在另一个 JPanel 上?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10929931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 03:07:25  来源:igfitidea点击:

How to absolutely position a JPanel over another JPanel with setLayout(null) and a background image?

javaswingjpanellayout-managerabsolutelayout

提问by Exac

I'm working with JFrames in Java, specifically with absolutely positioned elements that need to overlap. I understand that to overlay components, one should make a JPanel (with setOpacity(false);), and position it with either setBounds(x,y,x2,y2);or setPosition(x,y)& setSize(x,y). Unfortunately the panels act like CSS's inline-divs; they take up only the needed amount of room on their line, and do not stack.

我正在使用 Java 中的 JFrames,特别是使用需要重叠的绝对定位元素。我知道要覆盖组件,应该制作一个 JPanel(带有setOpacity(false);),并用setBounds(x,y,x2,y2);setPosition(x,y)&定位它setSize(x,y)。不幸的是,面板就像 CSS 一样inline-divs;他们只占用他们线上所需的空间,并且不堆叠。

This is the code I have so far, but it doesn't seem to act like I'd imagine it would:

这是我到目前为止的代码,但它似乎不像我想象的那样:

class Login extends JFrame {
    private JPanel         backgroundpanel;
    private JPanel         panel;
    private JPanel         panel2;
    private JTextField     usernameBox;
    private JPasswordField passwordBox;
    private JButton        button;
    private int            height = 319;
    private int            width  = 452;
    private ImageIcon      ii     = new ImageIcon("special-window-BG.png");
    private JLabel         image;

    public Login() {
        setLayout(null);
        setTitle("Login");
        setSize(width,height);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(null);

        buildPanel();

        add(backgroundpanel);
        setVisible(true);
    }

    private void buildPanel() {
        usernameBox = new JTextField(20);
        passwordBox = new JPasswordField(20);
        button = new JButton("Login");
        image = new JLabel(ii);

        backgroundpanel = new JPanel();
        panel = new JPanel();
        panel2 = new JPanel();

        backgroundpanel.add(panel);
        backgroundpanel.add(panel2);
        backgroundpanel.add(image);

        panel.setBackground(Color.red);
        panel.setBounds(0, 0, 10, 10);
        panel.setOpaque(false);

        panel2.setBackground(Color.blue);
        panel2.setBounds(0, 0, 10, 10);
        panel2.setOpaque(false);

        panel.add(passwordBox);
        panel2.add(button);

        backgroundpanel.setOpaque(false);
        backgroundpanel.isOptimizedDrawingEnabled();
        backgroundpanel.setBounds(0, 0, width, height);

...cot'd, however unnecessary.

...cot'd,但没有必要。

So basically, I'd like to know how to absolutely position JPanels (or JComponents, if that's simpler) over a JPanel with a background-image.

所以基本上,我想知道如何将 JPanel(或 JComponents,如果更简单)绝对定位在带有背景图像的 JPanel 上。

Thanks for taking a look at this question, I've spent far too much time on this method; the commented-out code extends nearly 500 lines passed what I posted, so I have nowhere else to turn to. The image below shows a crude illustration of what I'm trying to accomplish, I'm not sure if I'actually come close to getting it yet, because sometimes the JComponents seem to disappear as if they're behind the background image, however I'd like to find the simple solution that's most likely right in front of my eyes!

感谢您查看这个问题,我在这个方法上花了太多时间;注释掉的代码扩展了近 500 行,超过了我发布的内容,所以我无处可去。下图显示了我正在尝试完成的粗略说明,我不确定我是否真的接近完成它,因为有时 JComponents 似乎消失了,好像它们在背景图像后面,但是我想找到最有可能就在我眼前的简单解决方案!

http://i.stack.imgur.com/revz8.jpg

http://i.stack.imgur.com/revz8.jpg

回答by Xeon

You're setting setLayout(null)on your JFramebut not on the "backgroundpanel" (which layout is default set to FlowLayout).

您在“背景面板”(布局默认设置为)上进行设置setLayout(null)JFrame但不在“背景面板”上进行设置FlowLayout

You shouldn't set layout of your Loginframe - because it is default set to BorderLayout- and it's ok (you want the "backgroundpanel" to grow to match the parent). Instead setLayout(null)on your JPanel- "backgroundpanel" - to which you add your arbitrary positioned panels.

您不应该设置Login框架的布局- 因为它默认设置为BorderLayout- 并且可以(您希望“背景面板”增长以匹配父项)。取而代之的是setLayout(null)在您的JPanel“背景面板”上添加任意定位的面板。

回答by Andrew Thompson

I'd like to find the simple solution that's most likely right in front of my eyes!

我想找到最有可能就在我眼前的简单解决方案!

Something like this?

像这样的东西?

LoginPanel

登录面板

import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class LoginPanel extends JPanel {

    private static final long serialVersionUID = 1L;

    BufferedImage image;

    LoginPanel(BufferedImage image) {
        super(new GridBagLayout());

        this.image = image;

        JPanel controls = new JPanel(new BorderLayout(15,35));
        controls.setOpaque(false);
        controls.setBorder(new EmptyBorder(110,0,0,0));

        JPanel fields = new JPanel(new GridLayout(0,1,30,30));
        fields.setOpaque(false);
        controls.add(fields, BorderLayout.CENTER);
        fields.add(new JTextField(20));
        fields.add(new JPasswordField(20));

        JPanel button = new JPanel(new GridBagLayout());
        button.setOpaque(false);
        controls.add(button, BorderLayout.PAGE_END);
        button.add(new JButton("Log In"));

        Dimension prefSize = new Dimension(image.getWidth(),image.getHeight());
        setPreferredSize(prefSize);

        add(controls);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
    }

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i.stack.imgur.com/revz8.jpg");
        final BufferedImage image = ImageIO.read(url); 
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                LoginPanel p = new LoginPanel(image);
                JOptionPane.showMessageDialog(null, p);
            }
        });
    }
}