简体   繁体   中英

Repaint() not calling paintComponent() in JComponent class

I'm creating a java app where i use a JComponent class to draw. I have a problem with the repaint() method not launching paintComponent(). What can be the cause of this?

Code:

JComponent Class:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JComponent;
import javax.swing.Timer;

public class Display extends JComponent implements ActionListener{

    private final static int Width = 400;
    private final static int Height = 600;
    private long period;
    private Timer timer;

    private Background background;

    private boolean isRunning = false;

    public Display(long period) {
        this.period = period;
        setSize(Width, Height);
        prepeareUi();
        setOpaque(false);
    }

    public void addNotify() {
        if(!isRunning) {
            timer = new Timer((int)period, this);
            timer.start();
            isRunning = true;
        }
    }

    public void stop() {
        if(isRunning)
            isRunning = false;
    }

    private void prepeareUi() {
        background = new Background(Width, Height);
    }

    public void paintComponent(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, Width, Height);
        background.draw(g);
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        if(isRunning) {
            background.update();
            repaint();
            return;
        }

        System.exit(0);

    }

}

Frame class:

import javax.swing.JFrame;

public class Frame extends JFrame {

    private static final int DEFAULTFPS = 20;

    public Frame(long period) {
        prepearUI(period);
    }

    private void prepearUI(long period) {
        Display d = new Display(period);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(d);
        pack();
        setResizable(false);
        setVisible(true);
    }

    public static void main(String[]args) {
        String fpsS = null;
        if(args.length==1)
            fpsS = args[0];

        int fps = (fpsS != null) ? Integer.parseInt(fpsS) :  DEFAULTFPS;
        long period = (long) (1000.0/fps); //In Ms!

        Frame f = new Frame(period);
    }

}

Background class

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;


public class Background {

    private int ParentWidth;
    private int ParentHeight;

    private int width;
    private int height;

    private BufferedImage image;

    private float x = 0;
    private float y = 0;

    private final static float ANIMATIONSPEED = 1F;
    private final static int ANIMATION_RIGHT = 0;
    private final static int ANIMATION_LEFT = 1;

    private int animationway = 1;

    public Background(int W, int H) {
        ParentWidth = W;
        ParentHeight = H;
        prepeareImage();
    }

    private void prepeareImage() {
        width = 0; height = 0;
        try {
            image = ImageIO.read(getClass().getResource("UI\\background.png"));
            width = image.getWidth(null);
            height = image.getHeight(null);
        } catch (IOException e) {
            System.err.println("Background.png not found!");
        }
    }

    public void update() {
        if(animationway == ANIMATION_RIGHT) {
            x += ANIMATIONSPEED;
            if(x>=0F) {
                animationway = ANIMATION_LEFT;
            }
        }

        if(animationway == ANIMATION_LEFT) {
            x -= ANIMATIONSPEED;
            if(x<=width/-1+ParentWidth) {
                animationway = ANIMATION_RIGHT;
            }
        }
    }

    public void draw(Graphics g) {
        g.drawImage(image, (int) x, (int) y, null);
    }

}

The problem is that your override of addNotify did not call the parent's implementation. This broke many things, proper repaint notifications is probably one of them. You can fix this by adding super.addNotify(); to your implementation.

But I would not touch addNotify at all. Don't override it. Initialize the timer in a constructor or add a method that a parent can call to start the timer. You already have method stop() so just create method start() .

JComponent.addNotify() documentation states:

Notifies this component that it now has a parent component. When this method is invoked, the chain of parent components is set up with KeyboardAction event listeners. This method is called by the toolkit internally and should not be called directly by programs.

EDIT:

To avoid breaking the paint chain make sure you call super.paintComponent() in your implementation of paintComponent() . For more details see Performing Custom Painting and Painting in AWT and Swing .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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