Java Swing跳棋开发中paintComponent重复添加按钮致界面异常
问题根因
- 大量极小按钮生成、调整窗口/点击按钮后新增按钮:
paintComponent是Swing的界面重绘回调,会在窗口大小变化、控件状态变化、手动调用repaint()时频繁触发,你将按钮创建、add()逻辑写在paintComponent调用的initalprnt()方法中,相当于每次重绘都会新增24个按钮(12绿12蓝)。同时你没有为MainPane设置空布局,setBounds()配置会被默认的FlowLayout忽略,未完成布局计算的按钮都会被堆在面板顶部,显示为极小的异常按钮。 - 鼠标悬停闪烁:一方面是大量重叠按钮的重绘冲突,另一方面是你为按钮设置了带alpha通道的透明背景,但没有调用
setOpaque(false)关闭Swing控件的默认不透明绘制属性,导致悬停时状态绘制异常。
补充问题:你当前的监听器逻辑只作用在最后创建的1个绿按钮和1个蓝按钮上,其余22个按钮都没有绑定点击事件。
修复方案
- 将按钮初始化逻辑从绘制逻辑中剥离,放到
MainPane构造方法中,仅在组件初始化时执行一次 - 为
MainPane设置空布局,让setBounds()配置生效 - 调整按钮透明配置,为每个按钮单独绑定监听器
paintComponent仅保留棋盘、棋子的绘制逻辑,不做组件修改操作
修复后核心代码示例
public class MainPane extends JPanel implements MouseListener { private GameListener gameListener; public MainPane() { // 设置空布局,让setBounds生效 setLayout(null); addMouseListener(this); // 初始化按钮仅执行一次 initButtons(); } private void initButtons() { int xshift = 125; int yshift = 0; // 初始化绿方按钮 for (int i = 0; i < 3; i++) { if (i == 2) { xshift = 125; } for (int j = 0; j < 4; j++) { JButton green = new JButton(); green.setBackground(new Color(0, 100, 0, 0)); green.setOpaque(false); // 关闭默认不透明绘制 green.setBounds(xshift, yshift, 125, 125); green.addActionListener(e -> { System.out.println("绿方按钮触发"); gameListener.startNewGame(); }); add(green); xshift += 250; } xshift = 0; yshift += 125; } yshift += 250; // 初始化蓝方按钮 for (int k = 0; k < 3; k++) { if (k == 2) { xshift = 0; } for (int j = 0; j < 4; j++) { JButton blue = new JButton(); blue.setBackground(new Color(0, 0, 100, 0)); blue.setOpaque(false); blue.setBounds(xshift, yshift, 125, 125); blue.addActionListener(e -> { System.out.println("蓝方按钮触发"); gameListener.startNewGame(); }); add(blue); xshift += 250; } xshift = 125; yshift += 125; } } public void setGameListener(GameListener gameListener) { this.gameListener = gameListener; } @Override public Dimension getPreferredSize() { return new Dimension(1000, 1000); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int xshift; int yshift = 0; // 绘制棋盘 g.setColor(new Color(0, 0, 0)); for (int i = 0; i < 4; i++) { xshift = 125; for (int j = 0; j < 4; j++) { g.fillRect(xshift, yshift, 125, 125); xshift += 250; } xshift = 0; yshift += 125; for (int k = 0; k < 4; k++) { g.fillRect(xshift, yshift, 125, 125); xshift += 250; } yshift += 125; } // 绘制棋子图形 xshift = 125; yshift = 0; g.setColor(new Color(0, 100, 0)); for (int i = 0; i < 3; i++) { if (i == 2) { xshift = 125; } for (int j = 0; j < 4; j++) { g.fillOval(xshift, yshift, 125, 125); xshift += 250; } xshift = 0; yshift += 125; } yshift += 250; g.setColor(new Color(0, 0, 100)); for (int k = 0; k < 3; k++) { if (k == 2) { xshift = 0; } for (int j = 0; j < 4; j++) { g.fillOval(xshift, yshift, 125, 125); xshift += 250; } xshift = 125; yshift += 125; } } // 其余鼠标事件方法保持不变 public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} }
内容的提问来源于stack exchange,提问作者OutcastedCringe
相关产品推荐
相关产品推荐

