我寫了一個自定義控件呈現一些圖形。圖形本身渲染起來相當昂貴,但一旦渲染它很少發生變化。我的問題是,如果你在圖形真快移動鼠標表面也保持調用控件的重寫Paint方法,然後會帶來較高的CPU處罰:C#OnPaint mousemove高CPU使用率
私人無效UserControl1_Paint(對象發件人,PaintEventArgs的E)
由於鼠標指針下面的圖形/圖像實際上並沒有改變,可以使用哪些技術來避免這種情況或最小化任何不必要的重繪?
我寫了一個自定義控件呈現一些圖形。圖形本身渲染起來相當昂貴,但一旦渲染它很少發生變化。我的問題是,如果你在圖形真快移動鼠標表面也保持調用控件的重寫Paint方法,然後會帶來較高的CPU處罰:C#OnPaint mousemove高CPU使用率
私人無效UserControl1_Paint(對象發件人,PaintEventArgs的E)
由於鼠標指針下面的圖形/圖像實際上並沒有改變,可以使用哪些技術來避免這種情況或最小化任何不必要的重繪?
編輯:看到你的編輯後,我可以向你保證的OnPaint不是默認調用時通過控制鼠標移動。你的代碼中的東西肯定會導致重新繪製,你只是還沒有看到它。也許發佈一些代碼可以幫助我們發現問題。
您是否使MouseMove上的控件無效?這可能是一個壞主意,如果你真的需要這樣做(即,你正在製作一個圖形編輯器或其他東西),那麼你就必須明白一個區域實際上被重新繪製了多大。所以,解決方案;請勿在MouseMove中繪製您的控件。
否則,我不希望OnPaint在鼠標移過控件時觸發。您也可以只生成一次圖像,然後將其繪製到Graphics對象上,直到需要重新生成。
謝謝。你一定是對的。我實際上覆蓋了另一個控件的行爲,所以它可能會在表單中做一些調皮的事情,導致鼠標移動失敗 –
您可以使用緩衝區圖像,在更改內容時繪製緩衝區圖像,並在Paint方法中將圖像複製到屏幕上。應該很快。您也可以使用剪輯區域來僅複製需要更新的部分。這應該會減少CPU使用率。
如果需要,您還可以使用IsDirty標誌來了解何時更新緩衝區映像(即完全重新繪製它)。
這是目前我所做的。但是我想知道是否有辦法在鼠標移動時停止調用Paint的環境。 –
光標在控件上移動時,不會調用OnPaint。 –
您可以使用此代碼來剿,恢復控制的重繪:] 好運。
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace pl.emag.audiopc.gui {
// ************************************************************************
//`enter code here`
// ************************************************************************
public class PaintingHelper {
// ********************************************************************
//
// ********************************************************************
public static void SuspendDrawing(Control parent) {
SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
}
// ********************************************************************
//
// ********************************************************************
public static void ResumeDrawing(Control parent) {
SendMessage(parent.Handle, WM_SETREDRAW, true, 0);
parent.Refresh();
}
// ********************************************************************
//
// ********************************************************************
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, Int32 wMsg,
bool wParam, Int32 lParam);
// ********************************************************************
//
// ********************************************************************
private const int WM_SETREDRAW = 11;
}
}
您不應直接致電Paint
。
相反,調用Invalidate
(Control.Invalidate)。這排隊需要重新繪製,Windows將自己照顧電話。這樣,可以通過對Paint
的一次調用來服務很多快速失效(重新繪製請求)。
同時檢查Clip Rectange in the PaintArgs event argument,讓你只重畫需要得到更新,而不是重新繪製整個圖像的區域。
在Paint方法中可能導致高CPU負載的事情之一是不正確的(非託管)資源釋放。確保你做Dispose()所有的筆,畫筆等等(可能所有的System.Drawing類實例都有一些非託管資源綁定到它們)。 基本上你應該儘快處理對象的Dispose()。不要緩存或任何東西 - GDI +資源是系統資源,應該儘快返回給系統。獲取它們(例如創建新的Brush類實例)應該很快,但我現在沒有什麼可以支持這個語句。
感謝迄今爲止的答案。我應該補充說我使用control.Invalidate當我知道有什麼改變。當鼠標移動時,Paint方法被.NET調用(不是我!)。 –
當鼠標移過控件時,OnPaint不會被調用,而是發生其他事情。 –
我剛剛測試了一個簡單的項目,以確保Paint不會被鼠標移動調用,除非我在OnMouseMove中調用Invalidate(正如其他人在此提到的那樣)。你確定代碼中沒有其他的條件使得調用在不應該被調用時失效嗎?嘗試添加一些日誌記錄代碼來記錄呼叫失效和鼠標移動,並看看他們是否打電話,因爲你打算。 – rslite