【发布时间】:2017-04-11 15:58:39
【问题描述】:
我正在开发一个 Java awt 应用程序。我们目前有一个实现可运行并为我们的应用程序中的对象调用渲染的类。我们还有键盘和鼠标监听器,它们调用各种对象的函数。我注意到当多个键被快速按下时会发生一个奇怪的错误,经过一些调查后,似乎事件侦听器被异步调用,与正在执行渲染的主线程分开。任何人都可以确认 Java awt 事件侦听器是异步调用的,并提出可能的解决方案吗?
public class Driver extends Canvas implements Runnable
{
private boolean running = false;
private Integer frames;
private Thread thread;
private Window window;
private Mouse mouse;
private Keyboard keyboard;
/**
* Constructor of Driver
* Initiates Window, Mouse, Keyboard, handlers
*/
public Driver()
{
window = new Window("Dominion", this);
mouse = new Mouse(this);
keyboard = new Keyboard(this);
}
/**
* updates classes/variables that change per frame
*/
public void tick() {
//Framerate independent calls
}
/**
* Draws the game onto the window
* Calls other handler render to draw their parts
*/
public void render()
{
BufferStrategy bs = this.getBufferStrategy();
if (bs == null)
{
this.createBufferStrategy(2);
return;
}
Graphics g = bs.getDrawGraphics();
//Start Graphics
g.setColor(Color.WHITE);
g.fillRect(0, 0, window.getWidth(), window.getHeight());
//Rest of rendering
//End Graphics
g.dispose();
bs.show();
}
/**
* Starts thread
*/
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
/**
* Stops thread
*/
public synchronized void stop() {
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Important game function that calls the render and tick methods
*/
public void run() {
this.requestFocus();
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
tick();
delta--;
}
if (running)
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
stop();
}
/**
* getter for window
* @return window
*/
public Window getWindow()
{
return window;
}
/**
* Starts up the whole Client side of things
*/
public static void main(String[] args)
{
new Driver();
}
}
和鼠标
public class Mouse implements MouseListener, MouseMotionListener, MouseWheelListener{
private Driver d;
/**
* Creates a Mouse object
* @param driver
*/
public Mouse(Driver driver) {
this.d = driver;
d.addMouseListener(this);
d.addMouseMotionListener(this);
d.addMouseWheelListener(this);
}
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
* @param e
*/
@Override
public void mouseClicked(MouseEvent e) {
}
//Other methods cut out
}
【问题讨论】:
-
你倒退了。它的 your 应用程序没有与 Swing 正确同步。 Swing 在它自己的线程上做所有事情(Event Disptach Thread = EDT)。在 EDT 之外做事是最常见的错误之一,会导致虚假且难以发现的错误。
-
哦,好的,我该如何解决这个问题?
-
取决于程序到底想做什么。您可以在 EDT 上运行整个逻辑(例如,使用 Swing 计时器,或严格事件驱动),或者如果您需要使用多个线程,您可以使用 SwingUtilities.invoke(Later) 在 GUI 中安排更新。不用说,如果没有某种 形式的同步,您无法 在线程之间共享数据。必须绝对避免渲染一个可能被另一个线程同时修改的模型对象。
-
好的,谢谢。我想我可以用 Swing 计时器解决这个问题。如果您想在答案中发表评论,我想我可以接受。