我們在使用GDI+實現類似畫圖板這樣的系統時,經常需要支持平移、滾動條、縮放等功能、解決繪制時的閃爍,對於缺乏GDI+開發經驗的朋友,經常會在這些問題上糾纏一段或長或短的時間。在這裡,我將自己的經驗小結一下,給後來的朋友作個參考。
1.如何解決繪制閃爍?
(1)所有的繪制動作都應該Paint事件中完成。
比如,即使我們要拖動一個View object,通常在MouseMove事件中處理拖動行為,但是不要在MouseMove事件中調用Graphics.Draw方法,而是應該采用 Command模式,將要繪制的動作封裝為一個對象,傳遞到下一次的Paint事件中再繪制。
(2)設置雙緩沖。
通常我們會選擇在某個控件的表面進行繪制,那麼在初始化時,可以通過執行下面的代碼來啟用雙緩沖:
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
注意,SetStyle是一個Control基類的一個Protected方法,也就是說,只能在其派生類中才能調用該方法。
通常,我是定義一個從Control繼承的自定義控件,然後在構造方法中進行雙緩沖設置,如:
public partial class ViewPanel : UserControl
{
public ViewPanel()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
}
}
(3)重新繪制發生變化的區域,而不是整個區域全部重繪。
Control的Invalidate方法有一個重載接收Region類型的參數,表示下次paint時要重繪的區域。比如,當我們拖動一個對象時,只需要重繪比這個對象的Bounds大一點的區域即可。
2.滾動條與縮放
當需要支持滾動條和縮放時,就需要采用一系列的坐標變換來正確的記錄坐標和繪制圖像,這些過程是比較繁瑣的。幸運的是,GDI+能為我們減輕一部分這方面的負擔。當繪制view object時,只要我們指定Graphics對象的幾個參數,Graphics對象就會自動采用正確的比例和偏移來繪制所有的view object了。比如:
//Graphics g ;
g.PageUnit = GraphicsUnit.Pixel; //GraphicsUnit.Pixel才支持縮放與偏移繪制。
g.TranslateTransform(this.hScrollValue, this.vScrollValue); //設置滾動條的當前位置
g.PageScale = this.Scale; //設置縮放比例
g.Draw(......);