控件開發
<!--[if !supportLists]-->一、 <!--[endif]-->直接從Windows消息隊列中接收信息操作
<!--[if !supportLists]-->1、 <!--[endif]-->具體函數:
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern bool GetMessage(ref MSG msg, int hWnd, uint wFilterMin, uint wFilterMax);
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern bool DispatchMessage(ref MSG msg);
<!--[if !supportLists]-->2、 <!--[endif]-->使用場合:
畫板中畫線操作。
拖動控件操作。
以及所有與鼠標移動相關的操作等。
<!--[if !supportLists]-->3、 <!--[endif]-->簡單說明:
對於畫線以及控件拖動等操作來說,一般操作起源於鼠標下擊(MouseDown)操作,然後再在控件的MouseMove事件中進行對應的畫線或者控件拖動操作,直到鼠標鬆開(MouseUp)爲止。
常規的做法爲:在MouseDown事件中設置一個全局變量表來啓動在MouseMove中執行移動操作,在MouseMove事件中檢驗這個變量看是否可以進行移動操作,如果可以則進行移動操作,在MouseUp事件中設置這個全局變量來禁止在MouseMove中進行移動操作。這樣做的缺點是麻煩,而且容易出錯,效率低。
採用直接在Windows消息隊列中獲取消息的操作則可以避免上面所說的缺陷,具體步驟爲:在MouseDown事件中循環使用GetMessage來接收消息,如果消息爲MouseMove則執行對應的移動操作,如果爲MouseUp或者KeyDown等事件則結束移動操作循環,對於其它與移動沒有關係的事件則使用DispatchMessage對消息進行分發。採用這個方法的優點爲:代碼可讀性強、集中(不會所有的事情都放在MouseMove事件中進行處理),效益好,不會涉及到多個事件,且不需要全局變量等額外代碼。
<!--[if !supportLists]-->二、 <!--[endif]-->圖元移動處理
<!--[if !supportLists]-->1、 <!--[endif]-->具體函數:
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static public extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static public extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static public extern IntPtr GetDesktopWindow();
[DllImport("gdi32.dll")]
static public extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
static public extern IntPtr DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
static public extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int Width, int Heigth);
[DllImport("gdi32.dll")]
static public extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
static public extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport("gdi32.dll")]
static public extern bool BitBlt(IntPtr hDCDest, int XOriginDest, int YOriginDest, int WidthDest, int HeightDest,IntPtr hDCSrc, int XOriginScr, int YOriginSrc, uint Rop);
2、使用場合
局部局域中單個圖元移動
3、簡單說明:
在圖元移動之前,計算出圖元移動目標影響的區域,然後將該區域拷貝爲一個圖片,然後進行移動操作,在下一次移動操作後,再將緩存的圖像拷貝到對應的區域中去,這樣就可以避免大面積的重畫,而且也不用產生控件的OnUpdate消息。他的具體過程如下圖所示:
4、缺陷及其對應措施:
這個方法只能夠移動一個單一的圖元,沒有辦法做到多個圖元同時移動(因爲移動拷貝目標區域的時候,如果存在多個圖元移動的情況下會互相影響),解決的辦法只有採用雙緩存,移動一次在後臺繪製整個被影響的區域,然後拷貝上去。
<!--[if !supportLists]-->三、 <!--[endif]-->圖元移動處理方法2
1、操作方法:
Graphics.Clip = Region ;// 限制繪圖區域
Region類
2、使用場合:
局部區域中單個圖元移動
局部區域中多個圖元聯動
3、簡單說明:
在局部區域中圖元移動的時候,其實圖元影響的只是較小的一個範圍,也就是說只需要重繪一個較小的範圍,這樣就可以避免移動時圖形閃爍的現象。但是怎麼限制重繪的區域呢?Graphics.Clip或者Graphics.SetClip給我們提供裏一個方法來限制重繪的區域。也就是說在圖元移動繪製函數中我們只要設置Graphics.Clip爲圖元當前區域以及圖元移動前區域的並集即可。
具體操作代碼如下所示意:
private Region _oldRegion;
// 獲取圖元當前影響的區域
private Region GetCurrentImageUnitRegion( )
{
…… //實現代碼
}
// 具體的繪圖函數
private void Draw( Graphics g )
{
……//實現代碼
//保存當前區域供下次使用。
this._oldRegion = this.GetCurrentImageUnitRegion( );
}
//在鼠標事件中進行圖元移動操作
private void OnMouse….( )
{
//設置圖元當前移動的新的位置。
……..
//進行繪圖操作
using( Graphics g = Graphics.From…(arg))
{
//聯合移動前影響的區域以及移動後影響的區域
this._oldRegion.Union( this.GetCurrentImageUnitRegion( ) );
//設置繪圖區域
g.Clip = this._oldRegion;
//繪圖操作
Draw( g );
}
}
4、評論:
方法3相對方法2來說更加的簡單明瞭,而且解決了方法2中不能夠多個圖元同時移動的問題,但是如果圖元影響的範圍較大的情況下,還是不能夠避免圖形閃爍的現象。