繁体   English   中英

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

[英]Why is my custom JPanel not being painted / repainted even though I'm painting from the Event Queue and overwriting paintComponent()?

我试图制作我的第一个 Swing 应用程序,但我一生都无法弄清楚为什么什么都没画,我只得到一个空的 Window。

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

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

我已经在这里呆了几个小时,仍然不知道为什么它不会画画。 我正在从事件队列线程中绘画,我正在覆盖paintComponent并调用super.paintComponent()就像它应该完成的那样(据我所知)。

sys.outs 表明应用程序逻辑的 rest 似乎工作正常。

我试图将代码缩减为必需品,但它仍然是一堵文字墙,对此感到抱歉。 它应该编译。

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

Model

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


事件监听器接口和 Class

import java.util.EventListener;

public interface ModelChangeListener extends EventListener {
          void  receiveModelChange( ModelChangeEvent e);
}

事件监听器 Class

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(...) 来允许游戏重新绘制自身并重置游戏 state。

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

controller.start();

上面的代码在 EDT 上执行。

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

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

所以这也是一个无限循环,会导致 EDT 休眠,这意味着它无法响应事件或重新绘制 GUI。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM