2013-12-09 83 views
0

当我运行我在JPanel中移动方块的模拟时,GUI不会更新。在整个模拟完成之前,它不刷新JPanel。为什么我的JPanel在运行模拟时没有更新?

我的代码:

import javax.swing.SwingUtilities; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.BorderFactory; 

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 

public class Main { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    private static void createAndShowGUI() { 
     System.out.println("Created GUI on EDT? "+ 
     SwingUtilities.isEventDispatchThread()); 
     JFrame f = new JFrame("Swing Paint Demo"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(new MyPanel()); 
     f.pack(); 
     f.setVisible(true); 
    } 
} 

class MyPanel extends JPanel { 
    private static final long serialVersionUID = 1L; 
    private int squareX = 50; 
    private int squareY = 50; 
    private int squareW = 20; 
    private int squareH = 20; 

    public MyPanel() { 

     setBorder(BorderFactory.createLineBorder(Color.black)); 

     doAnimation(); 

    } 

    private void doAnimation(){ 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       for(int x = 0; x < 250-squareW; x+=squareX){ 
        for(int y = 0; y < 200-squareH; y+=squareY){ 
         moveSquare(x,y); 
        } 
       } 
      } 
     }); 
    } 

    private void moveSquare(int x, int y) { 
     int OFFSET = 1; 
     if ((squareX!=x) || (squareY!=y)) { 
      repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); 
      squareX=x; 
      squareY=y; 
      repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); 
     } 
    } 


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

    protected void paintComponent(Graphics g) { 
     super.paintComponent(g);  
     g.drawString("This is my custom Panel!",10,20); 
     g.setColor(Color.RED); 
     g.fillRect(squareX,squareY,squareW,squareH); 
     g.setColor(Color.BLACK); 
     g.drawRect(squareX,squareY,squareW,squareH); 
    } 
} 
+0

如果你在每个'moveSquare(x,y);'之后执行'Thread.sleep(100)',它会工作吗? – jonhopkins

+4

不要阻塞EDT(Event Dispatch Thread) - 当发生这种情况时,GUI将“冻结”。而不是调用'Thread.sleep(n)'实现一个Swing'Timer'来重复执行任务,或者一个'SwingWorker'执行长时间运行的任务。有关更多详细信息,请参见[Swing中的并发](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 –

+0

不,它不...已经用Thread.sleep(1000)试过了。 –

回答

4

它不刷新的JPanel后才整个仿真 完成。

是的。该更新将被执行一次。因为正在运行的是由包装成一个单一事件提交给EDT所述的invokeLater可运行内部以下代码:

SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       for(int x = 0; x < 250-squareW; x+=squareX){ 
        for(int y = 0; y < 200-squareH; y+=squareY){ 
         moveSquare(x,y); 
        } 
       } 
      } 
     }); 

所有你的moveSquare(x, y)方法内由被包裹在单个事件重绘请求。即使我们在同一个事件处理函数中连续几次调用重绘,Swing也足够聪明,可以在一次绘制操作中获取这些信息并重新绘制屏幕的这些部分。换句话说,即使代码看起来在做什么,Swing也不会重新连续重绘组件。有关详细说明和示例,请查询this official tutorial page

但是,像这样运行一个长循环会使GUI应用程序无响应:因为它很可能等待E​​DT。并利用Swing Timer类的周期性任务优势来制作动画效果。

+0

我到底在哪里把计时器?我不明白。 –

+0

我从该教程页面抓取代码并将其修改为执行自动动画,而不必手动拖放。但它冻结。我的意思是这是我上面问题中的原始代码......这就是我在发布这个问题之前所做的。 –

+0

@BrianTHannan,如果你已经没有使用它,你将不会理解这种方式。请仔细阅读链接页面并品尝演示,并与其一起玩。 – Sage

-1

看吧..

private void moveSquare(int x, int y) { 
    int OFFSET = 1; 
    if ((squareX!=x) || (squareY!=y)) { 
     repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); 
     squareX=x; // It makes squareX will be 0 in first iteration 
     squareY=y; // It makes squareY will be 0 in first iteration 
     repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET); 
    } 
} 

最后你得到无限循环。所以改变它..

+0

我没有看到无限循环,究竟在哪里? –

相关问题