You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何BufferStrategy在渲染循环外调用show()会刷新/无法正常显示?

关于Java Canvas BufferStrategy的问题解答

问题重现

第一段代码调用bs.show()后窗口瞬间黑屏然后无内容:

import java.awt.*;
import javax.swing.*;

public class Main {
    static int width = 200;
    static int height = 200 ;

    public static void main(String[] args){
        JFrame jframe = new JFrame();
        Canvas canvas = new Canvas();
        BufferStrategy bs;
        Dimension dim = new Dimension(width,height);

        canvas.setPreferredSize(dim);
        jframe.setResizable(false);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.add(canvas);
        jframe.pack();
        jframe.setLocationRelativeTo(null);
        jframe.setVisible(true);
        canvas.requestFocus();

        bs = canvas.getBufferStrategy();
        if(bs == null){
            canvas.createBufferStrategy(3);
            bs = canvas.getBufferStrategy();
        }
        Graphics g = bs.getDrawGraphics();
        g.setColor(Color.black);
        g.fillRect(0,0,canvas.getWidth(),canvas.getHeight());
        g.dispose();
        bs.show();
    }
}

改成循环调用bs.show()则能正常显示黑色:

while(true){
    bs.show();
}

带休眠的循环也能正常显示(补充异常捕获):

while(true){
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    bs.show();
}

问题解答

1. 第一段代码黑色不显示的原因及相关疑问

  • 根本原因:不是bs.show()清空了缓冲区,而是Swing的事件调度线程(EDT)在你调用完bs.show()后,触发了Canvas的自动重绘。Canvas默认的paint方法会清空组件背景(回到默认浅色),直接覆盖了你用BufferStrategy画的黑色。而且main方法执行完毕后,EDT仍会持续处理窗口的重绘请求,导致刚画的黑色瞬间被冲掉。
  • bs.show()的作用:它仅负责交换缓冲区,把你绘制好的后台缓冲区切换到前台显示,本身不会主动清空任何缓冲区。
  • 第三段代码能显示的原因:循环里反复调用bs.show(),相当于每次都把存着黑色内容的后台缓冲区重新切换到前台。哪怕EDT触发重绘清空了当前前台内容,下一次bs.show()又会把黑色缓冲区换上来,所以你能持续看到黑色,和休眠时长无关。

2. 无需循环让黑色持续显示的方法

有两种简单可行的方式:

  • 方式一:关闭Canvas的自动重绘
    创建Canvas后添加一行代码,阻止Swing自动触发重绘:
    canvas.setIgnoreRepaint(true);
    
    同时要确保main线程不提前结束,可在代码末尾加阻塞逻辑:
    // 监听窗口关闭事件,确保程序正常退出
    jframe.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosed(WindowEvent e) {
            System.exit(0);
        }
    });
    // 让main线程持续阻塞
    try {
        Thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    
  • 方式二:重写Canvas的paint方法
    直接在paint方法里绘制黑色,贴合Swing的重绘机制,每次重绘都会重新生成黑色背景:
    Canvas canvas = new Canvas() {
        @Override
        public void paint(Graphics g) {
            g.setColor(Color.black);
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    };
    

内容的提问来源于stack exchange,提问作者jacob12

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 22:50:19