【问题标题】:Flickering white on canvas画布上闪烁的白色
【发布时间】:2014-08-24 22:37:17
【问题描述】:

我在发帖几分钟后想出了一个解决方案,但由于声誉低,我无法删除帖子

为了好玩,我决定开始做一些可能会在某个时候变成游戏的东西。

目前我正在尝试绘制一些圆圈并将它们沿给定方向移动。这会导致闪烁。我很可能监督了一些非常基本的事情,但我不知道为什么它渲染不流畅。

我的董事会课程看起来像(删除了我认为不必要的内容):

public class Board extends Canvas implements Runnable {

    public static void main(String[] args) {
        Board board = new Board();

        board.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));

        JFrame frame = new JFrame("Circles");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(board);
        frame.pack();

        frame.setVisible(true);

        board.start();
    }

    @Override
    public void run() {
        while (running) {
            process();
            repaint();

            try {
                Thread.sleep(15);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

绘制方法:

    public void paint(Graphics g1) {
        super.paint(g1);
        Graphics2D g = (Graphics2D) g1;
        for (Ball ball : Ball.BALLS) {
            g.drawOval((int) ball.getLocation().getX(), (int) ball.getLocation().getY(), ball.getRadius(),  ball.getRadius());
        }
    }

我的处理方法:

private void process() {
    if (utilities.randInt(1, 100) < 10 && Ball.getBallCount() < 40) {
        Ball.spawnNew(this);
    }
    for (Ball ball : Ball.BALLS) {
        ball.move(this);
    }
    Ball.BALLS.removeAll(Ball.TO_REMOVE);
    Ball.TO_REMOVE.clear();
}

move 方法基本上每次调用时都会将球的 x 值增加一个给定值(向右移动)。

就像我说的,我不确定它为什么会闪烁,所以如果您有任何指示,请告诉。

谢谢!

【问题讨论】:

    标签: java canvas flicker


    【解决方案1】:

    您需要双缓冲。为此,您需要创建一个BufferedImage 并从中获取Graphics。将所有内容绘制到图像上,将图像渲染到屏幕上,最后用背景颜色或图像填充图像以重置它。

    示例:

    //one time instantiation
    BufferedImage b = new BufferedImage(width, height, mode);
    

    paint(Graphics g):

    Graphics buffer = b.getGraphics();
    //render all of the stuff on to buffer
    Graphics2D g = (Graphics2D) buffer;
        for (Ball ball : Ball.BALLS) {
            g.drawOval((int) ball.getLocation().getX(), (int) ball.getLocation().getY(), ball.getRadius(),  ball.getRadius());
        }
    g1.drawImage(b, 0, 0, width, height, null);
    g.setColor(Color.BLACK);
    //reset the image
    g.drawRect(0, 0, width, height);
    g.dispose();
    

    【讨论】:

      【解决方案2】:

      这听起来像是您需要执行双缓冲的情况,这样您的画布的一个副本可以在您更新另一个副本时保持显示。

      您在这里使用的是 AWT,我不知道如何使用 AWT 手动实现双缓冲。但是,如果您愿意在这里使用 Swing,您可以利用自动双缓冲。请参阅有关 How to make canvas with Swing? 的问题以及 Oracle 技术网关于 Painting in AWT and Swing 的文章。

      基本思路是:

      1. 扩展 javax.swing.JPanel 而不是 Canvas(这意味着当您覆盖 paint(Graphics) 时,您现在是从 javax.swing.JComponent 而不是 java.awt.Component 覆盖它)
      2. 使用super(true) 创建一个构造函数以启用双缓冲。

      编辑:另外,as iccthedral points out,您最好覆盖paintComponent(Graphics) 并包括对super.paintComponent(Graphics) 的调用。见Difference between paint, paintComponent and paintComponents in Swing

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-02
        • 1970-01-01
        • 2012-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-24
        相关资源
        最近更新 更多