winform 如何绘制窗体? - what a mess

注意:此贴不是解决贴,忍……

1 之所以讨论这个问题,是因为想使用GDI+绘制透明窗体,在之前我也做过简单的有透明特征的窗体,但是因为是在窗体的级别透明,所以实现起来没有难度(只要设置transparency key),但是假如需要定义透明的用户控件,你会发现很难实现(实际上在C#中几乎无法实现)。

2 仅仅通过设置控件的background color为transparent的话,在控件独自占据某个容器的时候是可行的(此时往往也是没有意义的),当另外的控件在其下层时,显示的时候会将下层控件也透明掉,而且这个透明会达到控件所在的容器级别。这种行为让人觉得窗体似乎是一层一层覆盖绘制的,而所谓的控件透明是用相应位置的容器背景填充控件绘制区,这样就解释了为什么下层控件也会被透明掉。

3 然而测试层叠控件的paint事件触发顺序,我们可以发现事实并非如此,反而是放在上层的控件会先被绘制。实际上控件绘制的顺序是正序的:首先绘制窗体,然后按照深度遍历,依次绘制controls集合(0-based),当绘制某个控件时需要裁剪绘制域,使得其只显示容器内部的部分、且不会对上层控件区域绘图。

4 这让人感到奇怪:为什么MS使用这样一种复杂的手段呢?假如不是索引值越小层次越往上,而是恰恰相反,绘图控制会简单得多——只要一层一层的覆盖就可以了。但是事实上处理绘图的机制要更加复杂(-_-)。当窗体移动、使用scroll滚动以及改变容器(不包含控件本身)可见域时,控件均不会发生重绘!这意味着图像的信息似乎一直保存在内存中,而且存在某种判断机制来识别控件是否被调整大小、改变图片等真正需要重绘场合。

5 我和网络上很多同学一样,都尝试过在paint方法中做文章:试图在需透明控件被绘制之前得到相应区域的图像(即容器和底层控件的复合图像)将之保存起来,然后获取透明控件的图像,逐像素地,使用本层非透明色替换上层透明色,这样呈现出来就如同透明一样。问题的关键是,paint方法中无法获取该区域原本的图像,而且即便能够获取,此方法处理时已经绘制完成了。而Form的DLL又没有提供预处理绘图的事件(painting?)。

 

就此基本否定了使用GDI+绘制透明控件的可能,聪明人都开始使用WPF了。

Technorati 标签: winform 透明

你可能感兴趣的:(winform 如何绘制窗体? - what a mess)