2010-06-21 108 views
1

此代码绘制两行,但等待一秒钟.. 我正在寻找如何做到这一点在一个单独的线程,所以它不会冻结应用程序.. 要绘制一条线,并将其显示给用户和那么第二.. 很抱歉,但我很困惑..发现太多的解决方案Java Swing +线程

public class Askisi2_3 extends JFrame { 

    private class LineJPanel extends JPanel { 

     public LineJPanel() {      
      setSize(500,500); 
     } 

     private void drawRandomLines(Graphics g) { 
      g.drawLine(5, 4, 50, 100); 
      try{ 
       Thread.sleep(1000); 
      } catch(InterruptedException ex) { 

      } 
      g.drawLine(5, 4, 50, 200);     
     } 

     @Override   
     public void paint(Graphics g) { 
      super.paint(g); 
      drawRandomLines(g);     
     } 

    } 


    public Askisi2_3() { 
     initialiseComponents(); 
    } 

    private void initialiseComponents() { 
     JPanel panel = new LineJPanel(); 

     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     add(panel); 
     setSize(500, 500); 
     setVisible(true); 
    } 
} 

编辑

谢谢您的回复! 对此的要求是使用

try{ 
    Thread.sleep(1000); 
} 

这可能吗?

这是我更新的代码

@Override 
public void paint(Graphics g) { 
    super.paint(g); 
    for (int i = 0; i < lines.length; i++) { 
     try{ 
      Thread.sleep(1000); 
     }catch(InterruptedException e) { 

     } 
     g.drawLine(lines[i].getX1(),lines[i].getY1(), lines[i].getX2(), lines[i].getY2()); 

    } 
} 

打开这个线程之前用Google搜索了一下,发现约定时器..但我不得不使用Thread.Sleep() ..所以有没有解决或没有?

因此,你建议把外面的睡眠以某种方式?

回答

2

简短的回答

您可以使用Thread.sleep但不能从paint方法。从外面使用它,只需重新打开面板。

龙答案

因为它是现在,你的代码绘制的面板,直至暂停是完成它返回。从视觉上看,油漆需要花费太多时间才能完成。

你需要什么,是有一个“型号”画。你的组件只会绘制该模型并完成。

然后,您每秒钟都会向模型中添加更多“事物”,就是这样。

例如,比方说,你的模式是线组成的数组:

class Line { 
    int x1, y1, x2, y2; 
} 

class LineJPanel extends JPanel { 
// this is the private model 
private Line[] lines = new Line[10]; 
..... 

您需要在paint方法做的是画那些线:

// exactly as you have them: 
@Override 
public void paint(Graphics g) { 
    super.paint(g); 
    drawRandomLines(g); 
} 
// Changed. Do no "sleep" here, or you'll freeze the GUI 
// just draw whatever your model is/has. 
private void drawRandomLines(Graphics g) { 
    for(Line line : lines){ 
     if(line != null){ 
      g.drawLine(line.x1, line.y1, line.x2, line.y2); 
     } 
    } 
} 

就是这样。这样你就不会冻结GUI。

要添加具有越来越多行的效果,您将创建一个单独的线程并向其中添加行。

为了简单起见,你可以添加线程在构造函数中:

public LineJPanel() { 
    setSize(500,500); 
    Thread t = new Thread(){ 
     public void run(){ 
      while(true) { 
       // add random lines and repaint 
       // sleep for a while 
       // and repeat. 
      } 
     } 
    }; 
    t.start(); 
} 

这应该增加更多线路到“模式”(阵列)一样简单,让组件重新油漆他们。

左右的时间完成,我们可以添加,创建一个线addRandomLine方法,设置一些随机值,并把它在阵列中的代码:

private void addRandomLine(){ 
    Line line = new Line(); 
    line.x1 = random.nextInt(500); 
    line.y1 = random.nextInt(500); 
    line.x2 = random.nextInt(500); 
    line.y2 = random.nextInt(500); 
    lines[count++] = line;//put it in the next position 
    // if we reach the limit, start all over again 
    // from 0 
    if(count == lines.length){ 
     count = 0; 
    } 
} 

所以,结束了你的新的线程将如下所示:

Thread t = new Thread(){ 
     public void run(){ 
      while(true){ 
       addRandomLine(); 
       repaint(); 
       // and as per the requiement: 
       try{ 
        Thread.sleep(1000); 
       }catch(InterruptedException ie){} 
      } 
     } 
    }; 

请注意,这将在其他线程中调用repaint与EDT不同。为了解决这个问题,我们将使用:SwingUtilities.invokeLater这让我们定义一个方法被调用“最终”在EDT:

所以,最终的代码(从我的一部分某些格式的改进)将是:

import javax.swing.*; 
import java.awt.*; 
import java.util.Random; 
public class Askisi2_3 extends JFrame { 

    public Askisi2_3() { 
     initialiseComponents(); 
    } 

    private void initialiseComponents() { 
     JPanel panel = new LineJPanel(); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     add(panel); 
     setSize(500, 500); 
     setVisible(true); 
    } 
    public static void main(String [] args) { 
     new Askisi2_3(); 
    } 
} 
// line abstraction 
class Line { 
    int x1, y1, x2, y2; 
} 
class LineJPanel extends JPanel { 
    // this is the private model 
    private Line[] lines = new Line[10];// fixed of size 10 by now. 
    // private internal index position 
    private int count = 0; 

    // generates "random" numbers 
    private Random random = new Random(); 

    // create the panel and start adding more lines in a separate thread. 
    public LineJPanel() { 
     setSize(500,500); 

     Thread t = new Thread(){ 
      public void run(){ 
       // forever: 
       while(true){ 
        //add another line 
        addRandomLine(); 
        // rapaint it 
        SwingUtilities.invokeLater(new Runnable(){ 
         public void run(){ 
          repaint(); 
         } 
        }); 
        // sleep for while 
        try{ 
         Thread.sleep(1000); 
        }catch(InterruptedException ie){} 
       } 
      } 
     }; 
     t.start(); 
    } 
    // just draw the model 
    private void drawRandomLines(Graphics g) { 
     for(Line line : lines){ 
      if(line != null){ 
       g.drawLine(line.x1, line.y1, line.x2, line.y2); 
      } 
     } 
    } 
    @Override 
    public void paint(Graphics g) { 
     super.paint(g); 
     drawRandomLines(g); 
    } 
    // add another line to the "model" 
    private void addRandomLine(){ 
     Line line = new Line(); 
     line.x1 = random.nextInt(500); 
     line.y1 = random.nextInt(500); 
     line.x2 = random.nextInt(500); 
     line.y2 = random.nextInt(500); 
     lines[count++] = line; 
     if(count == lines.length){ 
      count = 0; 
     } 
    } 

} 

结果是一个非常好的 “行动画” 面板:

like this http://img689.imageshack.us/img689/8414/capturadepantalla201006bk.png

1

总结与if语句对于一些挥发性布尔(例如drawSecondLine)第二的drawLine:

if (drawSecondLine) { 
    g.drawLine(5, 4, 50, 200); 
} 

然后安排java.util.Timer运行定时任务,设置一个布尔为true后1000毫秒。从该计时器任务中,请在面板上拨打repaint()

new Timer().schedule(new TimerTask() { 
     public void run() { 
      drawSecondLine = true; 
      panel.repaint(); 
     } 
    }, 1000); 

(可选)使用Swing定时器,以便在EDT上进行切换,因此您不需要易失性布尔值。

回应提问者的“答案”:

可以避开定时任务,仍然由主线程设置布尔使用的Thread.sleep( Swing事件分派线程!)。例如,您可以将run()以上的逻辑作为一个示例,在Thread.sleep(1000)后面的initializeComponents的末尾。

+1

只是去'javax.swing.Timer'。如果可能,避免多线程 - 这很难得到正确的结果。一些声称在Swing中是线程安全的方法不是。 – 2010-06-21 18:23:48

1

您需要从线条设置中分离出绘制机制。

创建LineJPanel,以便它存储它应该绘制的线的坐标。写绘画方法以便绘制存储的线条:例如

class LineJPanel extends JPanel { 
    int x1,y1,x2,y2; 
    void setLine(int newX1,int newY1,newX2,newY2) { 
    x1=newX1; ///...etc 
    repaint(); 
    } 
    void paint(Graphics g) { 
    g.drawLine(x1,y1,x2,y2); 
    } 
} 

然后创建一个单独的线程,在LineJPanel上以1秒为间隔调用setLine。这将每秒更改一行,但如果您执行其他操作,如暴露窗口或调整其大小,则不会更改该行。