我试图制作我的第一个Swing应用程序,但我终生无法弄清为什么什么都没画,而我却只有一个空的Window。
我正在使用SwingUtilities.invokeLater
启动AWT事件队列线程,在我的控制器中,我正在将SwingWorker doInBackground()
用于我的主循环,正在处理我的模型代码。
我使用事件将更改从我的模型传递到控制器,然后控制器将其放入并发更改队列中,视图使用该队列来更新自身。
我已经在这里待了几个小时,但仍然不知道为什么它不会画画。我从事件队列线程中绘画,我重写paintComponent
并调用super.paintComponent()
,就像应该完成的(据我所知)。
sys.outs指示其余的应用程序逻辑似乎正常工作。
我试图将代码缩减为必需品,但这仍然是一堵墙,对此感到抱歉。它应该编译。
import javax.swing.SwingUtilities;
public class Application {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Controller controller = new Controller("Swing MVC Test Application");
controller.start();
}
});
}
}
型号
import javax.swing.event.EventListenerList;
public class Model {
private EventListenerList listeners = new EventListenerList();
private int[][] someChange = new int[][]{
{ 0,1},
{ 2,3},
{4,5}
};
private int gameLoopCounter = 0;
public Model(ModelChangeListener listener) {
listeners.add(ModelChangeListener.class, listener);
}
protected synchronized void notifyListeners(ModelChangeEvent event) {
for (ModelChangeListener l : listeners.getListeners(ModelChangeListener.class))
l.receiveModelChange(event);
}
public void nextGameLoopIteration() {
notifyListeners(new ModelChangeEvent(this, someChange[gameLoopCounter]));
gameLoopCounter++;
}
}
控制器
import javax.swing.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Controller implements ModelChangeListener {
private static final int QUEUE_SIZE = 20;
private Model model;
private View view;
public final BlockingQueue<ModelChangeEvent> changeQueue;
public Controller(String title) {
this.changeQueue = new ArrayBlockingQueue<ModelChangeEvent>(QUEUE_SIZE) ;
this.model = new Model(this);
this.view = new View(this, title);
}
public void start() {
SwingWorker<Void, Void> mainLoop = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
while (true) {
if (1 == 0) return null;
model.nextGameLoopIteration();
}
}
};
mainLoop.execute();
long time = System.currentTimeMillis();
while (true){
time += View.MILLIS_PER_LOOP;
try {
view.processModelUpdates();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(Math.max(0, time - System.currentTimeMillis()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void receiveModelChange(ModelChangeEvent e) {
try {
this.changeQueue.put(e);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
查看
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.TimeUnit;
public class View extends JPanel {
public static final int MILLIS_PER_LOOP = 1000;
private static final int CELLSIZE = 40;
private Controller controller;
private myPanel myPanel;
private ModelChangeEvent currentModelState;
public View(Controller controller, String title) throws HeadlessException {
this.controller = controller;
this.setSize(1500,1100);
initFrame(title);
}
private void initFrame(String title) {
JFrame frame = new JFrame(title);
frame.setContentPane(this);
frame.setSize(1600, 1200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void processModelUpdates() throws InterruptedException {
this.currentModelState = this.controller.changeQueue.poll(1, TimeUnit.SECONDS);
if (currentModelState != null) {
// do some processing....
this.repaint();
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// draw something
g.drawOval(currentModelState.getMovementExample()[0],
currentModelState.getMovementExample()[1],
CELLSIZE, CELLSIZE);
}
}
事件侦听器接口和类
import java.util.EventListener;
public interface ModelChangeListener extends EventListener {
void receiveModelChange( ModelChangeEvent e);
}
事件侦听器类
import java.util.EventObject;
public class ModelChangeEvent extends EventObject {
private int[] movementExample;
public int[] getMovementExample() {
return movementExample;
}
public ModelChangeEvent(Object source, int[] change) {
super(source);
movementExample = change;
}
@Override
public Object getSource() {
return super.getSource();
}
}
我在主循环中使用SwingWorker doInBackground(),
几件事突出:
model.nextGameLoopIteration();
这基本上是一个无限循环,因为您没有计时机制。对于游戏,通常需要Thread.sleep(…)才能允许游戏重新绘制自身并重置游戏状态。
而且,我实际上看到了第二个循环:
controller.start();
以上代码在EDT上执行。
在具有一会儿(true)循环的start()方法中,您有:
Thread.sleep(Math.max(0, time - System.currentTimeMillis()));
因此,这也是一个无限循环,将导致EDT进入睡眠状态,这意味着它无法响应事件或重新绘制GUI。
不确定为什么有两个循环,但是绝对不应该在EDT上睡觉。