【问题标题】:How do I force a repaint in Java using Swing JPanel?如何使用 Swing JPanel 在 Java 中强制重绘?
【发布时间】:2013-10-10 15:37:34
【问题描述】:

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

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){}
    }
}

【问题讨论】:

  • 您是否尝试过使用 SwingUtilities.invokeLater 调用 repaint 调用(来自动画线程),因为 Swing/AWT 不是线程安全的?
  • 如需尽快获得更好的帮助,请提供SSCCE
  • 即使我找不到重复的,这种问题已经回答了很多次了:Here 和here 快速search
  • 发布的代码如何成为 SSCCE?代码可以编译吗?
  • 不管怎样,JComponent 重绘方法应该是线程安全的。

标签: java swing jpanel repaint


【解决方案1】:

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

【讨论】:

  • 效果很好。即使没有SwingUtilities.invokeLater...
【解决方案2】:

就像我之前说的,问题在于hBod 构造函数中的这一行render = new drawr();。在gutz 类中创建一个像private drawr panel = new drawr() 这样的单个实例,并使用它们的构造函数将它传递给其他两个类,例如hBod hb1 = new hBod(50, 30, 21, 111, 7, -11, panel) 和windowmakr w = new windowmakr(panel),并简单地使用这个引用指向panel.renderImage(...) 在hBod 类中的hBod 和panel.setSpeed(...) 来自 windowmakr 类。

这里是修改后的代码,请学习Java Coding Conventions:

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){}
    }
}

【讨论】:

  • 太酷了!!!非常感谢。 (我正在参加 Java 编码大会。但进展缓慢。就像我说的:我只是一个穴居人!再次感谢所有人。
  • 但是,我想请您稍微改变一下逻辑,不要使用Thread 来重复任务,而是尝试使用javax.swing.Timer 来实现此目的,如图所示@ 987654322@。请随时提出任何问题,这仍然不清楚。其余的你最欢迎并保持微笑:-)
  • 我要离开几天,但我回来时会尝试。 (忍不住笑了;这真的很有趣!)
  • fyi - 我试图比较之前和之后,但您对 JAVA Coding ConVenTionS 所做的所有更改都受到干扰。我最终不得不删除你所有的额外工作。 :)
猜你喜欢
  • 1970-01-01
  • 2012-06-19
  • 2011-11-16
  • 1970-01-01
  • 2011-01-10
  • 2013-11-12
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多