重拾Delphi试手之作,一个能让主窗口拖出渐变阴影的类--支持异型窗口

阿呆_ 2009-08-15 02:41:28
加精
抛弃 Delphi 4年后由于工作关系,又重新开始使用这个工具。为了尽快找回感觉,花了1天半时间试手写了一个类,只提供一个看上去很愚蠢的功能, 那就是能让form产生类似Vista和Win7中窗口的那种阴影, 呃, 加一点点微不足道的扩展--对不规则形状窗口照样有效. 效果还可以:


源代码:
http://download.csdn.net/sort/tag/Delphi/1168

由于是试手作品,所以源码当中没有注释。为了便于大家理解,我这里说一下设计思路:
原理极简单:偷偷生成一个新的带Layered属性的窗口,比目标Form大一圈,然后悄悄插到目标Form后边,位置几乎重叠稍稍偏出一点,然后保持一直躲在那。
这个新窗口通过API UpdateLayeredWindow() 设置了一幅带per pixel alpha channel的动态生成的32位bmp。这个bmp其实就是阴影啦。总的来说,实现起来还是比较容易没什么难度的。
代码当中稍微值得显摆一下的也只剩下这个32位bmp的生成和更新时机而已。
生成时首先用黑色充填整个bmp, 然后试图用GetWindowRgn()获取目标窗口的region, 如果有,那么用白色将这个region画到bmp合适位置上,没有region则用白色画一个方形(比窗口大一点点,原因后面会说到), 接着判断目标Form是否使用TransparentColor,如果用了,那说明目标也可能不那么规矩是个异型,呃,窗口。接下来就要想办法获取这个形状,这步是通过Form.PaintTo画到一个临时的tempbmp上,然后调用tempbmp.Mask(Form.TransparentColorValue)生成黑白图,将其画到32位bmp相应位置上。这步后有棱有角的阴影已经生成,接着逐像素处理bmp模糊化所有棱角和边框(为了追求速度,这段模糊化代码有个很不好的习惯, 那就是不规则图案看上去是向外圈扩张模糊的,而方形却是向内部收缩模糊, 这也就是为什么对规规矩矩的Form我们画阴影时要大上一圈的原因)。至此,阴影图案已经生成完毕。 不过这个只是24位的阴影,我们还需要将它扩展到32位的。因为我们刚才画的都是黑白色,因此每个像素中的rgb值正好都相等,我们只要逐像素过一遍,将该像素rgb中的任意一个复制到alpha位,并在复制的同时顺手将rgb颜色值改成设置的阴影颜色即可大功告成。最后将目标Form.AlphaBlendValue也顺过来一起调用UpdateLayeredWindow()更新界面. 好了, 酷酷胖胖的阴影就出现在屏幕上了.
为了保证我们的阴影窗口一直躲在目标Form下正确的位置上并保持正确的形状,我们还需要截获目标Form移动,改变大小和ZOrder变化的消息并对我们的阴影Form进行相应操作(需要判断是偷偷跟着一起跑就够了还是要重新生成). 为了省事, 在我们的阴影控件初始化时就偷换了目标Form.WindowProc,这样目标Form所有的消息都会先被我们得到. 我们感兴趣的其实只有两个消息--WM_WINDOWPOSCHANGING和WM_WINDOWPOSCHANGED, 因为所有目标Form位置,大小, 显示/隐藏等变化都会通过这两个消息得到反映。其实我们真正感兴趣的只有一个:WM_WINDOWPOSCHANGED, 此时对阴影进行调整就足够了。截获WM_WINDOWPOSCHANGING的目的是为了在目标窗口最大/最小前我们可以先一步隐身(为了执行效率,最大化时不生成阴影--因为大部分跑屏幕外边去了看不见),省得在目标Form往任务条上跑时我们的阴影还傻傻待在原地造成走光。

还有,使用这玩意还是比较简单的, 如果你想哪个Form飘起来,只要uses ufrmShadowFrame; 然后在Form.OnCreate中创建一个 Shadow := TFormShadow.Create(Application); Shadow.ParentForm := Self; 再在需要它起作用时设置Shadow.Active := True; 就行了。
BUT! 千万不要在Form.OnShow中调用Active := True; 如果你设置了TransparentColor, 那么就会得不到正确的阴影, 因为在OnShow中无法用Form.PaintTo()得到正确的界面图片.

最后, 我没有把它写成一个component而是做成一个需要你手工写代码调用的类. 因为我最讨厌的事就是: 为了阅读某个人写的程序, 我不得不安装一大堆我从来都用不上的控件, 还常常遇到它用的是针对某个版本delphi的没有源码地控件, 为了5分钟的阅读我可能要花几个小时才能建立起相同的编译环境才得以顺畅地看到对方的代码, 大多看完的感觉却是:"没这么玩人的".

因此, 我不玩你.
...全文
6087 127 打赏 收藏 转发到动态 举报
写回复
用AI写文章
127 条回复
切换为时间正序
请发表友善的回复…
发表回复
dongmei757 2012-07-27
  • 打赏
  • 举报
回复
学习,支持
广州佬 2012-07-20
  • 打赏
  • 举报
回复
首先很感谢楼主,让人受益匪浅了。
也感谢6楼。

工程除了23楼说的小问题外,当窗体最小化时,“...阴影还傻傻待在原地...”,恢复时,若能让窗体先于阴影恢复,那就更完美了。
酷阿金 2012-07-19
  • 打赏
  • 举报
回复
下载是php格式文件,打不开啊,急!哪们兄弟能否发份给我,谢谢了先
steedsky@163.com
jimpro1 2012-04-13
  • 打赏
  • 举报
回复
不错啊
lzg827 2012-04-01
  • 打赏
  • 举报
回复
这个得支持啊~~~~
大肚肥肥 2012-04-01
  • 打赏
  • 举报
回复
感谢楼主
taishan2033 2012-02-13
  • 打赏
  • 举报
回复
收藏下
代码跳动 2012-02-13
  • 打赏
  • 举报
回复
对我有用
对牛乱弹琴 2012-02-12
  • 打赏
  • 举报
回复
很不错
山东蓝鸟贵薪 2011-07-15
  • 打赏
  • 举报
回复
占个位置学习学习,谢谢分享
formernetcn 2011-07-15
  • 打赏
  • 举报
回复
可以学习,随便赚下分
smhpnuaa 2011-07-05
  • 打赏
  • 举报
回复
下载地址无效了嘛
林石公 2011-06-27
  • 打赏
  • 举报
回复
此处严禁挖坟
luquansen 2011-06-23
  • 打赏
  • 举报
回复
记号学习,佩服高手
黑漆漆 2011-06-23
  • 打赏
  • 举报
回复
老哥啊~真不好意思!

我是Delphi菜鸟来着,我看了你的说明,但是还是没法使用你的源码啊~

总是在构建时提示以下三个语句的Shadow错误

Shadow := TFormShadow.Create(Application);
Shadow.ParentForm := Self;
Shadow.Active := True;

请不吝赐教!
zhaohuateng 2010-09-29
  • 打赏
  • 举报
回复
delphi前辈啊,佩服佩服~~~
lyhoo163 2009-12-28
  • 打赏
  • 举报
回复
up
symr1314 2009-12-23
  • 打赏
  • 举报
回复
delphi前辈啊,佩服佩服~~~
fulirongWY 2009-11-25
  • 打赏
  • 举报
回复
牛B人物
sy0331 2009-11-24
  • 打赏
  • 举报
回复
今天仔细读了下程序,很简捷扼要。自己做了个Demo,发现在移动窗口或调整窗口大小时,有时阴影大小会算错。不知什么原因,是否还需要捕获其它Windows消息?楼主可否赐教?
加载更多回复(94)

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧