gpt4 book ai didi

java - 为什么我的自定义 JPanel 没有被绘制/重新绘制,即使我从事件队列中绘制并覆盖paintComponent()?

转载 作者:行者123 更新时间:2023-12-01 16:21:57 29 4
gpt4 key购买 nike

我试图制作我的第一个 Swing 应用程序,但我一生都无法弄清楚为什么没有任何内容被绘制,而我只得到一个空窗口。

我正在使用SwingUtilities.invokeLater要启动 AWT 事件队列线程,在我的 Controller 中我使用 SwingWorker doInBackground()对于我的主循环,处理我的模型代码。

我使用事件将更改从模型传递到 Controller ,然后 Controller 将其放入并发更改队列中, View 使用该队列来更新自身。

我已经研究了几个小时了,但仍然不知道为什么它不会画出来。我正在从事件队列线程进行绘画,我正在覆盖 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++;
}

}

Controller

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);
}
}


事件监听器接口(interface)和类

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();
}
}

最佳答案

I am using a SwingWorker doInBackground() for my Main Loop,

有几件事很突出:

model.nextGameLoopIteration();

这基本上是一个无限循环,因为你没有计时机制。对于游戏,您通常需要 Thread.sleep(...) 来允许游戏重新绘制自身并重置游戏状态。

此外,我实际上看到了第二个循环:

controller.start();

以上代码在EDT上执行。

在带有 while (true) 循环的 start() 方法中,您有:

Thread.sleep(Math.max(0, time - System.currentTimeMillis()));

因此这也是一个无限循环,将导致 EDT hibernate ,这意味着它无法响应事件或重新绘制 GUI。

不知道为什么你有两个循环,但你绝对不应该在 EDT 上 sleep 。

关于java - 为什么我的自定义 JPanel 没有被绘制/重新绘制,即使我从事件队列中绘制并覆盖paintComponent()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62246620/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com