简体   繁体   English

Repaint()不调用JComponent类中的paintComponent()

[英]Repaint() not calling paintComponent() in JComponent class

I'm creating a java app where i use a JComponent class to draw. 我正在创建一个Java应用程序,其中使用JComponent类进行绘制。 I have a problem with the repaint() method not launching paintComponent(). 我有一个repaint()方法无法启动paintComponent()的问题。 What can be the cause of this? 这可能是什么原因?

Code: 码:

JComponent Class: JComponent类:

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. 问题是您对addNotify的覆盖未调用父级的实现。 This broke many things, proper repaint notifications is probably one of them. 这打破了很多事情,正确的重画通知可能是其中之一。 You can fix this by adding super.addNotify(); 您可以通过添加super.addNotify();来解决此问题super.addNotify(); to your implementation. 实施

But I would not touch addNotify at all. 但我根本不会触摸addNotify 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() . 您已经有了stop()方法,因此只需创建方法start()

JComponent.addNotify() documentation states: JComponent.addNotify()文档指出:

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. 调用此方法时,将使用KeyboardAction事件侦听器设置父组件链。 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() . 为了避免断开绘制链,请确保在paintComponent()实现中调用super.paintComponent() paintComponent() For more details see Performing Custom Painting and Painting in AWT and Swing . 有关更多详细信息,请参见在AWT和Swing中 执行自定义绘画绘画

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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