最近迷上了迅雷7的界面特效,有种惊为天人的感觉,尤其是那右键滑动菜单,还有那皮肤管理器的水平翻转。于是在毕设之余搞了搞界面特效之类的东西。其实像渐变三态按钮,滑动菜单,类Win7进度条什么的,开工前两周就已经搞定了,唯独这个半透明缩放窗口,拖了三个月搞到现在才算找到一个满意的解决方案。
看到现在有很多童鞋,尤其是易友们都非常乐中于UI特效,我虽然不太懂易语言,但也down下来一些demo来,比了比发现我做的还不错,我是用VC6+MFC+OpenCV实现的,估计现在商业软件的话用VC编C/C++的还是蛮多的把,呵呵,VC7/8/9/10原理应该也类似。于是在这里讲一下思路,算是抛砖引玉把。事先声明一下,有些部分并非原创,版权属于原作者:)
1)首先最基本的是实现不规则形状窗口,这里我推荐使用BitmapDialog,这是一个pudn上的一个开源类,继承于CWnd,我们只需将自己的CXXDlg类继承他就Ok。剩下的只需要设定皮肤图片,透明色,还可实现任意位置拖拽,功能很强大。其实很多其它的开源库或类也能实现这些功能,但是前者与BitmapDialog最大的区别是BitmapDialog可以与其它库如SonicUI无缝继承,这个非常赞
上图窗口均为不规则形状(圆角),那个菜单是动态弹出的(类似迅雷7),所有按钮均为渐变三态按钮,下面还有个Win7风格的进度条,自绘实现
2)第二类就是渐变三态按钮,滑动菜单和进度条了。其实渐变三态按钮想想挺头疼的,如何写代码让它去渐变呢,幸好SonicUI(一位高人写的开源界面库)提供了三态按钮的原生支持,据说有很多恶心人的SSE指令集优化,我猜测应该与这个效果的实现有关,所以果断的用他的算啦。滑动菜单和进度条就比较简单了,一个字就是画。需要注意的是滑动菜单的draw需要在timer中实现比较好,进度条的走位在OnPaint中实现,高光在timer中实现,timer这个东西在网上查到的大家都说精度在50ms,不过我试验的结果是间隔设为10ms比较好(跟50ms效果差距也蛮大的),具体的draw函数我是采用的SonicUI里提供的,自己直接DrawToHdc的话估计需要双缓冲一下。。
3)最后的也是最麻烦的就是半透明缩放窗口了,这其实可以分解为两个效果:半透明的渐变和缩放的渐变,单独实现其中一个还是不很难的,只是放一块就恶心了。半透明很容易,SetLayeredWindowAttributes一个函数就搞定。缩放我尝试了很多方法,BitBlt自带的缩放,CxImage里的缩放,甚至考虑到了DirectDraw里的Overlay表面了,越来越复杂。其中DDraw本来就不适合这种窗口应用,所以也没搞成,剩下的CxImage性能较低下。后来学仪器光电的童鞋告诉了有OpenCV这么个东西,还是Intel出的,好家伙,那不用想,肯定是它快。安好了OpenCV一调函数,果然NB。需要注意的是需要在OpenCV的IplImage上缩放(调用cvResize函数),而不要用CvvImage的DrawToHdc自带的,速度差别很大。再调一下cvResize的放缩算法,选哪个效果都差不多,就选那个叫NN的啦,速度贼快。
需要注意一点就是擦除图像要InvalidateRect与UpdateWindow联合使用,别犯懒用Invalidate,速度慢不说还容易闪,UpdateWindow一定要有,表示把WM_Paint消息直接发往窗口而不经过消息队列,用不用差别还是很大的。
上面就是我最终实现的半透明缩放窗口特效,窗口打开时先放大后缩小,关闭时先缩小后放大。
这样就分别实现了半透明和缩放,关键是怎么和在一起呢?这里一个比较简单的方法就是将半透明缩放窗口的特效另开一个Dialog实现,真正的Dialog打开时先隐藏,然后调用这个特效Dialog,特效完毕再切回真正的Dialog,当然中间切换的timing还是很有讲究的,不小心就会闪瞎咱的狗眼,闪了我一天最终还是搞定。隐藏和显示真正Dialog用MoveWindow就行,省时省力。特效Dialog主要作用是提供hWnd进而提供hDC进行绘图,修改Dialog的透明度可以进而修改其上所绘图形的透明度。说到这里就很明白了把,还涉及到最后一个问题,就是如何隐藏特效Dialog本体?我这里就用到了SetLayeredWindowAttributes中的透明色,呵呵,把那个讨厌的0xff00ff设成透明色,再将其设成特效Dialog的背景色就ok啦(继承OnEraseBkgnd)。
重点都说完了,剩下的就是一些细节问题比如timer中的状态机怎么设置才能产生平滑加速,减速的动画,可以参考运动学设个加速度什么的,呵呵。