带有延迟的while循环使JFrame无响应

2022-01-24 00:00:00 loops while-loop java jframe

因此,当我运行此代码时,我的 JFrame 变得无响应.我设法将其追溯到 gameLoop() 下的 while 循环.无论使用在其中调用 Thread.sleep() 的 delay(1000/FRAMERATE),它都不会允许 Key 或 Mouse Listeners 完成他们的工作.

So, my JFrame becomes unresponsive when I run this code. I managed to trace it back to the while loop under gameLoop(). Regardless of using delay(1000/FRAMERATE) which calls Thread.sleep() within it, it will not allow the Key or Mouse Listeners to do their job.

完整代码如下,gameLoop()中存在问题

Full code below, problem exists in gameLoop()

package me.LemmingsGame;

import java.awt.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;

public class Game extends JFrame implements KeyListener, MouseListener{

    private World wrld;//reference to current world
    private WorldFile loader=null;//world data

    private int gateCounter;

    private int width,height; //width and height of level

    private int mx,my;

    private int tool = Lemming.CLIMB;
    private Image dbImage; private Graphics dbg; //backbuffer  
    private Image [] sprites;//all images used in game

    private Lemming[] lemmings; //array of all Lemmings in level
    private int nextLem;//next Lemming to be received from Gate class

    private int running;//state of game
    private static final int FRAMERATE=180;//assigned framerate

    public Game(WorldFile loader){
        super("Lemmings");
        setLocation(50,40);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        width=3+loader.x*10;height=29+loader.y*10;
        loadImages();
        lemmings=new Lemming[loader.noLemmings*loader.gates().length];
        setSize(width,height);
        setVisible(true);   
        addMouseListener(this);
        addKeyListener(this);
        this.loader=loader;
        running=2;
        dbImage= createImage(width,height);
        dbg=dbImage.getGraphics();
        wrld=new World(loader,createImage(width,height), sprites, this);
        gameLoop();
    }
    public void loadImages(){
        sprites=new Image[2];
        sprites[0]=new ImageIcon("Resources/toolbar.png").getImage();
        sprites[1]=new ImageIcon("Resources/selector.png").getImage();
    }
    public static void delay(long len){
        try{
            Thread.sleep(len);
        }catch(InterruptedException e){
            System.out.println(e);
        }
    }
    public void moveLemmings(){
        if(nextLem>0)
            for(int i = 0;i<nextLem;i++)
                lemmings[i].cycle();
    }
    public void gameLoop(){

        wrld.openGates();
        while(running>0){
            delay(1000/FRAMERATE);
            if(running==2){
                gateCounter++;
                if(gateCounter>FRAMERATE*2){
                    wrld.cycleGates();
                    gateCounter=0;
                }
                moveLemmings();
                if(nextLem>0)
                    wrld.checkPositions(lemmings,nextLem);
            }
            repaint();
            //paint(getGraphics());
        }
    }
    public void paint(Graphics g){
        if(wrld!=null){
            dbg.setColor(Color.BLACK);
            dbg.fillRect(0, 0, width, height);
            wrld.draw(dbg);
            if(nextLem>0)
                for(int i=0;i<nextLem;i++){
                    lemmings[i].draw(dbg);
                }
            dbg.drawImage(sprites[0],0,0,null);
            dbg.drawImage(sprites[1],tool-3*39,0,null);
            g.drawImage(dbImage,3,29,this);
        }
    }
    public void addLemming(Lemming lemmy) {
        lemmings[nextLem]=lemmy;
        lemmy.spawn();
        nextLem++;
    }
    public void goal(){
        running=0;
        dispose();
        new Menu();
    }
    public void fail(){
        running=0;
        dispose();
        new Menu();
    }
    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void keyTyped(KeyEvent e) {}
    public void mousePressed(MouseEvent e) {
        System.out.println("boop");
        mx=e.getX();
        my=e.getY();
        if(my<40)
            if(mx<40)
                tool=Lemming.CLIMB;
            else if(mx>39&&mx<=39*2)
                tool=Lemming.CHUTE;

    }
    public void mouseReleased(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }
    public void keyPressed(KeyEvent e) {
        System.out.println("boop2");
    }

    public void keyReleased(KeyEvent e) {

    }
}

如果重要,程序从这里开始并进入游戏类

If it matters the program begins here and goes to the Game class

package me.LemmingsGame;

import java.awt.*;
import java.awt.event.*;
import java.io.File;

import javax.swing.*;

public class Menu extends JFrame implements ActionListener{
    /**
     * 
     */
    private static final long serialVersionUID = -1448646591011984524L;
    private JComboBox worldList;
    private JButton launch, worldEditor;
    private String [] worldPaths;
    private String [] worldNames;
    private int currentWorld;
    public Menu(){
        super("Lemmings! By: Jordan and Seth");
        this.setLocation(new Point(550,400));
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        File listDir[] = new File("./Worlds").listFiles();
        int x=0;
        for (int i = 0; i < listDir.length; i++) 
            if (listDir[i].isDirectory()) 
                   x++;
        worldPaths=new String[x];
        worldNames=new String[x];
        x=0;
        for (int i = 0; i < listDir.length; i++) 
            if (listDir[i].isDirectory()){ 
                    worldPaths[x]=listDir[i].getPath().substring(2);    
                    worldNames[x]=worldPaths[x].substring(7);
                    x++;
            }
        worldList=new JComboBox(worldNames);
        worldList.addActionListener(this);
        worldEditor=new JButton("Open World Editor");
        worldEditor.addActionListener(this);
        launch = new JButton("Play");
        launch.addActionListener(this);
        Container cp = getContentPane();
        cp.setLayout(new FlowLayout());
        cp.add(worldEditor);
        cp.add(worldList);
        cp.add(launch);
        pack();
        setVisible(true);
    }
    public void actionPerformed(ActionEvent e){
        if(e.getSource()==worldEditor){
            dispose();
            new MapEditor();
        }else if(e.getSource()==launch){
            dispose();
            try {
                new Game(new WorldFile(worldPaths[currentWorld]));
            } catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
        }else if(e.getSource()==worldList){
            currentWorld=worldList.getSelectedIndex();
        }
    }
    public static void main(String [] args){
        new Menu();
    }
}

可能无关紧要,但这是 github 存储库的插件 https://github.com/cybnetsurfe3011/Lemmings-计算机-科学/

Probably irrelevant, but here's a plug to the github repo https://github.com/cybnetsurfe3011/Lemmings-Computer-Science/

推荐答案

您正在主线程中执行 Thread.sleep(),在本例中是 EDT(事件调度线程).该线程负责绘制图形和监听事件.通过执行 Thread.sleep() 您实际上是在暂停它,因此不允许它完成它的工作.

You are performing Thread.sleep() in your main thread which in this case is the EDT (Event Dispatcher Thread). This thread is responsible for painting your graphics and listening to events. By doing Thread.sleep() you are essentially pausing it, thus not allowing it to do it's job.

您似乎想每隔一段时间刷新一次 GUI(至少我是这么猜测的).如果是这种情况,您将需要将您的逻辑移动到一个新的单独线程,然后从您将产生的线程中调用您需要的任何更新方法.要使更改可见,您需要使用 SwingUtilities.invokeLater() 方法.

It seems that you want to refresh your GUI at intervals (at least that is what I am guessing). If this is the case, you will need to move your logic to a new separate thread and then, call what ever update methods you will need from the thread you will have spawned off. To make changes visible, you will need to call the event dispatcher thread again by using the SwingUtilities.invokeLater() method.

相关文章