Java Swing调用repaint()未触发paint(Graphics)方法执行问题求助
问题核心原因
你遇到的repaint()不触发paint()的核心问题是JFrame实例混淆,除此之外还有不符合Swing绘制规范的问题,具体如下:
- 实例调用错误
你的View类本身已经继承了JFrame,但你在createFrame()方法中又重新创建了一个独立的JFrame对象frame,你调用setVisible()显示的是这个新创建的内部frame对象,而你在updateView()中调用repaint()的主体是当前View类实例,这个实例从未被设置为可见,自然不会触发它的paint()方法。 - 绘制逻辑不符合Swing规范
Swing不推荐直接重写JFrame的paint()方法,JFrame的绘制包含边框、标题栏等系统级元素,直接重写容易出现绘制偏移、闪烁等问题。正确的做法是自定义JPanel子类,重写其paintComponent()方法实现自定义绘制,再将面板添加到JFrame中。 - 不合理的静态变量设计
你将Model设置为静态变量,会导致状态全局耦合,后续扩展功能时容易出现不可预期的BUG,建议改为普通成员变量由外部注入。
修复方案
1. 修正View类逻辑
public class View extends JFrame{ // 删掉多余的内部JFrame变量 private JPanel drawPanel; // 去掉static修饰,改为普通成员变量 private Model model; public View(){ // 不要在这里创建Model,由Controller注入 } public void createFrame(){ // 直接操作当前View实例(本身就是JFrame) this.setSize(500,700); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("Breakout Ball"); // 新增自定义绘制面板 drawPanel = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; System.out.println("Hello"); // 非空判断避免空指针 if (model == null || model.getPaddle() == null) { return; } Paddle paddle = model.getPaddle(); Rectangle paddleImage = new Rectangle(paddle.getX(),paddle.getY(), paddle.getWidth(),paddle.getHeight()); g2.draw(paddleImage); } }; drawPanel.setBackground(Color.BLACK); this.add(drawPanel); this.setVisible(true); } public void updateView(Model modelArg){ this.model = modelArg; System.out.println("Hi there"); System.out.println(SwingUtilities.isEventDispatchThread()); // 调用绘制面板的repaint触发刷新 drawPanel.repaint(); } // 删除原来重写的paint方法、静态draw方法 }
2. 优化Controller游戏循环
你原来构造方法中的while循环只会触发两次刷新,不符合游戏的持续刷新需求,建议使用Swing Timer实现稳定的游戏循环,不会阻塞Swing事件调度线程:
public Controller(Model model, View view){ this.model = model; this.view = view; initView(); // 替换原来的while循环,16ms刷新一次约等于60帧 new Timer(16, e -> doCycle()).start(); }
内容的提问来源于stack exchange,提问作者Jon Cohen
相关产品推荐
相关产品推荐

