2010-01-09 57 views
2

我目前正在使用Windows.Forms應用程序。這基本上是一個簡單的運動檢測問題。從單獨的線程在窗體上繪製圖像

我有一個表格上的按鈕時,在按下時啓動一個背景工人其執行以下操作:

  1. 從磁盤
  2. 抓取的圖像創建一個新的位圖,可以用作緩衝器。
  3. 執行運動檢測
  4. 從運動檢測的結果,更新該緩衝液(使用緩衝器的繪圖表面)
  5. 火災進展更改事件與由所述緩衝器的克隆的自變量,基本上(sender as BackgroundWorker).ReportProgress((Bitmap)buffer.Clone())

在進度改變的事件中,我畫了緩衝區。

if (!PnlImage.IsDisposed) 
      PnlImage.CreateGraphics().DrawImageUnscaled(buffer, 0, 0); 

我不禁想知道這是否是在屏幕上繪製更新圖像的最佳方式。任何人都可以提出我可以做的改進嗎? 謝謝。

編輯: 我已經更新程序使用.NET Framework 4,我們不再使用BackgroundWorker。相反,我們現在使用System.Threading.Tasks命名空間,並使用Invoke從任務內更新背景圖像。

感謝所有回覆。

+0

克隆緩衝區的原因是什麼? – ironic 2010-01-09 23:27:26

+0

您不能跨線程訪問它,因爲每個步驟都會創建並銷燬新的緩衝區。我試着製作一個通用緩衝區,並使用鎖來訪問它,但它並沒有證明太成功。 – 2010-01-10 00:09:37

回答

2

我相信您可能遇到的任何問題的根源是任何GUI更新都必須在UI線程上完成。您無法安全地從另一個線程更新UI。所以,基本上,你需要做類似如下(我只是改變了背景色作爲一個例子,但你可以做任何你喜歡):

private void SomethingCalledFromBackgroundThread() 
    { 
     panel1.Invoke(new DoUpdatePanel(UpdatePanel), Color.Blue); 
    } 

    private delegate void DoUpdatePanel(Color aColor); 

    private void UpdatePanel(Color aColor) 
    { 
     panel1.BackColor = aColor; 
    } 

========= ===更新=======>

@Ash你錯誤地描述了我的答案。我沒有說從ProgressChanged中調用Invoke。 @Jean記住ReportProgress/ProgressChanged是異步運行的 - 這就是爲什麼你會發現自己對圖像進行克隆。如果您在後臺線程中使用Invoke,而不是ReportProgress,則這不是必需的。

1

我不確定這是否完全正確,但我確定您無法在單獨的線程上交叉線程GUI /控制操作,因爲它是在專用GUI線程上默認處理的。

我之前試圖做類似的事情,最後我決定採取一種完全不同的方法,因爲將屬性設置爲false是使其工作的最糟糕方式。

+0

我知道,這就是爲什麼我通過克隆它將位圖傳遞給Progress Changed Event的原因,因爲跨線程gui更新僅導致由於跨線程訪問而導致的異常。 我只想知道是否有人成功做了類似的事情 – 2010-01-10 00:59:14

+0

我的歉意,我個人沒有太多的GUI組件經驗。 如果你現在使用的方法有效,那麼最好堅持使用它,試圖找到替代方案可能會使其性能變差,看起來你做得很好。 – 2010-01-10 01:14:58

1

ProgressChanged和RunWorkerCompleted Events允許您直接更新UI。它只是DoWork事件處理程序,您不能訪問它。 See MSDN

你一定要小心,不要操縱 在 DoWork的事件處理程序的任何用戶界面對象。相反, 通過ProgressChanged和 RunWorkerCompleted事件與用戶界面 進行通信。

這是使用BackgroundWorker創建自己的線程的主要優點之一。所以TheObjectGuy不正確,你不需要在ProgressChanged中使用BeginInvoke/Invoke。

只要你的圖像不是太大,克隆它不應該導致任何嚴重的性能問題。如果您有疑慮,請使用更大的圖像運行一些性能測試。

否則,爲了避免棘手的同步問題,例如使用鎖定,我認爲對圖像進行克隆是使事情簡單化的好方法。

+0

圖像大約是640x480,它幾乎保證了這種方式。 雖然謝謝。 – 2010-01-10 09:39:46

1

使用ProgressChanged事件很好。不好的是直接畫到屏幕上。當您最小化和恢復表單時,圖像將消失。解決方法很簡單:

PnlImage.BackgroundImage = buffer; 
+0

然而,謝謝,但是,我們正在屏幕上約每秒23次:S閃爍像地獄.. – 2010-01-11 21:05:49

+0

然後,你不必擔心圖像可能會消失。 – 2010-01-11 21:12:24

+0

哦,但不是用PictureBox代替面板。謝謝你的提示! – 2010-01-11 21:18:27