当 JPanel 应该填充 JFrame 时,在 JPanel 周围有一点额外的 space
Tiny bit of extra space around the JPanel when it should fill the JFrame
我制作了一个 MRE,您可以在底部找到它,以及我正在使用的图像文件。不确定只上传我的 src 文件夹是否会更好,但有人可以告诉我是否可以这样做。
首先,它确实填充了 JFrame。但是有一个问题。只有当内容窗格的尺寸是 54 的倍数时,它才会正确填充。我附上了一张图片,因为它更容易看清然后解释。
现在,如果我调整 JFrame
的大小。如果我将宽度再扩大一个像素,JPanel
将水平填充。高度也一样,如果我将 JFrame 垂直扩展一个像素,JPanel 将垂直填充,如下图所示。
两个图像之间的唯一区别是我在第二个图像中将 JFrame 的 height/width 扩展了 1 个像素
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
class UIPanel extends JPanel {
private BufferedImage[] textures;
GridBagConstraints c = new GridBagConstraints();
JLayeredPane jp = new JLayeredPane();
BufferedImage PewterCityMap;
UIPanel() {
this.setLayout(new BorderLayout());
jp.setLayout(new GridBagLayout());
c.fill = 1;
c.weightx = 1;
c.weighty = 1;
c.gridwidth = 1;
c.gridheight = 1;
try {
PewterCityMap = ImageIO.read(new File("src/imagesUI/PewterCityMap.jpg"));
final int width = 16;
final int height = 16;
final int rows = 55;
final int cols = 53;
textures = new BufferedImage[rows * cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
textures[(i * cols) + j] = PewterCityMap.getSubimage(
j * width, i * height,
width, height
);
}
}
} catch (
IOException ex) {
ex.printStackTrace();
}
int count = 0;
for (int i = 0; i < 55; i++) {
c.gridy = i;
c.gridx = 0;
for (int j = 0; j < 53; j++) {
c.gridx = j;
CanEnterLbl canEnterLbl = new CanEnterLbl(new ImageIcon(textures[count]));
jp.add(canEnterLbl, c);
jp.setLayer(canEnterLbl, 0);
count++;
}
}
this.add(jp, BorderLayout.CENTER);
}
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setLayout(new BorderLayout());
UIPanel ui = new UIPanel();
jf.add(ui, BorderLayout.CENTER);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
}
}
class CanEnterLbl extends JLabel{
private Image img;
CanEnterLbl(ImageIcon imageIcon){
img = imageIcon.getImage();
this.setIcon(imageIcon);
}
@Override
protected void paintComponent(Graphics g){
//In reply to @Frakcool.
//Firstly, thank you! Are the next two lines what you were thinking? I
doesn't fill correctly when using just this line though
//super.paintComponent(g);
//What I was doing before
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
这是我正在使用的图像文件。我会使用公开可用的图像,但图像的高度和宽度需要是 16 的倍数。
I need the images to resize
那么你不应该使用 JLabel 来显示图像。您不需要 JLabel UI 的所有额外开销。
相反,您可以通过扩展 JComponent
创建自定义组件。然后自定义它的 paintComponent()
方法以在绘制时缩放图像。
It only fills properly when the contentpane dimensions are, I believe a multiple of 54.
我猜是水平 53 垂直 55 的倍数。
GridBagLayout
将首先按每个组件的首选大小分配 space。
然后如果有额外的space,它将根据weightx/y约束将space分配给每个组件。
您不能将一小部分像素分配给组件。所以最好的办法是分配一个像素,这就是为什么你需要 53 或 55,具体取决于大小方向。
我不知道 JDK 中的任何布局管理器可以防止面板边缘周围的额外 space
一个可能的解决方案是使用 Relative Layout。 Relative Layout
允许组件的大小相对于 space 可用。一旦给出组件的相对大小,它就允许您指定应如何分配 "extra" 像素。
要使用这种方法,您需要一个垂直使用 RelativeLayout
的主面板,然后是水平使用 RelativeLayout
的每一行的子面板。
所以逻辑可能是这样的:
RelativeLayout verticalLayout = new RelativeLayout(RelativeLayout.Y_AXIS);
verticalLayout.setRoundingPolicy( RelativeLayout.EQUAL );
verticalLayout.setFill(true);
JPanel mapPanel = new JPanel( vertcalLayout );
for (int i = 0; i < rows; i++)
{
RelativeLayout rowLayout = new RelativeLayout(RelativeLayout.X_AXIS);
rowLayout.setRoundingPolicy( RelativeLayout.EQUAL );
rowLayout.setFill(true);
JPanel row = new JPanel( rowLayout );
for (int j = 0; j < cols; j++)
{
CanEnterLbl canEnterLbl = new CanEnterLbl(…);
row.add(canEnterLbl, new Float(1));
}
mapPanel.add(row, new Float(1));
}
请注意,RelativeLayout 不会计算初始首选大小,因此您需要对其进行设置,以便 frame.pack() 方法正常工作。
我制作了一个 MRE,您可以在底部找到它,以及我正在使用的图像文件。不确定只上传我的 src 文件夹是否会更好,但有人可以告诉我是否可以这样做。 首先,它确实填充了 JFrame。但是有一个问题。只有当内容窗格的尺寸是 54 的倍数时,它才会正确填充。我附上了一张图片,因为它更容易看清然后解释。
现在,如果我调整 JFrame
的大小。如果我将宽度再扩大一个像素,JPanel
将水平填充。高度也一样,如果我将 JFrame 垂直扩展一个像素,JPanel 将垂直填充,如下图所示。
两个图像之间的唯一区别是我在第二个图像中将 JFrame 的 height/width 扩展了 1 个像素
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
class UIPanel extends JPanel {
private BufferedImage[] textures;
GridBagConstraints c = new GridBagConstraints();
JLayeredPane jp = new JLayeredPane();
BufferedImage PewterCityMap;
UIPanel() {
this.setLayout(new BorderLayout());
jp.setLayout(new GridBagLayout());
c.fill = 1;
c.weightx = 1;
c.weighty = 1;
c.gridwidth = 1;
c.gridheight = 1;
try {
PewterCityMap = ImageIO.read(new File("src/imagesUI/PewterCityMap.jpg"));
final int width = 16;
final int height = 16;
final int rows = 55;
final int cols = 53;
textures = new BufferedImage[rows * cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
textures[(i * cols) + j] = PewterCityMap.getSubimage(
j * width, i * height,
width, height
);
}
}
} catch (
IOException ex) {
ex.printStackTrace();
}
int count = 0;
for (int i = 0; i < 55; i++) {
c.gridy = i;
c.gridx = 0;
for (int j = 0; j < 53; j++) {
c.gridx = j;
CanEnterLbl canEnterLbl = new CanEnterLbl(new ImageIcon(textures[count]));
jp.add(canEnterLbl, c);
jp.setLayer(canEnterLbl, 0);
count++;
}
}
this.add(jp, BorderLayout.CENTER);
}
public static void main(String[] args) {
JFrame jf = new JFrame();
jf.setLayout(new BorderLayout());
UIPanel ui = new UIPanel();
jf.add(ui, BorderLayout.CENTER);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
}
}
class CanEnterLbl extends JLabel{
private Image img;
CanEnterLbl(ImageIcon imageIcon){
img = imageIcon.getImage();
this.setIcon(imageIcon);
}
@Override
protected void paintComponent(Graphics g){
//In reply to @Frakcool.
//Firstly, thank you! Are the next two lines what you were thinking? I
doesn't fill correctly when using just this line though
//super.paintComponent(g);
//What I was doing before
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
这是我正在使用的图像文件。我会使用公开可用的图像,但图像的高度和宽度需要是 16 的倍数。
I need the images to resize
那么你不应该使用 JLabel 来显示图像。您不需要 JLabel UI 的所有额外开销。
相反,您可以通过扩展 JComponent
创建自定义组件。然后自定义它的 paintComponent()
方法以在绘制时缩放图像。
It only fills properly when the contentpane dimensions are, I believe a multiple of 54.
我猜是水平 53 垂直 55 的倍数。
GridBagLayout
将首先按每个组件的首选大小分配 space。
然后如果有额外的space,它将根据weightx/y约束将space分配给每个组件。
您不能将一小部分像素分配给组件。所以最好的办法是分配一个像素,这就是为什么你需要 53 或 55,具体取决于大小方向。
我不知道 JDK 中的任何布局管理器可以防止面板边缘周围的额外 space
一个可能的解决方案是使用 Relative Layout。 Relative Layout
允许组件的大小相对于 space 可用。一旦给出组件的相对大小,它就允许您指定应如何分配 "extra" 像素。
要使用这种方法,您需要一个垂直使用 RelativeLayout
的主面板,然后是水平使用 RelativeLayout
的每一行的子面板。
所以逻辑可能是这样的:
RelativeLayout verticalLayout = new RelativeLayout(RelativeLayout.Y_AXIS);
verticalLayout.setRoundingPolicy( RelativeLayout.EQUAL );
verticalLayout.setFill(true);
JPanel mapPanel = new JPanel( vertcalLayout );
for (int i = 0; i < rows; i++)
{
RelativeLayout rowLayout = new RelativeLayout(RelativeLayout.X_AXIS);
rowLayout.setRoundingPolicy( RelativeLayout.EQUAL );
rowLayout.setFill(true);
JPanel row = new JPanel( rowLayout );
for (int j = 0; j < cols; j++)
{
CanEnterLbl canEnterLbl = new CanEnterLbl(…);
row.add(canEnterLbl, new Float(1));
}
mapPanel.add(row, new Float(1));
}
请注意,RelativeLayout 不会计算初始首选大小,因此您需要对其进行设置,以便 frame.pack() 方法正常工作。