首页 > 解决方案 > 为我的菜单设置背景图像并调整大小

问题描述

所以我正在尝试为我正在开发的游戏制作菜单。

我想将图像作为背景放在我的位置menuPanel,但我无法弄清楚每次我提高窗户时如何让图像重新缩放。我已经制作了一个JLabel并且我已经从我的主要方法中导入了一个图像,当我启动游戏时,我可以看到图像已正确导入,但我想填满所有内容menuPanel并在我将窗口提升到全屏或减小时拉伸到我的框架的最小尺寸。我怎样才能做到这一点?

正如您在屏幕截图中看到的那样,我希望文本位于图像顶部,并将图像作为背景和全屏。

public class Window extends Canvas{

    private static final long serialVersionUID = 6331412385749386309L;
    
    private static final int WIDTH = 1024, HEIGHT = WIDTH / 16 * 9;
    private JFrame frame;
    
    private JPanel mainPanel;
    private JPanel menuPanel;
    private JPanel buttonsPanel;
    private JPanel playPanel;
    private JPanel optionsPanel;
    
    private JButton playBtn;
    private JButton optionsBtn;
    private JButton quitBtn;
    
    private int currWidth = WIDTH, currHeight = HEIGHT;

    public Window(String title, Game game) {
        frame = new JFrame(title);
        
        frame.setSize(1024, 576);
        frame.setMinimumSize(new Dimension(WIDTH, HEIGHT));
        
        frame.requestFocus();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(true);
        frame.setLocationRelativeTo(null);
        menu();
        game.start();
    }
    
    private void menu() {
        frame.getContentPane().setLayout(new BorderLayout(0, 0));
        mainPanel = new JPanel();
        mainPanel.setBackground(new Color(255, 255, 255));
        frame.getContentPane().add(mainPanel);
        mainPanel.setLayout(new CardLayout(0, 0));
        
        // menuPanel config
        menuPanel = new JPanel();
        menuPanel.setForeground(new Color(0, 0, 0));
        menuPanel.setBackground(new Color(0, 0, 0));
        mainPanel.add(menuPanel, "menuPanel");
        
        buttonsPanel = new JPanel();
        buttonsPanel.setBorder(null);
        buttonsPanel.setBackground(new Color(0, 0, 0));
        
            // playBtn config
        playBtn = new JButton("Play");
        playBtn.setForeground(new Color(255, 255, 255));
        playBtn.setFont(new Font("Segoe Script", Font.BOLD, 40));
        playBtn.setOpaque(false);
        playBtn.setContentAreaFilled(false);
        playBtn.setBorderPainted(false);
        playBtn.setFocusPainted(false);
        
            // optionsBtn config
        optionsBtn = new JButton("Options");
        optionsBtn.setForeground(new Color(255, 255, 255));
        optionsBtn.setFont(new Font("Segoe Script", Font.BOLD, 35));
        optionsBtn.setOpaque(false);
        optionsBtn.setContentAreaFilled(false);
        optionsBtn.setBorderPainted(false);
        optionsBtn.setFocusPainted(false);
        
            //quitBtn config
        quitBtn = new JButton("Quit");
        quitBtn.setForeground(new Color(255, 255, 255));
        quitBtn.setFont(new Font("Segoe Script", Font.BOLD, 35));
        quitBtn.setOpaque(false);
        quitBtn.setContentAreaFilled(false);
        quitBtn.setBorderPainted(false);
        quitBtn.setFocusPainted(false);
        
        GroupLayout gl_buttonsPanel = new GroupLayout(buttonsPanel);
        gl_buttonsPanel.setHorizontalGroup(
            gl_buttonsPanel.createParallelGroup(Alignment.TRAILING)
                .addGroup(gl_buttonsPanel.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(gl_buttonsPanel.createParallelGroup(Alignment.LEADING)
                        .addComponent(quitBtn, GroupLayout.DEFAULT_SIZE, 175, Short.MAX_VALUE)
                        .addComponent(playBtn, GroupLayout.DEFAULT_SIZE, 175, Short.MAX_VALUE)
                        .addComponent(optionsBtn, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addContainerGap())
        );
        gl_buttonsPanel.setVerticalGroup(
            gl_buttonsPanel.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_buttonsPanel.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(playBtn)
                    .addPreferredGap(ComponentPlacement.RELATED)
                    .addComponent(optionsBtn, GroupLayout.PREFERRED_SIZE, 74, GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(ComponentPlacement.RELATED)
                    .addComponent(quitBtn, GroupLayout.PREFERRED_SIZE, 71, GroupLayout.PREFERRED_SIZE)
                    .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        buttonsPanel.setLayout(gl_buttonsPanel);
        
        //
        JLabel menuImageLabel = new JLabel(new ImageIcon(Game.menu_image.getScaledInstance(700, 400, Image.SCALE_FAST)));
        //
        
        GroupLayout gl_menuPanel = new GroupLayout(menuPanel);
        gl_menuPanel.setHorizontalGroup(
            gl_menuPanel.createParallelGroup(Alignment.TRAILING)
                .addGroup(gl_menuPanel.createSequentialGroup()
                    .addComponent(menuImageLabel, GroupLayout.PREFERRED_SIZE, 762, GroupLayout.PREFERRED_SIZE)
                    .addGap(0)
                    .addComponent(buttonsPanel, GroupLayout.DEFAULT_SIZE, 195, Short.MAX_VALUE))
        );
        gl_menuPanel.setVerticalGroup(
            gl_menuPanel.createParallelGroup(Alignment.LEADING)
                .addGroup(gl_menuPanel.createSequentialGroup()
                    .addGap(161)
                    .addComponent(buttonsPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGap(124))
                .addComponent(menuImageLabel, GroupLayout.DEFAULT_SIZE, 537, Short.MAX_VALUE)
        );
        menuPanel.setLayout(gl_menuPanel);
        
        // playPanel config
        playPanel = new JPanel();
        playPanel.setBackground(new Color(0, 0, 255));
        mainPanel.add(playPanel, "playPanel");
        
        // optionsPanel config
        optionsPanel = new JPanel();
        optionsPanel.setBackground(new Color(255, 0, 0));
        mainPanel.add(optionsPanel, "optionsPanel");
        
        frame.setVisible(true);
        
        setActions();
    }
    
    private void setActions() {
        
        // playBtn action
        playBtn.addMouseListener(new MouseAdapter() {
            
            public void mouseEntered(MouseEvent e) {
                playBtn.setForeground(new Color(200, 210, 10));
            }
            
            public void mouseExited(MouseEvent e) {
                playBtn.setForeground(new Color(255, 255, 255));
            }
            
            public void mouseClicked(MouseEvent e) {
                menuPanel.setVisible(false);
                playPanel.setVisible(true);
                optionsPanel.setVisible(false);
            }
        });
        
        // optionsBtn action
        optionsBtn.addMouseListener(new MouseAdapter() {

            public void mouseEntered(MouseEvent e) {
                optionsBtn.setForeground(new Color(200, 210, 10));
            }
            
            public void mouseExited(MouseEvent e) {
                optionsBtn.setForeground(new Color(255, 255, 255));
            }
            
            public void mouseClicked(MouseEvent e) {
                menuPanel.setVisible(false);
                playPanel.setVisible(false);
                optionsPanel.setVisible(true);
            }
        });
        
        // quitBtn action
        quitBtn.addMouseListener(new MouseAdapter() {

            public void mouseEntered(MouseEvent e) {
                quitBtn.setForeground(new Color(200, 210, 10));
            }
            
            public void mouseExited(MouseEvent e) {
                quitBtn.setForeground(new Color(255, 255, 255));
            }
            
            public void mouseClicked(MouseEvent e) {
                System.exit(0);
            }
        });
    }
    
    public void tick() {
        mainPanel.getSize(new Dimension(currWidth, currHeight));
        
        System.out.println(currWidth + ", " + currHeight);
    }
    
    public void render() {
        
    }
}

标签: javaswingmenu

解决方案


Swing 基于父/子关系。

因此,如果您希望按钮显示在背景上,您的代码结构需要是:

- frame
    - background component
        - buttons panel

最简单的方法是使用JLabel图像作为背景。然后将按钮面板添加到标签中。唯一的问题是默认情况下 aJLabel不使用布局管理器,因此您需要查看布局管理器才能达到您想要的效果。

我建议使用 a GridBagLayout,然后按钮将在面板上居中。基本代码是:

JPanel buttons = new JPanel();
buttons.add(...);

JLabel background = new JLabel(...);
background.setLayout( new GridBagLayout() );
background.add(buttons, new GridBagConstraints());

标签将以背景图像的大小显示。

如果您希望背景图像随着帧大小的变化而缩放,那么您有几个选择:

  1. 使用拉伸图标。它会自动将图像缩放到可用空间。
  2. 用 JPanel 替换 JLabel 并自己绘制图像。查看可以配置为自动缩放图像的背景面板。

编辑:

我试着阅读代码,它真的很混乱。

好吧,目的不是让您阅读代码。目的是让您使用代码。

当您编程时,您将学习如何使用类和类的方法。当你使用这个ImageIcon类时,你是先阅读代码还是只是学习如何使用它的构造函数?

现在我同意,这两个类没有发布的 API,但您实际上只需要了解类的构造函数和方法即可使用它们。

如果您阅读Stretch Icon博客,它会指出:

StretchIcon 是 ImageIcon 的替代品,它扩展了它,但不支持 ImageIcon 的无参数构造函数。

这意味着如果您通常使用:

JLabel background = new JLabel( new ImageIcon("background.jpg") );

您将使用以下内容StretchIcon

JLabel background = new JLabel( new StretchIcon("background.jpg") );

类似地BackgroundPanel,如果您阅读博客,它会声明它是:

JPanel 的扩展,为图像的绘制提供了一些自定义绘画支持

然后它继续说默认是绘制“缩放”的图像,这就是你想要的。因此,您只需要弄清楚使用哪个构造函数来创建面板。

对于常规面板,您将使用:

JPanel background = new JPanel();

BackgroundPanel简单的构造函数是类的第一个构造函数,它只接受一个Image作为参数:

JPanel background = new BackgroundPanel(image);

现在您有了一个面板,您只需将 3 个按钮添加到面板。

我没有写这个StretchIcon类,所以我不知道代码的细节,我也不关心细节,只要这个类做我期望它做的事情。

我确实写了这BackgroundPanel门课,所以如果你有具体的问题,那么我可能会帮助你。但我没有时间猜测代码的哪一部分让您感到困惑。

编辑2:

我有 3 个按钮,我希望它们位于中央并伸展,以便它们保持在图像的中心

这是关于学习如何使用布局管理器。我从不使用 IDE 来生成我的代码。我想完全控制代码。这使您的代码更清晰,更易于维护。

这允许您为作业选择合适的布局管理器,并允许您轻松地嵌套具有不同布局管理器的面板。在这种情况下,您要使用 GridBagLayout,默认情况下,添加到其中的任何组件都会水平和垂直居中。

默认情况下BackgroundPanel使用 BorderLayout。但是您可以轻松地将其更改为使用 GridBagLayout。然后我将使用带有 GridLayout 的第二个面板作为按钮。

所以代码会是这样的:

JPanel buttonPanel = new JPanel( new GridLayout(0, 1, 10, 0) );
buttonPanel.add(playBtn);
...

backgroundPanel.add(buttonPanel, new GridBagConstraints());

现在随着框架大小的改变,按钮将自动重新居中。

阅读有关布局管理器的 Swing 教程中的部分以获取更多信息和示例。

保持手边的 Swing 教程的链接。它包含大多数 Swing 基础知识的信息和示例。


推荐阅读