使用createBufferStrategy()的正确方法是什么? [英] What is the correct way to use createBufferStrategy()?
问题描述
即使使用Java Swing超过一年,它对我来说仍然是神奇的。我如何正确使用BufferStrategy,特别是方法 createBufferSrategy()
?
Even after using Java Swing for over a year, it still seems like magic to me. How do I correctly use a BufferStrategy, in particular, the method createBufferSrategy()
?
我想要添加到它然后绘制的JFrame和Canvas。我还希望能够调整Canvas的大小( setSize()
)。每次我调整画布大小时,似乎我的 BufferStrategy
被删除,或者说变得无用,因为使用 show()
on BufferStrategy
实际上并没有做任何事情。此外, createBufferStrategy()
有一个奇怪的非确定性行为,我不知道如何正确同步它。
I would like to have a JFrame and a Canvas that gets added to it and then painted. I would also like to be able to resize (setSize()
) the Canvas. Every time I resize the Canvas it seems my BufferStrategy
gets trashed or rather, turns useless, since using show()
on the BufferStrategy
does not actually do anything. Also, createBufferStrategy()
has a weird non-deterministic behaviour and I don't know how to synchronize it correctly.
这就是我的意思:
public class MyFrame extends JFrame {
MyCanvas canvas;
int i = 0;
public MyFrame() {
setUndecorated(false);
setVisible(true);
setSize(1100, 800);
setLocation(100, 100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
canvas = new MyCanvas();
add(canvas);
canvas.makeBufferStrat();
}
@Override
public void repaint() {
super.repaint();
canvas.repaint();
//the bigger threshold's value, the more likely it is that the BufferStrategy works correctly
int threshold = 2;
if (i < threshold) {
i++;
canvas.makeBufferStrat();
}
}
}
MyCanvas
有一个方法 makeBufferStrat()
和 repaint()
:
public class MyCanvas extends Canvas {
BufferStrategy bufferStrat;
Graphics2D g;
public MyCanvas() {
setSize(800, 600);
setVisible(true);
}
public void makeBufferStrat() {
createBufferStrategy(2);
//I'm not even sure whether I need to dispose() those two.
if (g != null) {
g.dispose();
}
if (bufferStrat != null) {
bufferStrat.dispose();
}
bufferStrat = getBufferStrategy();
g = (Graphics2D) (bufferStrat.getDrawGraphics());
g.setColor(Color.BLUE);
}
@Override
public void repaint() {
g.fillRect(0, 0, 100, 100);
bufferStrat.show();
}
}
我只需拨打 MyFrame
's repaint()
来自main方法中while(true)循环的方法。
当阈值
很小(即2)时, bufferStrat.show()
约占70% case没有做任何事情 - JFrame在启动程序时仍然是灰色的。剩下的30%它绘制了矩形它应该如何。如果我 threshold = 200;
,绘画成功接近100%我执行程序的时间。 Javadoc说 createBufferStrategy()
可能需要一段时间,所以我认为这是问题所在。但是,如何正确同步和使用它?显然,我在这里做错了。我无法想象它应该如何被使用。
I simply call MyFrame
's repaint()
method from a while(true) loop in the main method.
When threshold
is small (i.e. 2), bufferStrat.show()
in about 70% of all cases doesn't do anything - the JFrame just remains gray upon starting the program. The remaining 30% it paints the rectangle how it's supposed to. If I do threshold = 200;
, the painting succeeds close to 100% of the time I execute the program. Javadoc says that createBufferStrategy()
may take a while, so I assume that's the issue here. However, how do I synchronize and use it properly? Clearly, I'm doing something wrong here. I can't imagine that's how it's supposed to be used.
有没有人有一个最小的工作示例?
Does anyone have a minimal working example?
推荐答案
方式你创建 BufferStrategy
是好的,你可以看一下 JavaDocs for BufferStrategy
,它有一个简洁的例子。
The way you create the BufferStrategy
is "okay", you could have a look at the JavaDocs for BufferStrategy
which has a neat little example.
您使用它的方式值得怀疑。使用 BufferStrategy
的主要原因是因为你想要控制绘画过程(主动绘画)远离Swing的绘画算法(这是被动的)
The way you're using it, is questionable. The main reason for using a BufferStrategy
is because you want to take control of the painting process (active painting) away from Swing's painting algorithm (which is passive)
但是,你似乎试图同时做这两件事,这就是为什么它会导致你的问题。相反,你应该有一个主循环,负责决定缓冲区应该绘制的内容和时间,例如......
BUT, you seem to trying to do both, which is why it's causing your issues. Instead, you should have a "main" loop which is responsible for deciding what and when the buffer should paint, for example...
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferStrategy;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane testPane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(testPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// The component needs to be attached to displayed window before
// the buffer can be created
testPane.startPainting();
}
});
}
public class TestPane extends Canvas {
private AtomicBoolean painting = new AtomicBoolean(true);
private PaintCycle paintCycle;
private Rectangle clickBounds;
public TestPane() {
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (clickBounds != null && clickBounds.contains(e.getPoint())) {
painting.set(false);
}
}
});
}
public void startPainting() {
if (paintCycle == null) {
createBufferStrategy(2);
painting.set(true);
paintCycle = new PaintCycle();
Thread t = new Thread(paintCycle);
t.setDaemon(true);
t.start();
}
}
public void stopPainting() {
if (paintCycle != null) {
painting.set(false);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public class PaintCycle implements Runnable {
private BufferStrategy strategy;
private int xDelta = 2;
private int yDelta = 2;
@Override
public void run() {
System.out.println("Painting has started");
int x = (int) (Math.random() * (getWidth() - 40));
int y = (int) (Math.random() * (getHeight() - 40));
do {
xDelta = (int) (Math.random() * 8) - 4;
} while (xDelta == 0);
do {
yDelta = (int) (Math.random() * 8) - 4;
} while (yDelta == 0);
clickBounds = new Rectangle(x, y, 40, 40);
strategy = getBufferStrategy();
while (painting.get()) {
// Update the state of the model...
update();
// Paint the state of the model...
paint();
try {
// What ever calculations you want to use to maintain the framerate...
Thread.sleep(40);
} catch (InterruptedException ex) {
}
}
System.out.println("Painting has stopped");
}
protected void update() {
int x = clickBounds.x + xDelta;
int y = clickBounds.y + yDelta;
if (x + 40 > getWidth()) {
x = getWidth() - 40;
xDelta *= -1;
} else if (x < 0) {
x = 0;
xDelta *= -1;
}
if (y + 40 > getHeight()) {
y = getHeight() - 40;
yDelta *= -1;
} else if (y < 0) {
y = 0;
yDelta *= -1;
}
clickBounds.setLocation(x, y);
}
protected void paint() {
// Render single frame
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
Graphics2D graphics = (Graphics2D) strategy.getDrawGraphics();
// Render to graphics
// ...
graphics.setColor(Color.BLUE);
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.setColor(Color.RED);
graphics.fill(clickBounds);
// Dispose the graphics
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
}
}
}
您还应该记住,Swing一直在使用DirectX或OpenGL管道,因为大约1.4(或者1.5)。使用 BufferStrategy
的主要原因是更直接访问硬件(无论如何,Swing非常接近)并直接控制绘制过程(现在这是唯一的原因)使用它)
You should also remember, Swing's been using either DirectX or OpenGL pipelines since about 1.4 (or maybe 1.5). The main reasons for using BufferStrategy
are more direct access to the hardware (which Swing is pretty close to anyway) AND direct control over the painting process (which is now really the only reason to use it)
这篇关于使用createBufferStrategy()的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!