Swing repaint()在循环或线程中不起作用

时间:2014-04-30 16:42:50

标签: java multithreading swing animation graphics

我有以下代码:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.text.View;

public class ex10 extends JPanel  {
    private int x=1;
    int y=1;

    //Constructor 
    public ex10() {


        while(true) {

          System.out.println("x ->"+ x);
          System.out.println("y ->" + y);


          x = randomposition(x);
          y = randomposition(y);

          this.repaint();
        }
    }

  public int randomposition(int value) {
        Random random = new Random();

    if (random.nextBoolean() == true) {
      if (value+1 != 500) {
        value++;
      }
    }
    else {
      if (value-1 != 0) {
        value--;  
      }
    }
    return value;
  }
    @Override
    public void paintComponent(Graphics g) {
        //super.paintComponent(g);
        g.setColor(Color.green);
    g.fillRect(x, y, 20, 20);
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.add(new ex10());
    }

}

不幸的是,当调用this.repaint()时,该点未显示,但我仍然得到了System.out.println。我尝试分开设置一个新线程,但无济于事。 我尝试了其他一些解决方案(invokelaterpaintimmediately),也无济于事。

我的目标是设置一个在屏幕上徘徊的绿点。 你有任何解决方案吗?

1 个答案:

答案 0 :(得分:8)

您的while (true)阻止了让应用程序进入休眠状态的Swing事件线程。

对于简单的动画和游戏循环,请使用Swing Timer。如果你有长时间运行的代码需要在后台,那么使用后台线程,如SwingWorker,但要注意确保所有调用Swing组件状态的调用应该在Swing事件线程上完成。

例如,您可以更改此内容:

    while(true) {

      System.out.println("x ->"+ x);
      System.out.println("y ->" + y);


      x = randomposition(x);
      y = randomposition(y);

      this.repaint();
    }

使用Swing Timer(javax.swing.Timer):

int timerDelay = 20;
new Timer(timerDelay, new ActionListener(){
  public void actionPerformed(ActionEvent e) {
    x = randomposition(x);
    y = randomposition(y);
    repaint();
  }
}).start();

关于DSquare的评论:

  • 确实你没有在Swing事件线程上运行你的GUI,你应该做的事情,但是你的while循环仍然会冻结你的绘画因为你的无限循环阻止了组件完全自我创建。
  • 如上所述,您应该在Swing事件线程上启动所有Swing GUI,您可以通过将Swing创建代码放入Runnable并通过SwingUtilities方法invokeLater在事件线程上排队Runnable来完成。
  • 您需要在paintComponent覆盖中调用super的paintComponent方法,以便JPanel可以执行其内务处理图形工作,包括清除“脏”像素。

例如,更改此内容:

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    frame.add(new ex10());
}

到此:

public static void main(String[] args) {
  SwingUtilities.invokeLater(new Runnable() {
     public void run() {
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.add(new Ex10());
     }
  });
}

并改变这一点:

@Override
public void paintComponent(Graphics g) {
  //super.paintComponent(g);
  g.setColor(Color.green);
  g.fillRect(x, y, 20, 20);
}

到此:

@Override
public void paintComponent(Graphics g) {
  super.paintComponent(g);
  g.setColor(Color.green);
  g.fillRect(x, y, 20, 20);
}