- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
即使在使用 Java Swing 一年多之后,它对我来说仍然像魔法一样。如何正确使用 BufferStrategy,特别是 createBufferSrategy()
方法?
我想要一个 JFrame 和一个 Canvas,将其添加到其中然后进行绘制。我还希望能够调整 Canvas 的大小(setSize()
)。每次我调整 Canvas 大小时,我的 BufferStrategy
似乎都会被丢弃,或者更确切地说,变得毫无用处,因为在 BufferStrategy
上使用 show()
实际上并没有做任何事情。另外,createBufferStrategy()
有一个奇怪的非确定性行为,我不知道如何正确同步它。
这就是我的意思:
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();
}
}
我只是从 main 方法中的 while(true) 循环调用 MyFrame
的 repaint()
方法。当 threshold
很小(即 2)时,大约 70% 的情况下 bufferStrat.show()
不会执行任何操作 - JFrame 在启动程序时只是保持灰色。剩下的 30% 按照预期的方式绘制矩形。如果我执行 threshold = 200;
,则在执行程序时绘画几乎 100% 都会成功。 Javadoc 说 createBufferStrategy() 可能需要一段时间,所以我认为这就是问题所在。但是,如何同步并正确使用它呢?显然,我在这里做错了什么。我无法想象它应该如何使用。
有人有一个最小的工作示例吗?
最佳答案
您创建BufferStrategy
的方式是“好的”,您可以看看JavaDocs for BufferStrategy
其中有一个简洁的小例子。
您使用它的方式值得怀疑。使用 BufferStrategy 的主要原因是您想要控制绘制过程(主动绘制),远离 Swing 的绘制算法(被动)
但是,您似乎试图两者兼而有之,这就是导致您出现问题的原因。相反,您应该有一个“主”循环,它负责决定缓冲区应该绘制什么以及何时绘制,例如......
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 从 1.4(或者可能是 1.5)开始就一直在使用 DirectX 或 OpenGL 管道。使用 BufferStrategy 的主要原因是更直接地访问硬件(无论如何 Swing 都非常接近)和直接控制绘画过程(这实际上是现在使用它的唯一原因)
关于java - 使用 createBufferStrategy() 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35516191/
我正在学习 BufferStrategy,但我对 BS 的创建有点困惑。 我的代码看起来像这样... public class Game extends Canvas{ /*code not
标题大致概括了这一点。为什么我不能这样做? private void render() { bs = window.getCanvas().getBufferStrategy(); i
即使在使用 Java Swing 一年多之后,它对我来说仍然像魔法一样。如何正确使用 BufferStrategy,特别是 createBufferSrategy() 方法? 我想要一个 JFrame
错误: Exception in thread "main" java.lang.IllegalStateException: Component must have a valid peer at
我开始使用 Java 创建游戏。在我的 render() 方法中,我有一个缓冲区策略,具有三个缓冲区。但是,当我运行它时,我收到此错误。 Exception in thread "Thread-1"
我有一些网格被一一绘制到屏幕上。我使用箭头键将网格作为一个组移动。 Swing 据说默认情况下是双缓冲的,所以我相信 frame.createBufferStrategy(2) 是一个不好的做法,但问
似乎大多数人建议只使用 2 或 3。这是否只是因为超过 3 占用了太多的处理能力或其他原因(请原谅我是新手)?你会在什么样的程序中使用 3 个以上的缓冲区? 2 或 3 适合我的程序,我只是好奇。 最
我是一名优秀的程序员,十分优秀!