为何以下Java Swing代码运行后会显示2个JButtons
问题原因
paintComponent 是Swing的组件绘制回调方法,只要界面需要刷新(比如窗口移动、缩放、前后台切换,甚至鼠标划过界面元素),这个方法就会被系统自动触发调用。你将JButton的创建、添加逻辑写在了paintComponent里,每触发一次重绘就会往JPanel里新增一个按钮,你运行时看到2个按钮只是刚好触发了2次重绘,实际使用过程中按钮数量会随着重绘次数不断增加。
除此之外你的代码还有两个影响性能和表现的问题:
- 图片加载、缩放的逻辑也写在了
paintComponent里,每次重绘都要重新读本地文件、缩放图片,会导致界面严重卡顿 - main方法中先调用了
setVisible(true)再设置窗口参数、添加组件,会触发多次无效重绘
修复后的代码
import java.awt.Graphics; import java.awt.Image; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class TowerDefence extends JPanel { // 背景图作为成员变量,只加载缩放一次 private Image bgImage; // 按钮只初始化一次 private JButton button; public TowerDefence() { // 空布局才能用setBounds设置组件位置 setLayout(null); // 初始化加载背景图 ImageIcon easyImage = new ImageIcon("WelcomeImage.png"); bgImage = easyImage.getImage().getScaledInstance(1000, 700, java.awt.Image.SCALE_SMOOTH); // 初始化并添加按钮,只执行一次 button = new JButton("Click Button"); button.setBounds(100, 100, 100, 100); add(button); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); // paintComponent里只做绘制逻辑,不修改组件结构 g.drawImage(bgImage, 0, 0, this); } public static void main(String[] args) throws Exception { TowerDefence t = new TowerDefence(); JFrame frame = new JFrame("Sam"); // 先设置窗口参数 frame.setResizable(false); frame.setBounds(150, 20, 1000, 700); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 添加组件 frame.add(t); frame.setLocationRelativeTo(null); // 最后再显示窗口 frame.setVisible(true); } }
核心修改点
- 所有初始化逻辑(图片加载、按钮创建添加、布局设置)都挪到了类的构造方法中,只会在类实例化的时候执行一次,不会重复添加按钮、重复加载图片
paintComponent方法只保留绘制背景图的逻辑,不做任何修改组件结构的操作- 调整了main方法中窗口初始化的顺序,避免无效重绘
- 增加了
@Override注解标明重写方法,避免方法签名写错的问题 - 替换了原来的
paintIcon绘制方式,直接用drawImage绘制缩放后的背景图,逻辑更简洁
内容的提问来源于stack exchange,提问作者Boomwhat1000
相关产品推荐
相关产品推荐

