控件開發中與圖元移動有關的幾個個小技巧(DTE知識總結)

控件開發

<!--[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中不能夠多個圖元同時移動的問題,但是如果圖元影響的範圍較大的情況下,還是不能夠避免圖形閃爍的現象。

  

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章