`
snzipeng
  • 浏览: 21998 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

[转]循序渐进实现仿QQ界面(三):界面调色与控件自绘

阅读更多

本篇讲述如何进行界面调色。界面调色一般有两种方法,调色板和HSL色彩变换。调色板局限于256色,这里不采用,因此用HSL色彩变换实现。首先要了解一下什么是HSL色彩空间,完整且详尽的知识请到维基百科去看,链接地址:http://zh.wikipedia.org/wiki/HSL%E5%92%8CHSV%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4,这里简单讲一下(摘自维基百科):
HSL 和 HSV(也叫做 HSB)是对RGB 色彩空间中点的两种有关系的表示,它们尝试描述比 RGB 更准确的感知颜色联系,并仍保持在计算上简单。HSL 表示 hue(色相)、saturation(饱和度)、lightness(亮度),HSV 表示 hue、 saturation、value 而 HSB 表示 hue、saturation、brightness(明度)。如下图:



HSL 和 HSV 二者都把颜色描述在圆柱体内的点,这个圆柱的中心轴取值为自底部的黑色到顶部的白色而在它们中间是的灰色,绕这个轴的角度对应于“色相”,到这个轴的距离对应于“饱和度”,而沿着这个轴的距离对应于“亮度”,“value”或“明度”。

把RGB颜色转换到HSL色系,进行调色就很简单了,改变色彩只要转个角度,改变亮度就是沿轴升降进行“切片”,饱和度就是改变到中心轴的距离,3点定位到一个颜色,再转回RGB颜色就完成了界面调色。对需要调色的贴图进行这么一个变换,再重新贴图刷新一下界面就完成了调色功能。

并不是所有图片都需要调色,象标题栏右边的沙滩图案,如果调色就很难看了,会象照片的负片效果,因此用户头像,底纹图案,文字,图标都不需要调色,只需要把背景图案,按钮的高亮和按下状态图片,菜单背景和高亮图案进行色彩变换就行了。系统按钮需要局部调色,把最小化和最大化,还原按钮的高亮和按下状态的背景进行调色,因此准备了另外一张图片,一共5张图片需要调色:

 

最后一张图片是调色后透明绘制到系统按钮源图象上,实现了局部调色。

HSL色彩变换的实现是通过挂接图象库的滤镜插件类实现,实现原理请看RingSDK的帮助文档,调用代码极其简单,m_dibBkg.GETFILTER(dibFilterEFFECT)->AdjustHSL(h,s,l);就完成了背景的调色。图象库实现了两个滤镜插件类,dibFilterALPHA和dibFilterEFFECT,实现图象的各种ALPHA混合效果和亮度对比度,色度调整等。这里把关键的调色代码贴出来,其中m_rdib->Data()为已加载的32位色图象数据:

C/C++ code
//调整色调,参数范围:-180~180(度),=0不作调整 //调整饱和度,参数范围0~200(建议,最大值可>200),=100不作调整 //调整亮度,亮度参数范围0~200(建议,最大值可>200),=100不作调整 BOOL dibFilterEFFECT::AdjustHSL(int degHue,int perSaturation,int perLuminosity) { if(!m_rdib->Data()) return FALSE; if(perSaturation < 0 || perLuminosity < 0) return FALSE; if(degHue == 0 && perSaturation == 100 && perLuminosity == 100) return TRUE; //未作调整,直接返回 LPBYTE pRed, pGrn, pBlu,pBuf=(LPBYTE)m_rdib->Data(); UINT loop = m_rdib->Width() * m_rdib->Height(); COLORREF *cr = (COLORREF*)m_rdib->Data(); pRed=pBuf++;pGrn=pBuf++;pBlu=pBuf; float H,S,L; for (UINT i=0;i<loop;i++) { RGBtoHSL(*pRed,*pGrn,*pBlu,&H,&S,&L); H += degHue; S = (S*perSaturation/100.0f); L = (L*perLuminosity/100.0f); *cr = HSLtoRGB(H,S,L); pRed+=4; pGrn+=4; pBlu+=4; cr ++; } return TRUE; } void dibFilterEFFECT::RGBtoHSL(BYTE R,BYTE G,BYTE B,float* H,float* S,float* L) { BYTE minval = min(R,min(G,B)); BYTE maxval = max(R,max(G,B)); float mdiff = float(maxval) - float(minval); float msum = float(maxval) + float(minval); *L = msum / 510.0f; if (maxval == minval) { *S = 0.0f; *H = 0.0f; } else { float rnorm = (maxval - R) / mdiff; float gnorm = (maxval - G) / mdiff; float bnorm = (maxval - B) / mdiff; *S = (*L <= 0.5f) ? (mdiff / msum) : (mdiff / (510.0f - msum)); if(R == maxval) *H = 60.0f * (6.0f + bnorm - gnorm); if(G == maxval) *H = 60.0f * (2.0f + rnorm - bnorm); if(B == maxval) *H = 60.0f * (4.0f + gnorm - rnorm); if (*H > 360.0f) *H -= 360.0f; } } COLORREF dibFilterEFFECT::HSLtoRGB(float H,float S,float L) { BYTE r,g,b; L = min(1,L); S = min(1,S); if(S == 0.0) { r = g = b = (BYTE)(255 * L); } else { float rm1, rm2; if (L <= 0.5f) rm2 = L + L * S; else rm2 = L + S - L * S; rm1 = 2.0f * L - rm2; r = HueToRGB(rm1, rm2, H + 120.0f); g = HueToRGB(rm1, rm2, H); b = HueToRGB(rm1, rm2, H - 120.0f); } return RGB(r,g,b); } BYTE dibFilterEFFECT::HueToRGB(float rm1,float rm2,float rh) { while(rh > 360.0f) rh -= 360.0f; while(rh < 0.0f) rh += 360.f; if(rh < 60.0f) rm1 = rm1 + (rm2 - rm1) * rh / 60.0f; else if(rh < 180.0f) rm1 = rm2; else if(rh < 240.0f) rm1 = rm1 + (rm2 - rm1) * (240.0f - rh) / 60.0f; float n = rm1*255; int m = min((int)n,255); m = max(0,m); return (BYTE)m; }


实现了界面调色功能,接下来就得实现调色的设置界面,QQ2009的调色设置是预置了8种基色,可以选择一种基色,也可以对HSL分别调色,但是这8种基色是随着底纹和皮肤的选择变动的,皮肤的选择影响可选择的底纹和基色,一开始没怎么搞懂,后来下了一个QQ2009的主题包,结果是一个自定义格式的打包文件,没办法解开看里面图片,就没研究了,再下了一个2008版的主题包,可以看到所用的图片,大致清楚其为什么这么做了,里面的底纹图片是BMP格式,用紫红做透明色,由于没有ALPHA混合通道,这样的图片透明绘制到背景,边缘是有锯齿的,除非背景颜色跟图象边缘颜色相近才看不出来,因此选择的皮肤会限定底纹图片和背景颜色,选择底纹会同时变动背景颜色,再调色则对背景和底纹一起调色,底纹图案尽量采用RGB色差不大的图案,使调色效果不会太明显,这样整个界面调色底纹图案就没有了锯齿,变化也不怎么看得出来,是一种比较巧妙的做法。当然这是QQ以前版本的做法,2009应该已经改进了。这里演示的界面调色功能由于底纹图案是采用了带ALPHA通道的PNG格式图片,因此不存在这样的限制,同时为了简单起见,代码易于理解,就不学QQ的做法了,取消皮肤的设定,调色和底纹的选择互不影响,不做联动。在资源里预置了5张底纹图片可供选择,有兴趣的可以自己加。这里只是为简单起见而将底纹加到了资源里面,实际为了实现换肤并可扩展应该是自己实现一个换肤的配置文件和资源包,这里就不演示了。

现在实现调色的设置界面,首先响应“更改外观”按钮的弹起事件(WM_LBUTTONUP消息里面),弹出设置窗口,这个窗口是资源里面调色和底纹对话框的大小,不可拖动和调整大小,需要在失去焦点时自动隐藏,因此需要在其WM_ACTIVATE消息里面判断一下,如果是WA_INACTIVE状态就发送一个退出消息把自己关闭。加载调色和底纹两个对话框,显示一个,把另一个隐藏,调色和底纹的选择看起来应该是TAB控件,不过得自绘,这里用图片控件模拟TAB反而简单,反正只有两个选择,判断一下鼠标位置,换个图片,切换一下两个对话框的显示状态,看代码就知道了。

这里主要讲解一下调色对话框上4个Slider控件的自绘。控件自绘需要先子类化,RingSDK界面库已经封装好了,继承相应的控件类,子类化是自动的,可以重载其RingdowProc函数,即控件的窗口过程,想做什么都可以,给了你最大的自由度,未处理的消息返回DefaultProc或基类的RingdowProc就可以。自绘的Slider控件是继承自RingTrackBar,只要响应其WM_PRINTCLIENT和WM_PAINT消息,把背景图案和滑块图案画上去就OK了,代码很简单:

C/C++ code
LRESULT RingTrackBarEx::RingdowProc(HWND hWnd,RINGPARAMS param) { switch(param.uMsg) { case WM_PRINTCLIENT: case WM_PAINT: { RECT rc,rcc; HDC hdc,hMemDC; PAINTSTRUCT ps; GetWindowRect(m_hWnd,&rc); OffsetRect(&rc,-rc.left,-rc.top); hdc = param.wParam?(HDC)param.wParam:BeginPaint(hWnd,&ps); FillRect(hdc,&rc,m_brush); hMemDC = CreateCompatibleDC(hdc); SelectObject(hMemDC,m_hbmLine); GetChannelRect(&rcc); StretchBlt(hdc,rcc.left,(rc.bottom - m_sizeLine.cy)/2,rcc.right-rcc.left,m_sizeLine.cy, hMemDC,0,0,m_sizeLine.cx,m_sizeLine.cy,SRCCOPY); SelectObject(hMemDC,m_hbmThumb); GetThumbRect(&rc); BitBlt(hdc,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,hMemDC,0,0,SRCCOPY); DeleteDC(hMemDC); if(param.wParam == 0) EndPaint(hWnd, &ps); return 0; } } return DefaultProc(param); }


因为调色函数AdjustHSL的参数关系,设置调整色调的控件调整范围值为-180 ~ 180,初始值为0,饱和度和亮度的范围都是0 ~ 200,初始值为100。关于透明度的调整,怎么使窗口半透明网上介绍文章有很多,这里就不罗嗦了,界面库对此做了封装,调用SetLayeredAlpha就可以了,不过范围值是设成了25 ~ 255,不能0 ~ 255,全透明的话窗口就不能操作了。

调整色调的图片是展开的HSL色环,如下图:



注意因为默认的背景是兰色,因此兰色是在图案的中间,如果默认背景是别的颜色,就需要循环平移这些色彩,使背景色处在中间位置,否则拖动滑块调色,实际的效果跟滑块所在的颜色就对不上号了。

底纹图案的选择很简单,重新加载选择的图案就OK,看代码就知道了。

至此完成了界面调色功能,界面中间部分因为以后会有控件遮盖,因此不需要调色。现在看看程序的截图:




最后说一下怎么做带ALPHA通道的PNG图片和加到程序里面:

首先找一张自己满意的图片,调整到高度95,QQ标题栏的高度,宽度随意,只要图案不怎么变形就可以,然后加一个蒙板,如图,按一下图中的按纽:



要使图片透明,需要去除背景,如果是新建图片并复制了图象过来,把背景层删掉,如果是直接打开的图片,需要复制一层然后把背景层删掉。加了蒙板后选择渐变工具,从右往左一拉,然后把图片保存为PNG格式就可以了,如图:



做完PNG图片还要做一张31*31的预览BMP图片,按资源里的格式做就可以了,把PNG加入为“PNG”类型的资源,ID值必须与resource.h里IDP_SEA等5张预置图片的ID值连续,预览图片的ID值必须与IDB_TATOO1~IDB_TATOO5的值连续,在wnduioption.cpp里面找到gszTatooInfo的初始化代码,把图片说明加到里面,编译一下程序就OK了。

现在这个仿QQ界面的程序已经完成了标题栏部分的功能,接下来要完成客户区和底栏部分的功能,留待下一篇再讲了。

程序代码下载地址:http://download.csdn.net/source/1995651

分享到:
评论

相关推荐

    循序渐进实现仿QQ界面(四)

    在本教程中,我们将深入探讨如何“循序渐进实现仿QQ界面(四)”。这个教程是基于VC6,一个经典的Microsoft Visual C++ 6.0集成开发环境,虽然现在可能较旧,但它仍然是学习Windows应用程序开发的良好平台。在本阶段...

    模仿QQ界面(三):界面调色与控件自绘

    在开发聊天程序,尤其是模仿QQ界面的过程中,界面的美观性和个性化是吸引用户的重要因素之一。本文将探讨如何通过HSL色彩变换实现界面调色,从而为应用程序增添独特的视觉效果。 首先,我们需要理解HSL色彩空间的...

    仿QQ界面程序(5)

    编译有问题的,请到以下地址去看: ... 循序渐进实现仿QQ界面(五):半透明窗体与不透明控件的配套源码,文章请见: http://blog.csdn.net/ringphone/archive/2010/02/11/5306231.aspx

    仿QQ登录界面

    【标题】"仿QQ登录界面"是一个项目,旨在利用MFC(Microsoft Foundation Classes)库来创建一个类似于腾讯QQ的登录窗口。MFC是微软为Windows应用程序开发提供的一组C++类库,它使得开发者能够方便地构建用户界面,...

    仿QQ界面程序(2)

    缺头文件的,请到下面文章的地址去看。 循序渐进实现仿QQ界面(二):贴图按钮的三态模拟的配套源码,文章请见:http://blog.csdn.net/ringphone/archive/2010/01/10/5171490.aspx

    QT实现高仿QQ QT实现QQ界面

    本项目"QT实现高仿QQ QT实现QQ界面"旨在通过QT框架来复刻QQ的经典界面,从而展示如何利用QT库来创建类似QQ这样的即时通讯软件的用户界面。下面将详细介绍这个项目可能涉及的关键知识点: 1. **QT Widgets模块**:QT...

    一个简易仿qq登录界面

    实现一个简易仿qq登录界面,要求实现: 1) 登录界面有帐号、密码文本和编辑框,登录和退出按钮。在程序中维护一个帐号密码的数组,用以判断正确登录与否。如果登录成功,则进入qq主界面,否则清空帐号和密码编辑框,...

    仿qq界面实现(仿照qq2008版界面实现)

    在本文中,我们将深入探讨如何使用C++编程语言来实现一个仿照QQ2008版界面的应用程序。QQ作为一款流行的即时通讯软件,其用户界面设计独特且易用,吸引了大量的用户。为了重现这样的用户体验,我们需要理解界面设计...

    winform高仿qq登陆界面

    1. **界面设计**:使用Visual Studio的WinForms设计器,摆放控件,调整大小和位置,设置字体、颜色和图片等视觉元素,以达到与QQ登录界面的相似效果。 2. **事件处理**:编写C#代码,如在登录按钮的Click事件中,...

    C# 仿qq界面

    7. **网络通信**:为了让仿QQ界面具有实际功能,还需要实现客户端与服务器之间的通信。这涉及到网络编程,可以使用C#的Socket类进行TCP/IP通信,或者使用WebSocket等高级API来处理实时数据交换。 8. **多线程**:...

    仿QQ界面程序(3)

    总的来说,这个"仿QQ界面程序(3)"项目是一个很好的学习资源,它让我们了解并实践了GUI设计中的关键技巧,包括界面设计的美学原则、控件自绘的技术细节以及面向对象编程的设计模式。通过深入研究和模仿,我们可以...

    Qt 模仿QQ登陆,QQ好友列表,QQ聊天窗口。完全复原QQ界面,可以学习Qt基础,Qt界面美化,自定义树形控件等知识。

    在本文中,我们将深入探讨如何使用Qt框架来模仿QQ的登录、好友列表和聊天窗口,以帮助初学者理解和掌握Qt的基础、界面美化以及自定义控件的创建。 首先,让我们了解Qt。Qt是一个跨平台的应用程序开发框架,由The Qt...

    QQ界面的控件

    本篇文章将深入探讨如何使用Delphi来实现QQ界面的控件,特别是仿QQ好友列表的构建。 首先,我们要理解"仿QQ界面"这个概念。这不仅意味着我们需要创建具有类似外观的界面,还涉及到功能的模仿,如好友分组、在线状态...

    XE7 高仿QQ界面无第三方面控件

    在本文中,我们将深入探讨如何使用Delphi XE7来创建一个高仿QQ界面的应用程序,无需依赖任何第三方控件,完全基于标准控件。这个项目对于那些希望学习或提升界面设计技能,尤其是使用Delphi的开发者来说,具有很高的...

    仿QQ界面程序(6)

    编译有问题的,请到以下地址去看: ... 循序渐进实现仿QQ界面(六):异型菜单与内建滚动条自绘的配套源码,文章请见: http://blog.csdn.net/ringphone/archive/2010/03/13/5377522.aspx

    MFC 精仿QQ主界面(无闪烁移动,抽屉窗口,QQ好友列表)

    VS2008精心仿制QQ界面,纯MFC自绘控件打造精美QQ界面,利用双缓存贴图技术实现无闪烁移,源码上传。如果有建议与问题,请与我联系。此作品仅作参考,大家一起共同交流学习。若有修改后的成品还请发给我一份,谢谢!

    VB6.0QQ界面控件

    标题中的“VB6.0QQ界面控件”指的是使用Visual Basic 6.0(VB6.0)编程环境开发的一种控件,该控件的设计灵感来源于腾讯QQ的用户界面,旨在为开发者提供一种简单的方法来创建类似QQ的图形用户界面(GUI)。...

    QQ 登录界面 各个控件图片资源

    QQ登录界面是用户接触QQ应用的第一步,其设计和实现涉及到多个UI控件以及相应的背景图片资源。在本文中,我们将深入探讨QQ登录界面中各控件的图片资源及其重要性,同时也会提及如何管理和使用这些资源。 首先,登录...

    循序渐进学java视频教程之山寨版QQ

    资源名称:循序渐进学java视频教程之山寨版QQ资源目录:【】abbr_2b0a956c6deaffd161055bcc69352490【】abbr_69fe1d0216f529000a178ba7a943dbd8【】abbr_83be30c3d0d895e0b4887fe4e9c049f2【】abbr_89247c1a9c971d54...

Global site tag (gtag.js) - Google Analytics