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

时间:2016-04-05 15:03:49

标签: 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();
}

2 个答案:

答案 0 :(得分:5)

问题/解决方案:

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

答案 1 :(得分:2)

除了上面的解决方案......你应该以这种方式创建和启动你的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 
}