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

Java 如何在底部放置我的背景图像,java,swing,frame,layer,Java,Swing,Frame,Layer,我想把我的背景图像放在这个框架的最底部,按钮放在顶部。但是,我在下面编写的代码不起作用。有人能看到问题在哪里吗 另一件事是,即使我为我的按钮设置了位置,它仍然显示在画面的顶部中心 请忽略注释行。(我只是猜测,希望它们能起作用,但它们显然不起作用。) 问题/解决办法: setLocation(…)和setBounds(…)调用类型被大多数布局管理器忽略。使用它们的唯一方法是通过.setLayout(null)将容器的布局设置为null 但是,尽管空布局和setBounds()似乎是让新手们喜欢的

我想把我的背景图像放在这个框架的最底部,按钮放在顶部。但是,我在下面编写的代码不起作用。有人能看到问题在哪里吗

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

请忽略注释行。(我只是猜测,希望它们能起作用,但它们显然不起作用。)

问题/解决办法:

  • setLocation(…)
    setBounds(…)
    调用类型被大多数布局管理器忽略。使用它们的唯一方法是通过
    .setLayout(null)将容器的布局设置为null
  • 但是,尽管空布局和
    setBounds()
    似乎是让新手们喜欢的创建复杂GUI的最简单和最好的方法,但您创建的Swing GUI越多,在使用它们时遇到的困难就越严重。当GUI调整大小时,它们不会调整您的组件的大小,它们是一个需要增强或维护的皇家女巫,当它们放置在滚动窗格中时会完全失败,当在所有平台或屏幕分辨率与原始分辨率不同的情况下查看时,它们看起来非常糟糕
  • 总之,不要这样做,不要使用null布局或setBounds,而是嵌套JPanel,每个都使用自己的布局管理器,从而创建易于维护和体面的GUI
  • 如果你想在背景中绘制一幅图像,那么就用JPanel的
    paintComponent(Graphics g)
    方法将其绘制到一个JPanel中,作为GUI组件的容器,这在本网站上的许多类似问题中都得到了演示——我马上就会找到我的一些
  • 如果在该图像图形JPanel的顶部添加任何JPanel,请确保可以通过在这些重叠的JPanel上调用
    setOpaque(false)
    来查看它们。否则,您将掩盖图像
  • 当只需要一个jframe时,代码有两个jframe。把你不用的扔掉
  • 在将组件添加到GUI之前,在JFrame上过早调用
    setVisible(true)
    ——不要这样做。仅在将所有内容添加到GUI后调用它,以便所有内容都显示OK
  • 您正在创建两个JLayedPanes,并通过将它们添加到JFrame中而完全覆盖其中一个,而不了解JFrame的BorderLayout如何处理添加的组件
  • 我建议您甚至不要使用一个JLayeredPane,而是如上所述在JPanel中绘制,并将其用作容器
  • 当按下“播放”按钮时,您的代码似乎正在打开一个全新的GUI窗口,如果是这样,用户很快就会感到恼火。考虑交换视图而不是.
例如:

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 
}

谢谢;)@非常感谢!我实际上是java的新手。在你们的两个代码中我都不理解的一行是“SwingUtilities.invokeLater(newrunnable())”。你能告诉我它是做什么用的吗@Jorge@AnthonyZhang考虑到这是一份简短的简历!!!我希望有帮助。使用swing时,对用户界面的任何更新都必须发生在事件调度线程(AWT事件调度线程)上。因此,对任何方法的任何调用都意味着对GUI的更新,应该从这个线程调用。使用invokeLater可以保证代码将在EDT中执行。还有其他选项(如invokeAndWait),但在特定情况下,这将尽快在EDT中执行您的代码(在处理所有其他以前的事件之后),非常感谢!这对解释很有帮助。请给我一些时间修改我的代码,稍后我会给你一些反馈@HoverCraftFullOfeels为什么设置bgImage=null@HovercraftFullOfEels@AnthonyZhang:因为我没有将BuffereImage分配给声明变量的bgImage——我不能,因为这是不可能的。相反,我在构造函数中分配它(您可以清楚地看到)。
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 
}