如何将我的背景图片放在底部

how to put my background image at the bottom

我想把我的背景图片放在这个框架的最底部,按钮放在最上面。但是我在下面写的代码不起作用。谁能看出问题出在哪里?

另一件事是,即使我设置了按钮的位置,它仍然显示在框架的顶部中心。

请忽略评论行。 (我只是在猜测,并希望它们会起作用,但它们显然没有。)

public class Menu extends JFrame{
private JLayeredPane pane;
private JLayeredPane pane2;

public Menu(){
    final JFrame f = new JFrame("Chinese Chess");


    JButton play = new JButton("Play vs. AI");

    f.setLayout(new FlowLayout());
    f.setLocationRelativeTo(null);
    f.setSize(800, 800);
    f.setVisible(true);
    f.setResizable(false);
    //f.pack(); 

    pane = new JLayeredPane();
    pane2 = new JLayeredPane();
    f.add(pane);
    f.add(pane2);


    //background image
    JLabel background = new JLabel(new ImageIcon("res/img/background.png"));
    background.setLocation(0, 0);
    background.setSize(800, 800);
    pane.add(background, JLayeredPane.FRAME_CONTENT_LAYER);
    pane2.add(play, JLayeredPane.DEFAULT_LAYER);
    //pane.moveToBack();

    //button PlayAI
    play.setLocation(500,500);
    play.setPreferredSize(new Dimension(100,50));
    //f.setLayout(new FlowLayout());

    //frame menu
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //f.getContentPane().add(play);


    play.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
            new PlayAI();
        }
    });
}

public static void main(String[] args){
    new Menu();
}

Problems/Solutions:

    大多数布局管理器会忽略
  • setLocation(...)setBounds(...) 类型的调用。使用它们的唯一方法是通过 .setLayout(null);
  • 将容器的布局设置为 null
  • 但话虽如此,虽然空布局和 setBounds() 对于 Swing 新手来说似乎是创建复杂 GUI 的最简单和最好的方法,但您创建的 Swing GUI 越多,您遇到的困难就越严重 运行 使用它们时。它们不会在 GUI 调整大小时调整组件的大小,它们是皇家 来增强或维护的,当放置在滚动窗格中时它们会完全失败,当在所有平台或不同的屏幕分辨率上查看时它们看起来很糟糕从原来的。
  • 所以总而言之——不要这样做,不要使用空布局或 setBounds,而是嵌套 JPanel,每个 JPanel 使用自己的布局管理器,从而创建易于维护且体面的 GUI。
  • 如果您希望图像在背景中,则将其绘制在用作 GUI 组件容器的 JPanel 中,方法是在 JPanel 的 paintComponent(Graphics g) 方法中绘制它,如许多示例中所示此站点上有许多类似的问题 -- 我马上会为您找到一些我的问题。
  • 如果您在此图像绘制 JPanel 之上添加任何 JPanel,请确保您可以通过在这些重叠的 JPanel 上调用 setOpaque(false) 来透视它们。否则你会掩盖图像。
  • 您的代码有两个 JFrame,而实际上只需要一个。摆脱你不使用的那个。
  • 您在 JFrame 上调用 setVisible(true) 太早,在组件添加到 GUI 之前 -- 不要。仅在将所有内容添加到 GUI 后调用它,以便所有显示正常。
  • 您正在创建两个 JLayedPanes,并通过将它们添加到 JFrame 而完全由另一个覆盖,而不了解 JFrame 的 BorderLayout 如何处理添加的组件。
  • 我建议您甚至不使用一个 JLayeredPane,而是如上所述在 JPanel 中绘制,并将其用作您的容器。
  • 当按下播放按钮时,您的代码看起来会打开一个全新的 GUI window,如果是这样,这很快就会让用户感到厌烦。考虑使用 CardLayout.
  • 交换视图

例如:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

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

// extend JPanel so you can draw to its background
@SuppressWarnings("serial")
public class Menu2 extends JPanel {
    private BufferedImage bgImage = null; // our background image
    private JButton playButton = new JButton(new PlayVsAiAction("Play Vs. AI", KeyEvent.VK_P));

    public Menu2(BufferedImage bgImage) {
        this.bgImage = bgImage;

        setLayout(new GridBagLayout());  // center our button
        add(playButton);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (bgImage != null) {
            g.drawImage(bgImage, 0, 0, this);
        }
    }

    // to size our GUI to match a constant or the image.
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }

        // if you want to size it based on the image
        if (bgImage != null) {
            int width = bgImage.getWidth();
            int height = bgImage.getHeight();
            return new Dimension(width, height);            
        } else {
            return super.getPreferredSize();
        }

        // if you want to size the GUI with constants:
        // return new Dimension(PREF_W, PREF_H);
    }

    private class PlayVsAiAction extends AbstractAction {
        public PlayVsAiAction(String name, int mnemonic) {
            super(name); // have our button display this name
            putValue(MNEMONIC_KEY, mnemonic); // alt-key to press button
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO code to start program

        }
    }

    private static void createAndShowGui() {
        BufferedImage img = null;
        String imagePath = "res/img/background.png";
        try {
            // TODO: fix this -- use class resources to get image, not File 
            img = ImageIO.read(new File(imagePath));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        Menu2 mainPanel = new Menu2(img);

        JFrame frame = new JFrame("Chinese Chess");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            createAndShowGui();
        });
    }
}

除了上述解决方案...您应该以这种方式创建和启动您的 swing 应用程序:

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}

private static void createAndShowGUI() {
    // Instantiate your JFrame and show it 
}