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

Ant*_*ang 2 java swing frame layer

我想把我的背景图像放在这个框架的最底部,按钮放在顶部.但是我在下面写的代码不起作用.任何人都可以看到问题出在哪里?

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

请忽略评论行.(我只是在猜测,并希望它们可以工作,但它们显然没有.)

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();
}
Run Code Online (Sandbox Code Playgroud)

Hov*_*els 5

问题/解决方案:

  • setLocation(...)setBounds(...)类型的呼叫被大部分布局管理器忽略.使用它们的唯一方法是将容器的布局设置为null.setLayout(null);
  • 但话虽如此,虽然null布局和setBounds()Swing新手似乎是创建复杂GUI的最简单和最好的方法,但是你创建的Swing GUI越多,你在使用它们时会遇到更严重的困难.当GUI调整大小时,它们不会调整组件的大小,它们是增强或维护的皇室女巫,当它们放置在滚动窗格中时它们会完全失败,当它们在所有平台上观看时或者与原始平台不同的屏幕分辨率时它们看起来很糟糕.
  • 总而言之 - 不要这样做,不要使用null布局或setBounds,而是嵌套JPanels,每个都使用自己的布局管理器,从而创建易于维护和体面的GUI.
  • 如果你想让一个图像在后台,然后在JPanel中绘制它,你可以用它作为GUI组件的容器,在JPanel的paintComponent(Graphics g)方法中绘制它,就像在这个网站上许多类似的问题所证明的那样 - 我我会在一秒钟内找到你的一些.
  • 如果您在此图像绘制JPanel的顶部添加任何JPanels,请确保您可以通过调用setOpaque(false)这些覆盖的JPanel 来查看它们.否则你将掩盖图像.
  • 只需要一个JFrame时,您的代码就有两个JFrame.摆脱你不使用的那个.
  • setVisible(true)在将组件添加到GUI之前,您在JFrame上调用太早 - 不要.只有在将所有内容添加到GUI后才能调用它,所以所有显示都可以
  • 您正在创建两个JLayedPanes,并通过将它们添加到JFrame完全覆盖它们,而不了解JFrame的BorderLayout如何处理添加的组件.
  • 我建议您甚至不使用一个JLayeredPane,而是如上所述在JPanel中绘制,并将其用作容器.
  • 当按下播放按钮时,您的代码看起来正在打开一个全新的GUI窗口,如果是这样,这可能会让用户快速烦恼.考虑使用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();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)