2015-04-23 59 views
1

在搜索了很多有關類似問題的線程的答案後,我仍然沒有找到適合我需求的解決方案。做一個循環迭代等待repaint()方法完成

基本上,我有一個while循環,我想等待repaint()方法在該循環的另一個迭代開始之前完成。

更詳細地,我有一些區段被在擴展JComponent的一個MapPanel類的方法的paintComponent繪製。 然後,當用戶點擊一個按鈕時,算法開始搜索以「上」段開始的交點(使用端點作爲事件點)。 這個算法基本上是我談到的while循環,它在這個while循環中每次迭代發送一個事件點時調用另一個算法(這些事件點按從上到下的順序發送)。

我想要做的是通過在當前事件點畫一條線來顯示算法的當前「位置」。 由於該算法找到新的交叉點,我也想展示它們。 我確實在paintComponent()方法中繪製了需要的東西。

問題是,當我在循環內調用MapPanel的repaint()方法時,它會在更新UI之前等待整個循環結束(我已經發現了很多關於它爲什麼會這樣做但不是關於如何解決這個在我的具體情況)。

好吧,我與解釋做,這裏的實際算法:

private void findIntersection(ArrayList<Segment> segments){ 
    QTree Q=new QTree(); 
    for (Segment s : segments){ 
     Q.initialise(s); 
    } 
    TreeT T=new TreeT(); 
    while (Q.getRoot()!=null){ 
     Point p = Q.maxEventPoint(Q.getRoot()); 
     Q.delete(p.getX(), p.getY()); 
     mapPanel.setSweeplinePosition(p.getY()); 
     handleEventPoint(p, T, Q); 
     mapPanel.repaint() 
     //should wait here for repaint() to complete 
    } 
     System.out.println("all intersections found, found " + mapPanel.getIntersections().size()); 
} 
+0

使用[定時器](https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html )或[工作線程](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html)。 – Radiodef

+0

你在哪個線程運行這個方法? – joz

+0

請參閱編輯以回答。 –

回答

4

的問題是,你的長期運行的代碼很可能被呼籲Swing事件線程,防止了事件的動作線程完成其操作,包括繪製GUI。

解決方案很可能類似於您在搜索已找到的東西,但我們不知道爲什麼你不能與你的程序中使用它,這是做while循環的SwingWorker的後臺線程,出版臨時結果使用SwingWorker的發佈/處理方法對,然後使用臨時數據執行您的繪圖。

更多關於此,請閱讀Concurrency in Swing


例如

private void findIntersection(final ArrayList<Segment> segments) { 
    final SwingWorker<Void, Double> myWorker = new SwingWorker<Void, Double>() { 

    @Override 
    protected Void doInBackground() throws Exception { 
     QTree Q = new QTree(); 
     for (Segment s : segments) { 
      Q.initialise(s); 
     } 
     TreeT T = new TreeT(); 
     while (Q.getRoot() != null) { 
      Point p = Q.maxEventPoint(Q.getRoot()); 
      Q.delete(p.getX(), p.getY()); 
      publish(p.getY()); // push data to process method 

      // take care that this method below does not 
      // make Swing calls 
      handleEventPoint(p, T, Q); 
     } 
     return null; 
    } 

    @Override 
    protected void process(List<Double> chunks) { 
     for (Double yValue : chunks) { 
      // this is called on the EDT (Swing event dispatch thread) 
      mapPanel.setSweeplinePosition(yValue); 
      mapPanel.repaint(); 
     } 
    } 
    }; 
    myWorker.addPropertyChangeListener(new PropertyChangeListener() { 

    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
     // get notified when Worker is done 
     if (evt.getNewValue() == SwingWorker.StateValue.DONE) { 
      // TODO: any clean up code for when worker is done goes here 
      try { 
       myWorker.get(); // must call to trap exceptions that occur inside worker 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } catch (ExecutionException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    }); 
    myWorker.execute(); // execute worker 
} 
+0

非常感謝,那實際上並不完全是我發現的(類似但無法讓它工作)。 – qdrien

0

你嘗試用方法的Thread.sleep(毫秒)??? 例如,我已經習慣了做這樣的事情在我的代碼:

 btnNewButton.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       // TODO Auto-generated method stub 
       new Thread(new Runnable() { 

        @Override 
        public void run() { 
         // TODO Auto-generated method stub 
         pca.setIcon(new ImageIcon("icon.png")); 
         for(int i=0; i<4; i++) { 
         try{Thread.sleep(700);} catch(InterruptedException er){} 
         x+=20; 
         p.repaint(); 
        }} 
       }).start(); 
      } 
     }); 
+0

我首先使用了一個簡單的Thread.sleep()(我現在在doInBackground()方法中使用它),但問題在於Thread.sleep()阻止該線程執行任何操作,因爲重繪( )線程繁忙或休眠時執行不會執行,直到算法結束時纔會刷新GUI。 這就是爲什麼我需要像SwingWorker一樣使算法等待repaint()執行。 從我現在(想我)瞭解的情況來看,您的示例工作原因是您在新線程中調用了repaint(),而不是因爲您正在使用Thread.sleep():p – qdrien

+0

是的,您是對的。我注意到在算法結束前沒有GUI刷新,所以我把repaint()放在一個Thread中;)正如你所看到的,我是一個初學者,我嘗試用我所擁有的知識來解決我的問題。如果有更正確的解決方案,我已經準備好了...... – user2896152