Java:repaint()没有在for循环中调用paintComponent()

问题描述 投票:2回答:1

这是我在stackoverflow上的第一篇文章,我希望有人可以帮助我解决我在这里遇到的问题。

我正在处理的问题是repaint()问题,有些人会认为我在这些论坛上没有足够的搜索来解决我的问题,但我已经看了很多,但没有任何工作。在下面的代码中,我尝试在for循环中调用drawB,无论数组多大,这个代码都能正常运行。 for循环调用drawB 20次左右。在drawB中,我希望设置一个图像(它将根据数组中的数字而不同)然后调用repaint(),然后调用子类GameCanvas中的paintComponent()

问题是paintComponant根本没有在这个初始化中运行。然而,repaint() DOES在我制作gameLoop()的循环中运行,但我需要在gameLoop()之前进行初始化。

任何人都知道发生了什么,或者如何解决它?

package engine;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.*;

public class GameMain extends JFrame // main class for the game as a Swing application
{     

    // Define constants for the game
    static final int CANVAS_WIDTH = 800;    // width and height of the game screen
    static final int CANVAS_HEIGHT = 600;
    static final int UPDATE_RATE = 4;    // number of game update per second
    static final long UPDATE_PERIOD = 1000000000L / UPDATE_RATE;  // nanoseconds

    String path;
    BufferedImage image;

    private GameCanvas canvas;

    // Constructor to initialize the UI components and game objects
    public GameMain() 
    {
        gameInit();

        image = null;
        canvas = new GameCanvas();
        canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
        this.setContentPane(canvas);


        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.pack();
        this.setTitle("Blockcraft!");
        this.setVisible(true);
    }

    public void gameInit() 
    {
        dispArray();
        gameStart();
    }

    public void dispArray() 
    {
        int tempLevel[][] = new int[][] {{1,1,1,1},{6,2,2,2},{3,3,3,3},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4},{4,4,4,4}};
        int widthTemp = tempLevel[0].length;
        int heightTemp = tempLevel.length;

        for(int i = 0; i < heightTemp; i++)
        {
            for(int j = 0; j < widthTemp; j++)
            {
                try
                {
                    image = ImageIO.read(getFile());
                }
                catch (Exception e) 
                {
                    e.printStackTrace();
                }
                drawB(image);
            }
        }
    }

    public File getFile() 
    {
        path = "images//1.jpg";
        File file = new File(path);
        return file;
    }

    public void drawB(BufferedImage imgTemp) 
    {
        image = imgTemp;
        repaint();
    }

    private void gameLoop() 
    {
        long beginTime, timeTaken, timeLeft;
        while (true) 
        {
            repaint();

            beginTime = System.nanoTime();

            timeTaken = System.nanoTime() - beginTime;
            timeLeft = (UPDATE_PERIOD - timeTaken) / 1000000L;  // in milliseconds
            if (timeLeft < 10) timeLeft = 10;   // set a minimum
            try 
            {
                Thread.sleep(timeLeft);
            }    
            catch (InterruptedException ex)
            { 
                //
            }
        }
    }

    // Refresh the display. Called back via repaint(), which invoke the paintComponent().
    private void gameDraw(Graphics2D g2d) 
    {
        g2d.drawImage(image, 0, 0, 15, 15, this);
    }

    public void gameKeyPressed(int keyCode)
    {
        //
    }

    public void gameKeyReleased(int keyCode) 
    {
       //
    }

    public void gameKeyTyped(char keyChar) 
    {
       //
    }

    class GameCanvas extends JPanel implements KeyListener
    {
        boolean paintAll;
        int xPos, yPos;
        Image img;

        public GameCanvas() 
        {
            setFocusable(true);  
            requestFocus();
            addKeyListener(this);
        }

        // Override paintComponent to do custom drawing.
        // Called back by repaint()... sometimes?
        @Override
        public void paintComponent(Graphics g) 
        {
            System.out.println("repainting");
            Graphics2D g2d = (Graphics2D)g;

            // Draw the game objects
            gameDraw(g2d);
        }


        // KeyEvent handlers
        @Override
        public void keyPressed(KeyEvent e) 
        {
            gameKeyPressed(e.getKeyCode());
        }

        @Override
        public void keyReleased(KeyEvent e) 
        {
            gameKeyReleased(e.getKeyCode());
        }

        @Override
        public void keyTyped(KeyEvent e) 
        {
            gameKeyTyped(e.getKeyChar());
        }
    }

    // To start and re-start the game.
    public void gameStart() 
    { 
        // Create a new thread
        Thread gameThread =  new Thread() 
        {
            // Override run() to provide the running behavior of this thread.
            @Override
            public void run() 
            {
                gameLoop();
            }
        };
        // Start the thread. start() calls run(), which in turn calls gameLoop().
        gameThread.start();
    }

    // main
    public static void main(String[] args) 
    {
        // Use the event dispatch thread to build the UI for thread-safety.
        SwingUtilities.invokeLater(new Runnable() 
        {
            @Override
            public void run() 
            {
                new GameMain();
            }
        });
    }
}
java swing for-loop repaint paintcomponent
1个回答
3
投票

从初始化代码开始,在初始化期间没有响应是有意义的:

public void dispArray() {
  int tempLevel[][] = new int[][] { { 1, 1, 1, 1 }, { 6, 2, 2, 2 },
        { 3, 3, 3, 3 }, { 4, 4, 4, 4 }, { 4, 4, 4, 4 }, { 4, 4, 4, 4 },
        { 4, 4, 4, 4 }, { 4, 4, 4, 4 }, { 4, 4, 4, 4 } };
  int widthTemp = tempLevel[0].length;
  int heightTemp = tempLevel.length;
  for (int i = 0; i < heightTemp; i++) {
     for (int j = 0; j < widthTemp; j++) {
           try {
              image = ImageIO.read(getFile());
           } catch (Exception e) {
              e.printStackTrace();
           }
        drawB(image);
     }
  }
}

public File getFile() {
  path = "images//1.jpg";
  File file = new File(path);
  return file;
}

public void drawB(BufferedImage imgTemp) {
  image = imgTemp;
  repaint();
}

包括读入图像文件,都是在Swing事件线程上完成的,这是你永远不应该做的事情。

解决方案:不要这样做。而是使用后台线程,例如SwingWorker提供的后台线程。有关这方面的更多信息,请阅读Concurrency in Swing

© www.soinside.com 2019 - 2024. All rights reserved.