Java - 顶部的 GridBagLayout 组件在调整大小时消失
Java - GridBagLayout components on top disappear on resize
我使用 JLabel
并在其前面使用 JTextField
,这样我就可以用一个值表示类似防御的统计数据。我使用以下代码:
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
JLabel jl = new JLabel();
ImageIcon ii = new ImageIcon("C:\Users\Max\Desktop\shield.png");
jl.setIcon(ii);
gbc.gridy = 0;
gbc.gridx = 0;
add(jl, gbc);
gbc.insets = new Insets(5, 10, 10, 10);
JTextField jtf = new JTextField(2);
jtf.setHorizontalAlignment(JTextField.CENTER);
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.gridy = 0;
gbc.gridx = 0;
jtf.setFocusable(false);
add(jtf, gbc);
并得到:
一切正常,但是,如果我尝试调整 window 的大小,JTextField
将永远消失,只有 JLabel
显示。为什么会这样?
- 标签的位置和文本字段的位置之间没有关系,这意味着标签和字段可以相互独立地自由移动
- 存在 z 顺序问题,容器顺序较低的组件在容器顺序较高的组件之后绘制(相反顺序),这意味着当整个容器更新时标签实际上是在屏蔽之前绘制.它有时可能起作用的原因是因为组件实际上可以彼此独立地绘制,这意味着文本字段实际上可以在不需要通知父容器或标签的情况下绘制
例如...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 10, 10, 10);
JTextField jtf = new JTextField(2);
jtf.setHorizontalAlignment(JTextField.CENTER);
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.gridy = 0;
gbc.gridx = 0;
jtf.setFocusable(false);
add(jtf, gbc);
gbc = new GridBagConstraints();
try {
JLabel jl = new JLabel();
ImageIcon ii = new ImageIcon(ImageIO.read(getClass().getResource("/shield01.png")));
jl.setIcon(ii);
gbc.gridy = 0;
gbc.gridx = 0;
add(jl, gbc);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
一个可能更好的解决方案是创建一个 "background" 组件,该组件获取图像并将其绘制为组件的背景,然后将文本字段添加到其中。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class TestBackground {
public static void main(String[] args) {
new TestBackground();
}
public TestBackground() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
try {
BackgroundPane pane = new BackgroundPane(ImageIO.read(getClass().getResource("/shield02.png")));
pane.setLayout(new GridBagLayout());
pane.setBorder(new EmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
JTextField jtf = new JTextField(2);
jtf.setHorizontalAlignment(JTextField.CENTER);
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.gridy = 0;
gbc.gridx = 0;
jtf.setFocusable(false);
pane.add(jtf, gbc);
add(pane);
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
public class BackgroundPane extends JPanel {
private BufferedImage img;
public BackgroundPane(BufferedImage img) {
this.img = img;
}
@Override
public Dimension getPreferredSize() {
return img != null ? new Dimension(img.getWidth(), img.getHeight()) : super.getPreferredSize();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g.drawImage(img, x, y, this);
}
}
}
}
我使用 JLabel
并在其前面使用 JTextField
,这样我就可以用一个值表示类似防御的统计数据。我使用以下代码:
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
JLabel jl = new JLabel();
ImageIcon ii = new ImageIcon("C:\Users\Max\Desktop\shield.png");
jl.setIcon(ii);
gbc.gridy = 0;
gbc.gridx = 0;
add(jl, gbc);
gbc.insets = new Insets(5, 10, 10, 10);
JTextField jtf = new JTextField(2);
jtf.setHorizontalAlignment(JTextField.CENTER);
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.gridy = 0;
gbc.gridx = 0;
jtf.setFocusable(false);
add(jtf, gbc);
并得到:
一切正常,但是,如果我尝试调整 window 的大小,JTextField
将永远消失,只有 JLabel
显示。为什么会这样?
- 标签的位置和文本字段的位置之间没有关系,这意味着标签和字段可以相互独立地自由移动
- 存在 z 顺序问题,容器顺序较低的组件在容器顺序较高的组件之后绘制(相反顺序),这意味着当整个容器更新时标签实际上是在屏蔽之前绘制.它有时可能起作用的原因是因为组件实际上可以彼此独立地绘制,这意味着文本字段实际上可以在不需要通知父容器或标签的情况下绘制
例如...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 10, 10, 10);
JTextField jtf = new JTextField(2);
jtf.setHorizontalAlignment(JTextField.CENTER);
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.gridy = 0;
gbc.gridx = 0;
jtf.setFocusable(false);
add(jtf, gbc);
gbc = new GridBagConstraints();
try {
JLabel jl = new JLabel();
ImageIcon ii = new ImageIcon(ImageIO.read(getClass().getResource("/shield01.png")));
jl.setIcon(ii);
gbc.gridy = 0;
gbc.gridx = 0;
add(jl, gbc);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
一个可能更好的解决方案是创建一个 "background" 组件,该组件获取图像并将其绘制为组件的背景,然后将文本字段添加到其中。
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class TestBackground {
public static void main(String[] args) {
new TestBackground();
}
public TestBackground() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
try {
BackgroundPane pane = new BackgroundPane(ImageIO.read(getClass().getResource("/shield02.png")));
pane.setLayout(new GridBagLayout());
pane.setBorder(new EmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
JTextField jtf = new JTextField(2);
jtf.setHorizontalAlignment(JTextField.CENTER);
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.gridy = 0;
gbc.gridx = 0;
jtf.setFocusable(false);
pane.add(jtf, gbc);
add(pane);
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
public class BackgroundPane extends JPanel {
private BufferedImage img;
public BackgroundPane(BufferedImage img) {
this.img = img;
}
@Override
public Dimension getPreferredSize() {
return img != null ? new Dimension(img.getWidth(), img.getHeight()) : super.getPreferredSize();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g.drawImage(img, x, y, this);
}
}
}
}