Turtled
Turtled

Reputation: 11

repaint() Method Not Repainting JPanel

OK, so first off I know there are a lot of other threads about this issue, but they only say to try using invalidate() and validate() which had no effect for me.

My problem is -- as the title makes obvious -- JPanel's repaint() method doesn't repaint. I added some debug messages in the paintComponent() method, here's the console output:

Debug
-10 421 010 441
repainted
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse
Moved mouse

Notice that you only see debug, (co-ordinates), and repainted once, at the beginning of the program, yet I call repaint(); each time the mouse is moved.

I added my five classes into one, as I believe it is preferred for debugging purposes:

package com.trtld.spacewar;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GroupClass {
     private static Content content = new Content();

    public static void main(String[] args) {
        JFrame window = new JFrame("Spacewar!");
        content.setVisible(true);
        window.setContentPane(content);
        MouseInput listener = new MouseInput();
        content.addMouseMotionListener(listener);
        content.addMouseListener(listener);
        window.setSize(600, 480);
        window.setLocation(100, 100);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
        //window.setResizable(false);
        System.out.println("Debug");
    }


}

 class Target {

    private int x1, y1;
    private int x2, y2;

    public Target(int x1, int y1, int x2, int y2){
        this.x1 = x1; 
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;

    }

    public int getX1(){
        return x1;
    }
    public int getX2(){
        return x2;
    }
    public int getY1(){
        return y1;
    }
    public int getY2(){
        return y2;
    }
}
class Content extends JPanel{

        private static Content instance;
        private Target[] targets = new Target[9];   
        private Bullet[] bullets = new Bullet[999];//assuming no more than 1000 bullets are on the screen at
                                                  //once (they'd have to have a really fancy-nice auto-clicker ha ha)
        int spaceShipX = (getWidth()/2); 





        public Content (){
            int yLevel = (((int)Math.random())*(getHeight() / 4));
            int xPos = ((int)Math.random())*getWidth();
            for(int i = 0;!(i == 9); i++){                                         //Create the randomly located targets
                targets[i] = new Target(xPos, yLevel, xPos-15, yLevel-10);
            }
        }

        public void paintComponent(Graphics g){
             super.paintComponent(g);  
             g.setColor(Color.RED);
             System.out.println(spaceShipX-10 + " " + (getHeight()-20) + " " + spaceShipX+10 + " " + getHeight());
             System.out.println("repainted");
             g.fillRect(spaceShipX+50, getHeight()-20 ,spaceShipX+100 , getHeight());

             /**  //commented out for simplicity + needs to be fixed:
                for(Target t : this.targets){        //paint targets
                    g.drawRect(t.getX1(), t.getY1(), t.getX2(), t.getY2());
                }
                for(Bullet b : this.bullets){         //paint bullets and remove invalid ones plus check for hits
                    if(b != null){


                    g.drawRect(b.getX1(), b.getY1(), b.getX2(), b.getY2());

                    if(!(b.checkTargetPresence() == null)){
                        for(Target target : targets){
                            if(b.checkTargetPresence() == target){
                                target = null;
                            }
                        }
                    }

                    if(b.isValid() == false){
                        b = null;
                    }
                }
                }*/
        }


        public static Content getInstance(){
            if(instance == null) {
                instance = new Content();     //TODO: Singletons are out-dated and not preferred; fix this
                }
                return instance;
        }


    //Getters and setters:

        public Bullet[] getBullets(){
            return bullets;
        }

        public Target[] getTargets(){
            return targets;
        }

        public void setTarget(Target t, int loc){
            this.targets[loc] = t;
        }

        public void setBullet(Bullet b){
            int location = -1;
            if(bullets[0] == null){
            this.bullets[0] = b;
            return;
            }
            for(Bullet bullet: bullets){
                location++;
            if(bullets[location] == null){ //TODO: Messy, clean this up
                bullets[location] = b;
                return;
            }   
            }

        }
        public int getSpaceShipX(){
        return spaceShipX;
        }
        public void setSpaceShipX(int x){
            spaceShipX = x-10;
            repaint();

        }

    }
class Bullet implements ActionListener{

    int x1, x2;
    int y1 = 10, y2 = 5;

    Timer timer = new Timer(250, this);

    public Bullet(int x1, int x2){
        this.x1 = x1;
        this.x2 = x2;
        timer.start();
    }

    public void actionPerformed(ActionEvent evt) {
        y1 = y1 + 2;
        y2 += 2;
        Content.getInstance().repaint();
    }

    public Target checkTargetPresence(){
        for(Target t : Content.getInstance().getTargets()){
            if(x1 <= t.getX1() && x1 >= t.getX2()){
                if(y1 <= t.getY1() && y1 >= t.getY2()){
                         //HIT!
                    return t;
                }
            }
        }
        return null; //TODO

    }

    public boolean isValid(){//Checks if the bullet is still on the screen

        if(y1 >= Content.getInstance().getHeight() || y2 >= Content.getInstance().getHeight()){
            return false;
        }else{
            return true;
        }

    }
    public int getX1(){
        return x1;
    }
    public int getX2(){
        return x2;
    }
    public int getY1(){
        return y1;
    }
    public int getY2(){
        return y2;
    }
}
class MouseInput implements MouseListener, MouseMotionListener {

    public void mouseDragged(MouseEvent arg0) {     
    }

    public void mouseMoved(MouseEvent evt) {
        Content.getInstance().setSpaceShipX(evt.getX());
        Content.getInstance().repaint(); // I try to repaint here and in the Content class, but nothing happens.
        System.out.println("Moved mouse");
    }

    public void mouseClicked(MouseEvent arg0) {

    }

    public void mouseEntered(MouseEvent arg0) {     
    }

    public void mouseExited(MouseEvent arg0) {      
    }

    public void mousePressed(MouseEvent evt) {  
    Content.getInstance().setBullet(new Bullet(evt.getX()-2, evt.getX()+2));
    System.out.println("clicked");
    }

    public void mouseReleased(MouseEvent arg0) {    
    }

}

I would appreciate any help greatly, and if I need to format something differently let me know. Please note that this is my first GUI program.

Upvotes: 0

Views: 984

Answers (1)

camickr
camickr

Reputation: 324088

I think the problem is that you create a Content class and then add it to the frame.

However, in you MouseListener code you invoke the getInstance() method of your Content class and the "instance" variable is null so a new Content instance is created (but never added to the frame so it will never get painted).

So this basic logic is wrong you don't want to be creating a new instance.

Instead in the constructor of your Content class you would just do:

instance = this;

Then the getInstance() method will just return the variable because it will always have a value.

Also, the MouseListeners should be inner classes in of your Content class. That is you should create and add the listener to your class. When you do this then you don't even need the static getInstance() method because you can just access the instance variable directly.

but they only say to try using invalidate() and validate() which had no effect for me.

You should not use those methods. Those are used in AWT. In Swing you might use:

revalidate();
repaint();

when you add components to the GUI AFTER the GUI is visible or when you change a property in your custom class. The revalidate() will invoke the layout manager. The repaint() will paint the component. In your class you are not changing the size of anything so you only need repaint() in your setter methods.

Edit:

Mind sharing the code you added?

I added one line of code:

    public Content (){
        int yLevel = (((int)Math.random())*(getHeight() / 4));
        int xPos = ((int)Math.random())*getWidth();
        for(int i = 0;!(i == 9); i++)   { 
             //Create the randomly located targets
            targets[i] = new Target(xPos, yLevel, xPos-15, yLevel-10);
        }

        instance = this; // added
    }

Make one change at a time. Once you verified my assumption is valid by adding the single line of code. Then you can tidy up the rest of the class. If you make multiple changes at once you don't know which one is causing the problem.

Upvotes: 2

Related Questions