使用缓冲策略获取要绘制的图形对象

Getting graphics object to draw with buffer strategy

我制作了一个带有 canvas 的 JFrame,我想利用它 canvas。稍后 canvas 将每秒更新多次,因此我为此使用了缓冲策略。这是代码:

package mainPackage;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

public class TickPainter {
    //just some presets for a window.
    public static JFrame makeWindow(String title, int width, int height) {
        JFrame mainWindow = new JFrame();
        mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainWindow.setSize(width, height);
        mainWindow.setVisible(true);
        mainWindow.setLocationRelativeTo(null);
        mainWindow.setTitle(title);

        return mainWindow;      
    }

    public static void main(String[] args) {

        JFrame mainWindow = makeWindow("Practice", 800, 600);
        Canvas mainCanvas = new Canvas();
        mainWindow.add(mainCanvas);
        mainCanvas.setSize(mainWindow.getWidth(), mainWindow.getHeight());
        mainCanvas.setBackground(Color.white);
        mainCanvas.createBufferStrategy(3);
        BufferStrategy bufferStrat = mainCanvas.getBufferStrategy();

        Graphics g = bufferStrat.getDrawGraphics();
        g.setColor(Color.black);
        g.fillRect(250, 250, 250, 250);
        g.dispose();
        bufferStrat.show();
    }
}

程序没有按预期绘制黑色矩形,我觉得我在这里错过了一些非常明显的东西,我就是看不到它。目前程序只生成空白canvas。我觉得问题的一部分是缓冲区只是比我看到的更快地传递带有矩形的帧,但是在那之后没有要加载的帧所以我不知道它为什么这样做。

A BufferStrategy 有许多初始要求,必须满足这些要求才能呈现。此外,由于其工作方式的性质,您可能需要在硬件层实际接受之前多次重复绘制阶段。

我建议阅读 JavaDocs and tutorial,它们提供了宝贵的示例,说明您应该如何使用 BufferStrategy

以下示例使用 Canvas 作为基本组件并在自定义 Thread 中设置渲染循环。它非常基础,但展示了您需要实施的基本概念...

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TestCanvas canvas = new TestCanvas();

                JFrame frame = new JFrame();
                frame.add(canvas);
                frame.setTitle("Test");
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                canvas.start();
            }
        });
    }

    public class TestCanvas extends Canvas {

        private Thread thread;
        private AtomicBoolean keepRendering = new AtomicBoolean(true);

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        public void stop() {
            if (thread != null) {
                keepRendering.set(false);
                try {
                    thread.join();
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }

        public void start() {
            if (thread != null) {
                stop();
            }

            keepRendering.set(true);
            thread = new Thread(new Runnable() {
                @Override
                public void run() {

                    createBufferStrategy(3);

                    do {
                        BufferStrategy bs = getBufferStrategy();
                        while (bs == null) {
                            System.out.println("get buffer");
                            bs = getBufferStrategy();
                        }
                        do {
                            // The following loop ensures that the contents of the drawing buffer
                            // are consistent in case the underlying surface was recreated
                            do {
                                // Get a new graphics context every time through the loop
                                // to make sure the strategy is validated
                                System.out.println("draw");
                                Graphics graphics = bs.getDrawGraphics();

                                // Render to graphics
                                // ...
                                graphics.setColor(Color.RED);
                                graphics.fillRect(0, 0, 100, 100);
                                // Dispose the graphics
                                graphics.dispose();

                                // Repeat the rendering if the drawing buffer contents
                                // were restored
                            } while (bs.contentsRestored());

                            System.out.println("show");
                            // Display the buffer
                            bs.show();

                            // Repeat the rendering if the drawing buffer was lost
                        } while (bs.contentsLost());
                        System.out.println("done");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    } while (keepRendering.get());
                }
            });
            thread.start();
        }

    }

}

请记住,BufferStrategy 的要点是让您完全控制绘画过程,因此它在通常由 AWT 和 Swing 实现的正常绘画过程之外工作

"At a later date the canvas will be updating many times a second so I am using a buffer strategy for this" - 在使用 "direct to hardware" 解决方案之前,我会考虑使用 Swing Timer 和正常的绘画过程来看看效果如何