如何使用 Swing JPanel 在 Java 中强制重绘?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19300268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 15:50:12  来源:igfitidea点击:

How do I force a repaint in Java using Swing JPanel?

javaswingjpanelrepaint

提问by user2671186

Why won't my image repaint for a simple animation? I call repaint() from two different methods and one causes repaint but the other doesn't. The method that does force the repaint is generated from an event listener. The one that doesn't is a timed animation thread. I know the animation thread is running correctly, and as long as I continuously slide the slider, it displays perfectly. Help please!
PS yes, I've seen many similar problems here, and I've tried validate, revalidate, and using paint vs paintComponent. Four classes that comprise the code follow:

为什么我的图像不会为简单的动画重新绘制?我从两种不同的方法调用 repaint() ,一种会导致重绘,但另一种不会。强制重绘的方法是从事件侦听器生成的。一个不是定时动画线程。我知道动画线程运行正常,只要我不断滑动滑块,它就会完美显示。请帮忙!
PS 是的,我在这里看到了很多类似的问题,我尝试过验证、重新验证和使用油漆与油漆组件。组成代码的四个类如下:

import javax.swing.*;

public class gutz{

    public static int windowWidth = 640;
    public static int windowHeight = 480;

    public static void main(String[] args){

        hBod hb1 = new hBod(50, 30, 21, 111, 7, -11);   //mass, radius, xpos, ypos, xvel, yvel
        Thread t1 = new Thread(hb1);

        windowmakr w = new windowmakr();
        w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        w.setSize(windowWidth, windowHeight);
        w.setVisible(true);

        t1.start();
    }
}

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class windowmakr extends JFrame {

    private JSlider slider;
    private drawr panel;

    public windowmakr(){
        super("Orbit Explorer");
        panel = new drawr();
        panel.setBackground(Color.BLACK);

        slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
        slider.setMajorTickSpacing(10);
        slider.setPaintTicks(true);

        slider.addChangeListener(
                new ChangeListener(){
                    public void stateChanged(ChangeEvent e){
                        panel.setSpeed(slider.getValue());
                    }
                }
        );

        add(slider, BorderLayout.SOUTH);
        add(panel, BorderLayout.CENTER);

    }

}

import java.awt.*;
import javax.swing.*;

public class drawr extends JPanel{

    private int diameter = 10;
    private static int rad;
    private static int xpos;
    private static int ypos;

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(Color.ORANGE);
        g.fillOval((gutz.windowWidth-diameter)/2, ((gutz.windowHeight-diameter)/2)-40, diameter, diameter);
        g.setColor(Color.CYAN);
        g.fillOval(xpos, ypos, rad, rad);

    }

/*  public void paint(Graphics g){
        super.paint(g);
        g.setColor(Color.ORANGE);
        g.fillOval((gutz.windowWidth-diameter)/2, ((gutz.windowHeight-diameter)/2)-40, diameter, diameter);
        g.setColor(Color.CYAN);
        g.fillOval(xpos, ypos, rad, rad);   
    }
*/  
    public void setSpeed(int newD){
        diameter = (newD >= 0 ? newD : 10);
        repaint();
    }

    public void renderImage(int r, int xp, int yp){
        rad=r;
        xpos=xp;
        ypos=yp;
        repaint();
    }

    public Dimension getPreferredSize(){
        return new Dimension(200,200);
    }

    public Dimension getMinimumSize(){
        return getPreferredSize();
    }
}

public class hBod implements Runnable{

    private int mass;
    private int rad;
    private int xpos;
    private int ypos;
    private double xvel;
    private double yvel;

    public drawr render;

    public hBod(int m, int r, int xp, int yp, double xv, double yv){
        mass=m;
        rad=r;
        xpos=xp;
        ypos=yp;
        xvel=xv;
        yvel=yv;

        render = new drawr();
    }

    public void run(){
        try{
            while(true){
                xpos+=xvel;
                ypos+=yvel;
                yvel+=1;
                System.out.printf("rad - %d, xpos - %d, ypos - %d\n", rad, xpos, ypos);
                render.renderImage(rad, xpos, ypos);

                Thread.sleep(1000);
            }
        }catch(Exception e){}
    }
}

回答by nIcE cOw

Like I said before, the problem lies in this line render = new drawr();inside the hBodconstructor. Create a single instance like private drawr panel = new drawr()inside the gutzclass and pass it to other two classes using their constructor, like hBod hb1 = new hBod(50, 30, 21, 111, 7, -11, panel)and windowmakr w = new windowmakr(panel)and simply use this reference to point to panel.renderImage(...)inside hBodclass and panel.setSpeed(...)from windowmakrclass.

就像我之前说的,问题就出在这条线render = new drawr();的内部hBod构造。如创建一个实例private drawr panel = new drawr()内部gutz类和使用它们的构造传给其他两个类,如hBod hb1 = new hBod(50, 30, 21, 111, 7, -11, panel)windowmakr w = new windowmakr(panel),只需使用这个参考点panel.renderImage(...)内部hBod类和panel.setSpeed(...)windowmakr类。

Here is the modified code, Please learn Java Coding Conventions :

这是修改后的代码,请学习 Java 编码约定:

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class Gutz {

    public static int windowWidth = 640;
    public static int windowHeight = 480;

    public static void main(String[] args){
        Drawr panel = new Drawr();
        panel.setBackground(Color.BLACK);
        HBod hb1 = new HBod(50, 30, 21, 111, 7, -11, panel);   //mass, radius, xpos, ypos, xvel, yvel
        Thread t1 = new Thread(hb1);

        WindowMakr w = new WindowMakr(panel);
        w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        w.setSize(windowWidth, windowHeight);
        w.setVisible(true);

        t1.start();
    }
}

class WindowMakr extends JFrame {

    private JSlider slider;
    private Drawr panel;    

    public WindowMakr(Drawr p){
        super("Orbit Explorer");
        final Drawr panel = p;        

        slider = new JSlider(SwingConstants.HORIZONTAL, 0, 200, 10);
        slider.setMajorTickSpacing(10);
        slider.setPaintTicks(true);

        slider.addChangeListener(
                new ChangeListener(){
                    public void stateChanged(ChangeEvent e){
                        panel.setSpeed(slider.getValue());
                    }
                }
        );

        add(slider, BorderLayout.SOUTH);
        add(panel, BorderLayout.CENTER);

    }

}

class Drawr extends JPanel{

    private int diameter = 10;
    private static int rad;
    private static int xpos;
    private static int ypos;

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(Color.ORANGE);
        g.fillOval((Gutz.windowWidth-diameter)/2, ((Gutz.windowHeight-diameter)/2)-40, diameter, diameter);
        g.setColor(Color.CYAN);
        g.fillOval(xpos, ypos, rad, rad);

    }

    public void setSpeed(int newD){
        diameter = (newD >= 0 ? newD : 10);
        repaint();
    }

    public void renderImage(int r, int xp, int yp){
        rad=r;
        xpos=xp;
        ypos=yp;
        repaint();
    }

    public Dimension getPreferredSize(){
        return new Dimension(200,200);
    }

    public Dimension getMinimumSize(){
        return getPreferredSize();
    }
}

class HBod implements Runnable{

    private int mass;
    private int rad;
    private int xpos;
    private int ypos;
    private double xvel;
    private double yvel;

    public Drawr render;

    public HBod(int m, int r, int xp, int yp, double xv, double yv, Drawr panel){
        mass=m;
        rad=r;
        xpos=xp;
        ypos=yp;
        xvel=xv;
        yvel=yv;

        render = panel;
    }

    public void run(){
        try{
            while(true){
                xpos+=xvel;
                ypos+=yvel;
                yvel+=1;
                System.out.printf("rad - %d, xpos - %d, ypos - %d\n", rad, xpos, ypos);
                render.renderImage(rad, xpos, ypos);

                Thread.sleep(1000);
            }
        }catch(Exception e){}
    }
}

回答by Amitesh

You can use the getContentPane().repaint() method in your JFrame class

您可以在 JFrame 类中使用 getContentPane().repaint() 方法