简体   繁体   English

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

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

I trying to make my first Swing application and i cannont for the life of me figure out why nothing is painted and I only get an empty Window.我试图制作我的第一个 Swing 应用程序,但我一生都无法弄清楚为什么什么都没画,我只得到一个空的 Window。

I am using SwingUtilities.invokeLater to start the AWT Event Queue Thread, in my Controller I am using a SwingWorker doInBackground() for my Main Loop, processing my Model code.我正在使用SwingUtilities.invokeLater来启动 AWT 事件队列线程,在我的 Controller 中我正在为我的主循环使用SwingWorker doInBackground() ,处理我的 Model 代码。

I use events to pass changes from my model to the controller who then puts it in a concurrent change queue which the View uses to update itself.我使用事件将更改从我的 model 传递到 controller,然后 controller 将其放入 View 用来更新自身的并发更改队列中。

I have been at this for hours and still no idea why it won't paint.我已经在这里呆了几个小时,仍然不知道为什么它不会画画。 I'm painting from the Event Queue Thread, I'm overriding paintComponent and call super.paintComponent() like it's supposed to be done (to my knowledge).我正在从事件队列线程中绘画,我正在覆盖paintComponent并调用super.paintComponent()就像它应该完成的那样(据我所知)。

The sys.outs indicate that the rest of the application logic seem to work fine. sys.outs 表明应用程序逻辑的 rest 似乎工作正常。

I tried to cut down the code to the necessities but it's still a wall of text, sorry for that.我试图将代码缩减为必需品,但它仍然是一堵文字墙,对此感到抱歉。 It should compile though.它应该编译。

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



View看法

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


Event Listener Interface and Class事件监听器接口和 Class

import java.util.EventListener;

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

Event Listener Class事件监听器 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();
    }
}

I am using a SwingWorker doInBackground() for my Main Loop,我正在为我的主循环使用 SwingWorker doInBackground(),

A couple of things stick out:有几件事很突出:

model.nextGameLoopIteration();

That is basically an infinite loop since you don't have a timing mechanism.这基本上是一个无限循环,因为您没有计时机制。 For a game you would generally need a Thread.sleep(…) to allow the game to repaint itself and reset the game state.对于游戏,您通常需要一个 Thread.sleep(...) 来允许游戏重新绘制自身并重置游戏 state。

Also, I actually see a second loop:此外,我实际上看到了第二个循环:

controller.start();

The above code is executed on the EDT.上面的代码在 EDT 上执行。

In the start() method withing a while (true) loop you have:在带有 while (true) 循环的 start() 方法中,您有:

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

So this is also an infinite loop which will cause the EDT to sleep, meaning it can't respond to events or repaint the GUI.所以这也是一个无限循环,会导致 EDT 休眠,这意味着它无法响应事件或重新绘制 GUI。

Not sure why you have two loops, but you definitely should not be sleeping on the EDT.不知道为什么你有两个循环,但你绝对不应该在 EDT 上睡觉。

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

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