【问题标题】:Swing repaint() doesn't work in loop or threadSwing repaint() 在循环或线程中不起作用
【发布时间】:2014-06-17 02:28:14
【问题描述】:

我有以下代码:

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),也无济于事。

我的目标是设置一个在屏幕上徘徊的绿点。 你有什么解决办法吗?

【问题讨论】:

  • 你需要了解一些关于 Swing 的知识,比如提到的 SwingTimer 或 how to work with threads in Swing(你的主要需要打电话给 invokeLater)但是有一个更基本的非 Swing 问题:不要在构造函数中放置无限循环,它永远不会结束对象的构造,并且您调用它的代码将在该点冻结。
  • 我明白了,现在一切都清楚了,谢谢!

标签: java multithreading swing animation graphics


【解决方案1】:

您的 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 计时器 (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的cmets:

  • 确实,您没有在 Swing 事件线程上运行您的 GUI,这是您应该做的事情,但是您的 while true 循环仍然冻结您的绘画,因为您的无限循环阻止了组件完全创建自己。
  • 如上所述,实际上您应该在 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);
}

【讨论】:

  • 虽然这通常是正确和好的建议,但 EDT 被阻止并不是在这种情况下它失败的原因,因为他没有从 EDT 调用 ex10()(这是一个错误本身)。它不起作用,因为构造函数进入一个循环,所以这条线 frame.add(new ex10()); 永远不会完全执行。 EDT 很好,正在执行重绘。他还必须取消注释super.paintComponent(g);
  • @sidney:不客气。但请查看重要的修改来回答。
  • @DSquare:感谢您的 cmets 是正确的。我已经编辑了我的答案以纳入您的要点。
  • 太棒了,再次感谢两位的详细解释
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多