paintComponent仅调用一次:Java Swing拖拽画圆功能异常排查
嘿,我帮你揪出了两个关键问题,导致你的paintComponent方法只在启动时调用一次,拖拽时完全没反应:
1. 鼠标监听器绑定到了错误的组件实例
你在PatternCreator的构造函数里写了这行代码:
addMouseMotionListener(new PaintingField());
这里你新建了一个完全独立的、根本没加到窗口上的PaintingField对象,把鼠标监听器绑到了它身上。而界面上实际显示的是你之前创建的paintingField实例——这个真正需要监听鼠标的组件,反而没有绑定任何监听器!
更糟的是,你看到的坐标打印,其实是那个隐藏的PaintingField实例的mouseDragged方法输出的,它调用的repaint()也是针对自己的,但这个组件根本不在界面上,所以它的paintComponent永远不会被调用。而界面上的paintingField的x和y一直是初始的-1,就算它被重绘,也会直接return什么都不画。
2. paintComponent没有调用父类方法
Swing的绘制规则要求:重写paintComponent时,必须先调用super.paintComponent(g)。这个方法负责清除组件背景、初始化绘制上下文,要是跳过它,不仅会导致图形残留,还会干扰Swing的重绘机制,让重绘请求无法被正确处理。
修复方案
第一步:修正PaintingField的代码
让组件自己监听鼠标事件,同时补上父类的paintComponent调用:
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class PaintingField extends JPanel implements MouseMotionListener { int x, y; public PaintingField() { setPreferredSize(new Dimension(500, 500)); x = -1; y = -1; // 让组件自己监听鼠标事件 addMouseMotionListener(this); } @Override public void mouseDragged(MouseEvent e) { x = e.getX(); y = e.getY(); System.out.println(x + " " + y); repaint(); } @Override public void mouseMoved(MouseEvent e) { } @Override public void paintComponent(Graphics g) { // 必须先调用父类方法,保证绘制环境正确 super.paintComponent(g); System.out.println("painting"); if (x == -1 || y == -1) return; g.drawOval(x, y, 10, 10); } }
第二步:移除PatternCreator里的错误代码
删掉构造函数中那行绑定错误监听器的代码:
public PatternCreator(){ createLayout(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); setVisible(true); // 删除这行错误的代码 // addMouseMotionListener(new PaintingField()); }
这样修改后,界面上的paintingField会正确监听鼠标拖拽事件,每次拖拽都会更新坐标并触发重绘,paintComponent也会被正常调用啦!如果之后你想保留所有绘制的圆形,可以把每次的坐标存到一个集合里,在paintComponent里遍历绘制所有圆形~
内容的提问来源于stack exchange,提问作者Rafał Prominski

