java - 为我的菜单设置背景图像并调整大小
问题描述
所以我正在尝试为我正在开发的游戏制作菜单。
我想将图像作为背景放在我的位置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() {
}
}
解决方案
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());
标签将以背景图像的大小显示。
如果您希望背景图像随着帧大小的变化而缩放,那么您有几个选择:
编辑:
我试着阅读代码,它真的很混乱。
好吧,目的不是让您阅读代码。目的是让您使用代码。
当您编程时,您将学习如何使用类和类的方法。当你使用这个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 基础知识的信息和示例。
推荐阅读
- abap - 如何读取功能模块中的结构化导入参数?
- c# - 如何在多对多模型中添加成分列表?
- typescript - 如何键入使用相同类型的泛型变量和函数?
- javascript - 用于将专有名称转换为规范名称的 javascript 代码
- javascript - 获取反应本机真实
- c# - C# CheckBox List 仅将选中的框发送到 Word 文档
- powershell - 使用 Powershell 为包含特殊字符的 Outlook 签名创建 txt 文件时出现编码问题
- python - 如何调整 matplotlib.pyplot 直方图的 x 轴?
- git - BitBucket SSH 克隆 Git
- rust - 如何在结构中存储“impl Trait”类型的变量?