今天,想和大家聊一下有关软件的界面的一些知识,当一个软件程序被设计出来时,首先展现的就是界面效果,平时见过很多软件,早些很多商用的软件为了追求软件运行性能的出色,并没有把软件界面设计的美轮美奂,相反一些大型的桌面应用软件界面往往比较单调,比如一些大型ERP软件。我想原因也许有多种,究其一二,一是软件设计者在设计软件之初就忽略界面元素,只是一味的追求实现系统的核心业务功能。殊不知,如今的软件行业竞争也很大,尤其在同类型的软件中,软件的使用者越来越要求软件有更好的人机交互能力,更方便快捷美观的人性化的用户体验。好的用户界面必然在诸多同行软件中占据先机,备受青睐。二是为了追求高性能的运行稳定,提高界面的响应速度,有意未将软件界面效果纳入非功能需求范畴,以节约系统资源。以我的观点来看待这个问题,现在电脑处理器水平都比较高,3D游戏的推动和涌现带来了个人计算机软硬件技术的日新月异和网络通信技术的高速发展。性能资源消耗方面已不足为虑。很多漂亮软件界面呼之欲出。在国内软件中,有很多比较优秀的软件,在软件界面上更是做足了功夫,提供了诸多漂亮界面主题和皮肤包。比如,我们经常用的迅雷,腾讯QQ等桌面程序。每次版本的升级都带来全新的用户体验。个人简单的认为,软件的界面犹如人的衣装穿着,人人都有一颗爱美之心,而软件也不例外。我在校期间利用业余时间学习了C#、winform界面编程,学习固然很辛苦,都是靠自学,其中的动力就是对编程技术的热衷与追求。
其中第一点就是窗体动态效果的实现:
一, 调用系统API消息函数给窗体添加动态特效
1. 导入系统user32.dll并声明API函数AnimateWindow
//导入系统的COM组件:user32.dll (user32.dll是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息)
[System.Runtime.InteropServices.DllImport("user32")]
//声明系统API消息函数
private static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags);
AnimateWindow函数里面的3个传参的说明如下:
hwnd 界面上控件的句柄
dwTime 窗体特效执行的持续时间(1=1毫秒、1000=1秒)
dwFlags 窗体特效的值
2. dwFlags要传的参数是一些INT类型的常量,这些常量定义了该特效具体有哪些动作。
const int AW_HOR_POSITIVE = 0x0001; //正面_水平方向
const int AW_HOR_NEGATIVE = 0x0002; //负面_水平方向
const int AW_VER_POSITIVE = 0x0004; //正面_垂直方向
const int AW_VER_NEGATIVE = 0x0008; //负面_垂直方向
const int AW_CENTER = 0x0010; //由中间四周展开
const int AW_HIDE = 0x10000; //隐藏对象
const int AW_ACTIVATE = 0x20000; //显示对象
const int AW_SLIDE = 0x40000; //拉幕滑动效果
const int AW_BLEND = 0x80000; //淡入淡出渐变效果
3.在程序事件中调用AnimateWindow方法,执行窗体特效函数
AnimateWindow(this.Handle, 1000, AW_CENTER | AW_HIDE | AW_HOR_NEGATIVE);//动画——窗体由四周向中心缩小
纵然windows消息函数很强大,但也只能实现的窗体效果简单的表现需求,更多的情况是需要对窗体的重绘来实现更好的界面效果。
二、winform窗体重绘
重绘技术主要是对WIN32消息函数来处理的。
在窗体的大小和位置改变时,操作系统需要重绘窗体上的图形或控件。当窗体大小改变时都将触发窗体的重绘事件,下面将介绍窗体的两个重绘事件。
1. Paint事件
在一个窗体被移动或放大之后或在一个覆盖该对象的窗体被移开之后,该窗体部分或全部暴露时,Paint事件发生。如果在代码中使用了各种图形方法的输出,则使用Paint过程可以确保这样的输出在必须时能被重绘。使用窗体Refresh方法时,Paint事件即被调用。窗体Paint事件处理过程为: Private Sub Form_Paint()
说明:如果窗体的AutoRedraw属性被设置为True,系统自动进行重新绘图。
2.Resize事件
当窗体第一次显示或窗体的状态改变时将触发Resize事件,如对窗体进行最大化、最小化、还原、被鼠标拖动进行放大、缩小操作。使用Resize过程可以调整窗体的大小,也可以用来调整窗体上控件的大小与位置,使控件的大小随着窗体大小改变而改变,从而使得窗体布局更加合理和美观。窗体Resize事件处理过程为:
Private Sub Form_Resize()
比如:用 OnPaint 进行实时绘图的
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics dc = e.Graphics;
//以下是绘图内容
}
三. GUI重绘过程中带来的问题
主要是窗体的闪烁问题,网上处理的方式有很多种,常见的有二种:
1. 使用双缓冲(two way soft-closing)技术
如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。
首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:
CDC MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象 //随后建立与屏幕显示兼容的内存显示设备 MemDC.CreateCompatibleDC(NULL); //这时还不能绘图,因为没有地方画 ^_^
//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小,也可以自己定义
(如:有滚动条时就要大于当前窗口的大小,在BitBlt时决定拷贝内存的哪部分到屏幕上)
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); //将位图选入到内存显示设备中 //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); //先用背景色将位图清除干净,这里我用的是白色作为背景 //你也可以用自己应该用的颜色
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255)); //绘图
MemDC.MoveTo(……); MemDC.LineTo(……); //将内存中的图拷贝到屏幕上进行显示
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY); //绘图完成后的清理 //把前面的pOldBit选回来.在删除MemBitmap之前 要先从设备中移除它。
MemDC.SelectObject(pOldBit); MemBitmap.DeleteObject(); MemDC.DeleteDC(); (来源于百度)
2. 调用Control.SetStyle 窗体样式方法
如:public form_From()
{
InitializeComponent();
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);//调整大小时重绘边界。
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);// 禁止擦除背景.
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);// 双缓冲
this.UpdateStyles();
}
经过以上的步骤闪烁问题依然存在,最好的解决之道恐怕要在系统消息函数上再做文章,提供消息钩子设置窗口句柄函数。例如:WM_ERASEBKGND消息传递函数,这一点有待深究。
经过一阶段的学习,发现微软的.NET平台有很多可取之处,在大学过过好几种编程语言,编程语言之间相识的地方有很多。比如c#和java。用.NET开发软件周期短且效率高的。个人认为对一个程序员而言,时间应该是最宝贵的。学习.NET的人越来越多,我也是浩浩大军中的一员,出于对编程的热衷,最大限度的追求和实现软件界面的完美,下边用图片方式展示目前自己已经实现的精仿QQ窗体的界面效果。之所以模仿QQ界面,原因很简单就是要实现一个企业级使用的即时通讯组件。在以后的博文中将陆续介绍。
目前已经实现的QQ界面功能需求有:
1.实现窗体皮肤透明化处理,实现窗体半透明效果。
2.实现包含类似于QQ的主题板,调色板,纯色板的皮肤控制器。
3.实现软件退出皮肤动态保存,动态主题图片排序功能。
4.实现窗体主题皮肤动态预览功能。
5.实现用户自定义皮肤功能。
6.实现皮肤主题动态删除功能。
程序使用的是QQ图片资源,在此声明不做任何商业操作,仅仅是用于技术上的探究。下面是一些效果图以飨大家:
个人觉得使用用.NET平台设计软件界面的确很出色。WPF的出现将带来更多更炫的用户体验。当然文章中的有些观点并不成熟。只是一孔之见,一口之言,望各位牛人大虾不吝拍砖。本人今年大四,即将毕业,希望和志同道合的朋友一起交流技术心得。联系方式QQ:875297974