我有一个在我的OSX笔记本电脑上运行良好的小型引擎,但在功能较弱的Linux PC上运行时会严重崩溃或严重滞后。我把代码最小化了,它只是一个小类,但完全相同的lagginess就在那里。我认为这与缓冲策略和线程有关。这是班级:
public class Test extends Canvas implements Runnable {
private Thread thread;
private boolean running = false;
public Test()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(1000, 1000));
frame.add(this);
frame.setVisible(true);
start();
}
public static void main(String[] args)
{
new Test();
}
public synchronized void start()
{
this.thread = new Thread(this);
this.thread.start();
this.running = true;
}
public synchronized void stop()
{
try
{
this.thread.join();
this.running = false;
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void run()
{
while(running)
{
render();
}
}
private void render()
{
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
this.createBufferStrategy(2);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, 1000, 1000);
g.dispose();
bs.show();
}
}
答案 0 :(得分:2)
我看到Canvas被漆成黑色之前的延迟。在将JFrame设置为可见之前,您必须在Canvas上绘制一些东西。
以下是我对您的代码所做的更改。
我使用了JPanel而不是Canvas。我使用JPanel获得自动双缓冲。
我通过调用SwingUtilities invokeLater方法启动了Swing应用程序。这将Swing组件的创建和执行放在Event Dispatch thread上。 Oracle和我坚持认为所有Swing应用程序都是以这种方式启动的。在这个解释的后面,你会明白为什么这是至关重要的。
我每250毫秒绘制一张白色图像,然后绘制一张黑色图像。这样,我确信绘画代码正常运作。
我将线程代码移到了自己的类中。我有一个问题,线程和JPanel使用布尔值通过将线程放在自己的类中,我可以为线程和JPanel创建单独的布尔值。
在JPanel paintComponent方法中,我在设置JFrame之前绘制了一些东西。
我设置了JPanel的首选大小,而不是JFrame的大小。无论如何,我想知道绘图板的大小。
在线程代码中,对绘图的方法调用JPanel放在SwingUtilities invokeLater方法内。这确保了绘制发生在Event Dispatch线程上,而定时循环在不同的线程中执行。这可确保GUI保持响应。
这是代码。
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawingTest extends JPanel {
private static final long serialVersionUID = 2584117430541789858L;
private DrawingTestRunnable drawingTestRunnable;
private boolean isWhite;
public DrawingTest() {
this.setPreferredSize(new Dimension(1200, 700));
this.isWhite = true;
JFrame frame = new JFrame("Drawing Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setVisible(true);
start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new DrawingTest();
}
});
}
public synchronized void start() {
drawingTestRunnable = new DrawingTestRunnable(this);
new Thread(drawingTestRunnable).start();
}
public boolean isWhite() {
return isWhite;
}
public void setWhite(boolean isWhite) {
this.isWhite = isWhite;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (isWhite) {
g.setColor(Color.WHITE);
} else {
g.setColor(Color.BLACK);
}
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.dispose();
}
public class DrawingTestRunnable implements Runnable {
private boolean isWhite;
private volatile boolean running;
private DrawingTest drawingTest;
public DrawingTestRunnable(DrawingTest drawingTest) {
this.drawingTest = drawingTest;
this.running = true;
}
@Override
public void run() {
long duration = 250L;
long startTime = System.currentTimeMillis();
while (running) {
repaintPanel();
long elapsedTime = System.currentTimeMillis() - startTime;
long loopDuration = Math.max((duration - elapsedTime), 5L);
sleep(loopDuration);
startTime = System.currentTimeMillis();
}
}
private void repaintPanel() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
drawingTest.repaint();
isWhite = !isWhite;
drawingTest.setWhite(isWhite);
}
});
}
private void sleep(long duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
}
}
public synchronized void setRunning(boolean running) {
this.running = running;
}
}
}