当前位置: 首页 > 图文教程 > 开发语言 > VC++ > 对C#中的TreeView加背景图

VC++
在类VC的界面实现中加入目录树
软件换肤技术在 BCB 中的实现
利用非模窗口生成MDI介面
报表输出轻松搞定
Windows 中不规则窗体的编程实现
解说Win32的窗口子类化
使用测试优先方法开发用户界面
一个简单的登录对话框的实现
一个简单的日记本程序
从资源中加载皮肤
一个在RichEdit中添加表情图象的类
ActiveSkin 4.3 软件换肤在VC中的实现
一种另类“关于(About)”对话框的动态显示方法
对话框打印预览及打印
关于如何换肤、子类化的解决方案
制作 MSN、QQ 的消息提示窗口
如何对 BCGControlBarPro 进行换肤
定制个性化的对话框窗口类
改变窗口中的光标形状
更新MFC中的视图,跟踪.NET Framework中的事件

VC++ 中的 对C#中的TreeView加背景图


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-30   浏览: 73 ::
收藏到网摘: n/a

对C#中的TreeView加背景图

翻译整理:李静南

下载源代码

原文地址:http://www.codeproject.com/cs/miscctrl/genmissingpaintevent.asp

  序:在微软的.NET 的Forms窗口控件中,比如Treeview和ListView,仅仅是对通用控件的简单封装,因此他们不正常的引发Paint事件。 微软所发布内容中,能看到的唯一建议就是设置控件的ControlStyles.UserPaint类型,然后自己为控件做所有的绘图操作。 (译注:老外提供了一个TreeViewWithPaint控件类,派生自TreeView类,提供了Paint事件的挂接。)

一、为了解决这个问题,我们在类内部使用了一个基于Bitmap类的Graphics对象。当任何窗口重新定义大小时候,对象都会重建。

//Recreate internal graphics objectprotected 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 GraphicsIntPtr 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() callOnPaint( new PaintEventArgs( internalGraphics, Rectangle.FromLTRB( updateRect.left, updateRect.top, updateRect.right, updateRect.bottom ) ) );
3. 把内部Graphics对象的位图拷贝到屏幕的Graphics设备上。
//Draw Screen GraphicsscreenGraphics.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%。


图一 测试程序

四、结束语