2010-06-21 218 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。這將每秒更改一行,但如果您執行其他操作,如暴露窗口或調整其大小,則不會更改該行。