user1927665
user1927665

Reputation: 21

Java: repaint() not calling paintComponent() in for loop

this is my first post here on stackoverflow and i'm hoping someone can help me out on a problem i'm having here.

The issue I am dealing with is a repaint() problem, and some will think that I just haven't searched enough on these forums to fix my problem, but I have looked extensively and nothing is working. In the code below I attempt to call drawB in a for loop for however big the array is, which this code functions properly. The for loop calls drawB 20 or so times. In drawB I wish to set an image(its going to differ depending on the number in the array) then call repaint() which then calls paintComponent() in the subclass, GameCanvas.

The problem is is that paintComponant is not running in this initialization at all. However the repaint() DOES operate in the loop that I make gameLoop(), but I need this initialization to take place before the gameLoop().

Anyone have any clue what is going on, or how to fix it?

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

Upvotes: 2

Views: 2223

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

It makes sense that is not responsive during the initialization since the initialization code:

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

including reading in of image files, is all being done on the Swing event thread, something you should never do.

Solution: don't do that. Instead use a background thread for this such as is available with a SwingWorker. For more on this, please read Concurrency in Swing.

Upvotes: 3

Related Questions