2012-04-19 47 views
2

我已經瀏覽了這個主題的很多主題,但沒有一個符合我的具體情況。SwingWorker結束,PropertyChangeListener偵聽,但我如何返回到EDT?

我有一個swing應用程序,它分析QR碼,提取找到的登錄名並進行數據庫調用以獲取該用戶的數據。爲了確保可以取消QR碼的捕獲,並且在捕獲時仍然可以訪問我的應用程序,爲此我使用了SwingWorker。到目前爲止一切正常,我已經包含了一個PropertyChangeListener,因此應用程序知道我的SwingWorker何時成功讀取代碼。但是因爲我不想讓PropertyChangeListener作爲我的mainClass中的嵌套類(爲了保持它的結構),我在外面爲它創建了一個新的類。現在我想從這個PropertyChangeListener類返回到我的主類,以切換到顯示提取數據的相應面板。我有不同的代碼可以讀取,所以根據代碼我有不同的面板切換到(所以我不能做一個反覆靜態切換到同一個面板)。那麼我怎麼能委託PropertyChangeListener把控制權交還給我的EDT呢? 我試過使用wait()和notify()讓我的EDT知道SwingWorker完成了。但顯然等待()會阻止我的EDT,而SwingWorker的使用毫無意義。

我希望我能夠詳細解釋我的問題,並且你們中的一些人有一個好主意來處理這個問題。 對於任何代碼片段請問,然後我會添加必要的。但是由於我的項目有點複雜,我只會發布要求的內容。

預先感謝任何幫助:)

編輯:下面是一個代碼片段來說明什麼我SwingWorker的是做。

SwingWorker類:​​

public class CodeDetector extends SwingWorker<byte[], String> { 

String s;      // read String 
byte[] completeCode;   // byte[] which is returned by doInBackground() 
BufferedImage resizedImg; 
IplImage img; 
JLabel labelForStream; 
JLabel result; 
FrameGrabber grabber = new VideoInputFrameGrabber();  // using JavaCV. 


public CodeDetector(JLabel labelForStream, JLabel result) { 
    this.labelForStream = labelForStream; 
    this.resultLabel = result; 
} 

@Override 
protected byte[] doInBackground() throws Exception { 
    try { 
     grabber.start();   // 
     while (true) { 
      // End if current thread was canceled. 
      if (Thread.currentThread().isInterrupted()) { 
       return null; 
      } 

      // Grab each image, save it, scan for code and display it. 
      img = grabber.grab(); 
      resizedImg = // resizing image to fit labelForStream. 
          // save resizedImg to file 
      // read barcode from saved file 
        if (isBadgeCode(tmp) || isDeviceCode(tmp)) { 
         s = tmp; 
        } else { 
         continue; 
        } 
        break; 
       } catch (NotFoundException e) { 
        // Code could not be encoded yet. 
       } 
       ... 

        // end worker after timeout 

     // show image on window 
       if (img != null) { 
        labelForStream.setIcon(new ImageIcon(resizedImg)); 
       } 
      } 
     } 
    } catch (Exception e) { 
     System.err.println("Error: " + e.getMessage() + " - " + e.getStackTrace() + " - " + e.getClass()); 
    } 
    return s != null ? s.getBytes() : null; 
} 

@Override 
protected void done() { 
    try { 
     completeCode = get(); 
     if (completeCode != null) { 
      String code = new String(completeCode); 
      if (isOtherCode(code)) { 
       resultLabel.setText(code); 
      } else if (isUsernameCode(code)) { 
       // Cut userName from read code (if previously verified) and set label text. 
       resultLabel.setText(verify(code, true) ? code.split(":")[0] : null); 
      } 
     } else { 
      resultLabel.setText(null); 
     } 
     resultLabel.setVisible(true); 
     resultLabel.updateUI(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } catch (ExecutionException e) { 
     e.printStackTrace(); 
    } catch (CancellationException e) { 
     return; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

由於這個SwingWorker的沒有任何面板引用,即使做了() - 方法是在美國東部時間做的,我需要以某種方式通知我mainClass一個代碼已被成功讀取,並且現在可以根據特定代碼更改panl。

希望這可以清理一些東西。

+0

爲什麼PropertyChangeListener ... SwingWorker可以指示進度。這在Swing教程中有解釋。或者你可以看看[這個示例代碼](http://stackoverflow.com/questions/8916721/java-swing-update-label/8917565#8917565) – Robin 2012-04-19 14:50:03

+0

你能提供一個你如何使用SwingWorker的例子嗎?從你的描述中不清楚爲什麼你使用PropertyChangedListener而不是重寫'done()'? – 2012-04-19 14:50:52

+0

不會從[SwingUtilities.invokeLater(...)]中調用您的代碼(http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater(java .lang.Runnable))將帶您到EDT,而您需要遍歷您的'JPanel' – 2012-04-19 14:52:41

回答

6

我想你誤會了,以什麼理由SwingWorker是存在的,請閱讀SwingWorker tutorial,其中實現從方法是輸出很機制保障:

  • ()完成

  • 過程()

  • 發佈()

  • setProgress()

應該EDT

+2

[This](http://albertattard.blogspot.com/2008/09/practical-example-of-swing-worker.html)是一個相當完整的例子如何使用SwingWorker,包括OP可能應該使用的'process'和'publish'。 – Jim 2012-04-19 19:44:22

+0

@Jim謝謝你的另一個不錯的鏈接:-) – mKorbel 2012-04-19 19:55:38

+0

@trashgod憎恨下來,對不起,我限制了我的用法:-), – mKorbel 2012-04-19 19:59:08

2

做簡單的揮杆工人的回答是覆蓋done()方法。這是在EDT上執行的 - SwingWorker負責爲您服務。

你可以自己動手,使用SwingUtilities.invokeLater。

對於您提出問題的方式,我懷疑您沒有完全掌握線程問題以及如何在線程之間切換。因此,對tutorial(如果您還沒有的話)的評論可能會很好。

3

這是錯誤的:

protected byte[] doInBackground() throws Exception { 

    // .... 
    if (img != null) { 
    labelForStream.setIcon(new ImageIcon(resizedImg)); 
    } 
    // .... 
} 

由於這表明你做的doInBackground方法,這東西不應該做中的關鍵搖擺電話。請考慮發佈Image或ImageIcon,並從process process override中設置JLabel的Icon。

正如我在我的評論中指出的那樣,如果減少代碼耦合,有時最好使用PropertyChangeListener和SwingWorker。這是SwingWorker擁有自己的PropertyChangeSupport和自己的狀態枚舉的原因之一。

+0

@Yeehaw [PropertyChangeListener是用於監聽SwingWorkers狀態](http://stackoverflow.com/questions/7053865/cant-get-arrayindexoutofboundsexception-from-future-and-swingworker-if-threa)+1 – mKorbel 2012-04-19 16:36:00

+0

太多瞭解,似乎SwingWorker正好在我的TO DO LIST的頂部+1上,用於代碼耦合:-) – 2012-04-19 16:42:44

+0

@nIcE cOw 1)not plain Runnable#與SwingWorker相比,線程是最舒適和可管理的,2)Runnable#需要線程有時候(大多數情況下)invokeLater,3)SwingWorker在那裏,並且實現了Swing的重要方法,4)Java6_021到Java7不是bug, – mKorbel 2012-04-19 20:53:34

相關問題