更详细地说,我有一个附加到JFrame的componentResized事件(它包含画布,没有别的),并且在那个事件中调用一个方法来相应地设置画布的边界。这很好,除了我调整画布大小时,它没有任何显示。我只看到JFrame的背面。一旦我停止调整JFrame的大小,画布就会重新打印。
public class MyCanvas implements ComponentListener {
public static void main(String[] args) {
new MyCanvas("MyCanvas",new Dimension(300,300));
}
private static final int frameRate = 30;
private JFrame frame;
private JPanel panel;
private Canvas canvas;
private BufferStrategy strategy;
private int delta;
private boolean running = false;
private int frameCount = 0;
public MyCanvas(String name, Dimension size) {
frame = new JFrame(name);
panel = (JPanel) frame.getContentPane();
canvas = new Canvas();
frame.setSize(size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(size);
panel.setLayout(null);
canvas.setBounds(0,0,size.width,size.height);
panel.add(canvas);
canvas.setIgnoreRepaint(true);
frame.setResizable(true);
frame.pack();
frame.addComponentListener(this);
canvas.createBufferStrategy(2);
strategy = canvas.getBufferStrategy();
running = true;
frame.setVisible(true);
long lastLoopTime = 0;
while (running) {
frameCount++;
delta = (int) (System.currentTimeMillis() - lastLoopTime);
lastLoopTime = System.currentTimeMillis();
Graphics2D graphics = (Graphics2D) strategy.getDrawGraphics();
graphics.setColor(Color.black);
graphics.fillRect(0,0,getSize().width,getSize().height);
graphics.dispose();
strategy.show();
try {
Thread.sleep(1000/frameRate);
} catch (InterruptedException e) {}
}
}
public final Dimension getSize() {
return frame.getSize();
}
public final void setSize(Dimension size) {
frame.setSize(size);
canvas.setBounds(0,0,size.width,size.height);
}
public synchronized void componentResized(ComponentEvent e) {
setSize(frame.getSize());
}
public synchronized void componentHidden(ComponentEvent e) {
// unused
}
public synchronized void componentShown(ComponentEvent e) {
// unused
}
public synchronized void componentMoved(ComponentEvent e) {
// unused
}
}
修改
经过一段时间的代码调整后,我想出了一个解决方案:
public class MyCanvas {
public static void main(String[] args) {
new MyCanvas("MyCanvas",new Dimension(400,400));
}
private static final int frameRate = 1000 / 30;
private JFrame frame;
private JPanel panel;
private int delta;
private long lastLoopTime;
private boolean running = false;
private int frameCount = 0;
private BufferedImage backBuffer = null;
private int lastPaintFrame = -1;
public MyCanvas(String name, Dimension size) {
frame = new JFrame(name);
panel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
redraw(g);
}
};
frame.setContentPane(panel);
frame.setSize(size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(size);
panel.setLayout(null);
frame.setResizable(true);
running = true;
frame.setVisible(true);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
backBuffer = new BufferedImage(screenSize.width,screenSize.height,BufferedImage.TYPE_INT_ARGB);
lastLoopTime = System.nanoTime();
while (running) {
long thisLoopTime = System.nanoTime();
delta = (int) ((thisLoopTime - lastLoopTime) / 1000000);
draw(backBuffer.getGraphics());
frameCount++;
lastLoopTime = thisLoopTime;
redraw(panel.getGraphics());
try {
Thread.sleep(1000/30);
} catch (InterruptedException e) {}
}
}
private final void redraw(Graphics g) {
if (g != null && backBuffer != null) {
g.drawImage(backBuffer,0,0,null);
}
}
int x = 30;
public final void draw(Graphics g) {
g.setColor(Color.darkGray);
g.fillRect(0,0,getSize().width,getSize().height);
g.setColor(Color.gray);
g.fillRect(0,0,500,500);
g.setColor(Color.blue);
g.fillRect(x,30,300,300);
x++;
}
public final Dimension getSize() {
return frame.getSize();
}
public final void setSize(Dimension size) {
frame.setSize(size);
}
}
然而,这还没有完全解决,因为它仍然有奇怪的小图形故障,只有当从面板的paintComponent方法调用重绘时才会出现,尽管不一致。那些毛刺表现为奇怪的颜色矩形(通常是黑色或灰色),它们会立即消失。我真的不确定它可能是什么......也许是双缓冲的问题?顺便说一句,如果我在paintComponent中抛出一个运行时异常,那就完美了。
如果这应该转移到一个新问题,请告诉我。
答案 0 :(得分:0)
我找到了解决方案:绘制和更新的不同循环:
public class MyCanvas {
public static void main(String[] args) {
new MyCanvas("MyCanvas",new Dimension(400,400));
}
private static final int frameRate = 1000 / 30;
private JFrame frame;
private JPanel panel;
private int delta;
private long lastLoopTime;
private volatile boolean running = false;
private int frameCount = 0;
public MyCanvas(String name, Dimension size) {
frame = new JFrame(name);
panel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
if (running) repaint();
}
};
frame.setContentPane(panel);
frame.setSize(size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(size);
panel.setLayout(null);
frame.setResizable(true);
running = true;
frame.setVisible(true);
lastLoopTime = System.nanoTime();
new Thread(()->{
while (running) {
update();
frameCount++;
try {
Thread.sleep(frameRate);
} catch (InterruptedException e) {}
}
},"Game Loop").start();
}
int x = 30;
public final void update() {
x++;
}
public final void draw(Graphics g) {
g.setColor(Color.darkGray);
g.fillRect(0,0,getSize().width,getSize().height);
g.setColor(Color.gray);
g.fillRect(0,0,500,500);
g.setColor(Color.blue);
g.fillRect(x,30,300,300);
}
public final Dimension getSize() {
return frame.getSize();
}
public final void setSize(Dimension size) {
frame.setSize(size);
}
}