英文:
Setting up a background image for my menu and being resizable
问题
以下是您的代码的翻译部分:
我正在尝试为我正在开发的游戏制作一个菜单。
我想在我的 `menuPanel` 上放置一张图片作为背景,但我无法弄清楚如何让图像在每次调整窗口大小时都能自动重新缩放。我已经创建了一个 `JLabel`,并从我的主方法中导入了一张图片,当我启动游戏时,我可以看到图像被正确导入,但我想要填充整个 `menuPanel`,并且随着窗口的扩大或缩小而拉伸到框架的最小尺寸。
如何做到这一点?
[![][1]][1]
正如您在截图中看到的,我希望文本位于图像之上,图像作为背景并占据整个屏幕。
```java
public class Window extends Canvas{
// ... (以下是类中的其他代码,未翻译)
}
请注意,这只是您代码的翻译部分,不包括问题或其他内容。如果您需要更多帮助或有其他问题,请随时提出。
英文:
So i am trying to make a Menu for a game i am working on.
I want to put an image as background at my menuPanel
but i cant figure out how to let the image rescale every time i am raising the window. I have made a JLabel
and i have imported an image from my main method and when i launch the game i can see that the image is correctly imported but i want to fill up all menuPanel
and also stretch as i am raising the window to full screen or decreasing to the Minimum size of my frame.
How can i do that?
As you can see at the screenshot i want the text to be on top of the image and the image as a background and full screen.
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() {
}
}
答案1
得分: 2
Swing基于父子关系。
如果您希望按钮显示在背景上,您的代码结构应如下:
- 框架
- 背景组件
- 按钮面板
最简单的方法是使用JLabel
作为背景,然后将按钮面板添加到标签上。唯一的问题是,默认情况下,JLabel
不使用布局管理器,因此您需要设置布局管理器以实现所需的效果。
我建议使用GridBagLayout
,这样按钮将居中显示在面板上。基本代码如下:
JPanel buttons = new JPanel();
buttons.add(...);
JLabel background = new JLabel(...);
background.setLayout(new GridBagLayout());
background.add(buttons, new GridBagConstraints());
标签将以背景图像的大小显示。
如果您希望背景图像随着窗口大小的变化而缩放,那么您有几个选项:
- 使用Stretch Icon。它将自动将图像缩放到可用空间。
- 将JLabel替换为JPanel并自行绘制图像。查看Background Panel,它可以配置为自动缩放图像。
编辑:
> 我尝试阅读代码,但它确实令人困惑。
嗯,我的意图不是让您阅读代码,而是让您使用代码。
编程时,您学习如何使用类和类的方法。当您使用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基础知识的信息和示例。
英文:
Swing is based on parent/child relationships.
So if you want the button displayed on the background the structure of your code needs to be:
- frame
- background component
- buttons panel
The easiest way to do this is to use a JLabel
with your image as the background. Then you add the buttons panel to the label. The only issue is that by default a JLabel
doesn't use a layout manager so you need to see the layout manager to achieve your desired effect.
I would suggest using a GridBagLayout
, then the buttons will be centered on the panel. The basic code would be:
JPanel buttons = new JPanel();
buttons.add(...);
JLabel background = new JLabel(...);
background.setLayout( new GridBagLayout() );
background.add(buttons, new GridBagConstraints());
The label will be displayed at the size of the background image.
If you want the background image to scale as the frame size changes, then you have a couple of options:
- Use the Stretch Icon. It will automatically scale the image to the space available.
- Replace the JLabel with a JPanel and paint the image yourself. Check out the Background Panel which can be configured to automatically scale an image.
Edit:
> i tried reading the code and its really confusing.
Well, the intent was not for you to read the code. The intent was for you to use the code.
When you program you learn how to use classes and the methods of the class. When you use the ImageIcon
class did you read the code first or just learn how to use its contructor?
Now I agree, the two classes don't have a published API but you really only need to understand the constructors and methods of the classes in order to use them.
If you read the Stretch Icon
blog it states:
StretchIcon is a drop-in replacement for ImageIcon, which it extends, except that ImageIcon’s no-arg constructor isn’t supported.
So that means that if you would normally use:
JLabel background = new JLabel( new ImageIcon("background.jpg") );
you would use the following for the StretchIcon
:
JLabel background = new JLabel( new StretchIcon("background.jpg") );
Similarly for the BackgroundPanel
, if you read the blog it states that it is:
an extension of JPanel that provides some custom painting support for the drawing of images
It then goes on to say that the default is to paint the image "scaled" which is what you want. So all you need to figure out is which constuctor to use to create the panel.
For a regular panel you would use:
JPanel background = new JPanel();
For the BackgroundPanel
the simplest constructor to use would be the first constructor of the class which simply takes an Image
as a parameter:
JPanel background = new BackgroundPanel(image);
Now you have a panel and you simply add your 3 buttons to the panel.
I did not write the StretchIcon
class so I don't know the details of the code, and I don't care about the details as long as the class does what I expect it to do.
I did write the BackgroundPanel
class so if you has specific questions then I can probably help you. But I don't have time to guess which part of the code you find confusing.
Edit 2:
> I have 3 buttons and i want them to be at the cemter and stretch too so they stay at the center of the image
This is about learning how to use layout managers. I never use an IDE to generate my code. I want full control over the code. This allows your code to be cleaner an more easily maintained.
This allows you to choose the appropriate layout manager for the job and allows you to easily nest panels with different layout mangers. In this case you want to use the GridBagLayout which by default will center horizontally and vertically any component added to it.
By default the BackgroundPanel
uses a BorderLayout. But you can easily change it to use the GridBagLayout. Then I would use a second panel with a GridLayout for the buttons.
So the code would be something like:
JPanel buttonPanel = new JPanel( new GridLayout(0, 1, 10, 0) );
buttonPanel.add(playBtn);
...
backgroundPanel.add(buttonPanel, new GridBagConstraints());
Now as the frame size is changed the buttons will automatically re-center.
Read the section from the Swing tutorial on Layout Managers for more information and examples.
Keep a link to the Swing tutorial handy. It contains information and example of most Swing basics.
答案2
得分: 1
你可以使用paintComponent(Graphics g)
方法和drawImage()
方法从JPanel来绘制你的图片。
import java.awt.*;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class AutoScale extends JFrame {
private Image image;
public AutoScale() {
setTitle("AutoScale");
setResizable(true);
setSize(400, 400);
try {
image = ImageIO.read(new File("你的文件路径"));
} catch (IOException e) {
System.out.println("未找到图片");
}
JPanel panelImg = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 30, 30, getWidth() / 2, getHeight() / 2, null);
}
};
add(panelImg);
}
public static void main(String[] args) {
AutoScale frame = new AutoScale();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
在这个示例中,我创建了面板和paintComponent()
方法。在这个方法内部,我使用6个参数调用drawImage()
:
- 图像
- x坐标
- y坐标
- 帧的宽度除以2(你可以通过添加、减去或除以
getWidth()
的结果来调整图像的大小) - 帧的高度除以2(与宽度相同)
- 图像观察者,通常设置为
null
。
paintComponent()
方法会在面板大小更改时自动调用,因此不需要像我之前建议的那样使用WindowListener。
注意:我使用了try-catch块,因为如果找不到文件,它将抛出异常。
希望对你有所帮助!
英文:
You could use the method paintComponent(Graphics g)
and drawImage()
from JPanel to draw your Image.
import java.awt.*;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class AutoScale extends JFrame{
private Image image;
public AutoScale() {
setTitle("AutoScale");
setResizable(true);
setSize(400,400);
try {
image = ImageIO.read(new File("path to your file"));
}catch(IOException e) {
System.out.println("Image not found");
}
JPanel panelImg = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 30, 30, getWidth()/2, getHeight()/2, null);
}
};
add(panelImg);
}
public static void main(String[] args) {
AutoScale frame = new AutoScale();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
In this example, I create the Panel and paintComponent()
. Inside that method, I invoke drawImage()
with 6 parameters:
- The Image <br>
- x Coordinate <br>
- y Coordinate <br>
- The width of the Frame divided by 2(you can play with the size of your image by adding, substracting or dividing the result of
getWidth()
) <br> - The height of the Frame divided by 2(same as the width) <br>
- The imageObserver, which generally is set to
null
. <br>
The paintComponent()
method gets invoke automatically whenever the size of the Panel changes, so there's no need to use a WindowListener as I suggested earlier.
Note: I use a try-catch block because if it can't find the file, it will throw an Exception.
Hope this was helpful!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论