成人午夜激情影院,小视频免费在线观看,国产精品夜夜嗨,欧美日韩精品一区二区在线播放

對C#中的TreeView添加背景圖

2010-08-28 10:49:18來源:西部e網作者:

    在微軟的.NET 的Forms窗口控件中,比如Treeview和ListView,僅僅是對通用控件的簡單封裝,因此他們不正常的引發Paint事件。 微軟所發布內容中,能看到的唯一建議就是設置控件的ControlStyles.UserPaint類型,然后自己為控件做所有的繪圖操作。 (譯注:老外提供了一個TreeViewWithPaint控件類,派生自TreeView類,提供了Paint事件的掛接。)

  一、為了解決這個問題,我們在類內部使用了一個基于Bitmap類的Graphics對象。當任何窗口重新定義大小時候,對象都會重建。

//Recreate internal graphics object
protected override void OnResize( System.EventArgs e )
{
 if( internalBitmap == null || internalBitmap.Width != Width || internalBitmap.Height != Height )
 {
  if( Width != 0 && Height != 0 )
  {
   DisposeInternal();
   internalBitmap = new Bitmap( Width, Height );
   internalGraphics = Graphics.FromImage( internalBitmap );
  }
 }
}

  二、重寫窗口過程

  當控件收到了WM_PAINT消息時候,將執行下面的三個步驟:

  1. 通過一個內部的WM_PRINTCLIENT消息,讓原來的控件過程把圖象畫到內部的Graphics對象上。

//Draw Internal Graphics
IntPtr hdc = internalGraphics.GetHdc();
Message printClientMessage = Message.Create( Handle, WM_PRINTCLIENT, hdc, IntPtr.Zero );
DefWndProc( ref printClientMessage );
internalGraphics.ReleaseHdc( hdc );

  2. 使用內部的Graphics對象建立PaintEventArgs參數,引發用戶的OnPaint()函數。

//Add the missing OnPaint() call
OnPaint( new PaintEventArgs( internalGraphics, Rectangle.FromLTRB(
updateRect.left,
updateRect.top,
updateRect.right,
updateRect.bottom ) ) );

  3. 把內部Graphics對象的位圖拷貝到屏幕的Graphics設備上。

//Draw Screen Graphics
screenGraphics.DrawImage( internalBitmap, 0, 0 );

WM_ERASEBKGND消息被過濾掉,什么都不做。 case WM_ERASEBKGND:
//removes flicker
return;

  三、所提供的代碼和測試程序能使用Paint事件在TreeNode在被選中的時候,在其邊框上畫個黃色的邊框。但是,其實對于我實際要用的項目來說,需要添加背景圖的功能沒有實現。而這里離我們的目的還有一步之遙,我們對前文繪圖過程2和3之間加一個步驟:

Bitmap temp = new Bitmap(internalBitmap, internalBitmap.Size); // 建立一個臨時的位圖temp,保存前面繪好的界面

temp.MakeTransparent(Color.White); // 設置白色為透明色
internalGraphics.FillRectangle(Brushes.White, 0, 0, this.Bounds.Width, this.Bounds.Height);
// 在原來的內部位圖對象上,用白色重畫背景
if (image != null) // 如果設置了背景圖,就在內部對象上畫背景
internalGraphics.DrawImage (image, 0, 0, image.Width, image.Height);
internalGraphics.DrawImage(temp, 0, 0, temp.Width, temp.Height);// 把前面繪好的界面按白色為透明色復合到內部位圖上
screenGraphics.DrawImage( internalBitmap, 0, 0 ); // 把合成的臨時位圖刷到屏幕上

  其實,這里還存在一個問題:在處理WM_PAINT消息時候,通常的做法是使用BeginPaint和Endpaint函數來操作DC畫圖的,當樹結點展開或者折疊時候,我們收到WM_PAINT消息,并由消息得到的刷新區域或者說刷新矩形。關鍵就是在于,這里的刷新區域不是整個客戶區,背景圖會出現重疊的部分而變形。

  解決方法:考慮使用GetDC和ReleaseDC操作,可以避開刷新區域的限制,我們可以把整個客戶區重畫,而實現背景圖的完整性。這里要非常注意的是:BeginPaint和Endpaint函數會自動把需要刷新的區域設為有效,而GetDC和ReleaseDC函數不會,所以我們要自己增加兩個操作GetUpdateRect和ValidateRect,也就是自己把需要刷新的區域設置為有效。否則:會不停的得到WM_PAINT消息,和死循環一樣,CPU占用達到100%。


圖一 測試程序

  四、結束語

  由于使用了Win32的API函數,因此附加了一個Win32內部類,導入了自己需要的函數。
關鍵詞:C#TreeView

贊助商鏈接:

主站蜘蛛池模板: 玉龙| 郸城县| 疏勒县| 聂拉木县| 云阳县| 来宾市| 阿勒泰市| 铅山县| 盐津县| 普格县| 商都县| 华容县| 廉江市| 兰考县| 象州县| 新泰市| 泰州市| 鄱阳县| 铜川市| 讷河市| 万安县| 娄烦县| 台北县| 图木舒克市| 台山市| 东城区| 二连浩特市| 车致| 彰化县| 合江县| 阿坝县| 古丈县| 闽清县| 理塘县| 当涂县| 桑植县| 涞水县| 习水县| 宾川县| 潜山县| 洪雅县|