DirectUi的效果可以使用GDI、GDI+、DirectX、OpenGL实现,常用的有GDI和GDI+,后两种有杀鸡用牛刀的感觉。在网络上能找到此方面的教材

现在的软件越来越多的有很炫目的界面,看来商家是越来越重视用户体验了,这个一个流行趋势呀。从技术上来说,美化界面基本有两种方式:

1. DirectUi 无句柄自绘控件方式

2. 继承MFC控件类进行自绘

两种各有优缺点,前者:实现复杂,控制复杂(如:消息控制、各个控件的基本设置),但自由度很大,你可以实现你能想象到的任何控件。后者:实现简单、但受制于MFC现有的控件功能,最重要的是窗口一旦多,窗口背景的绘制和子窗口的绘制如若处理不当很容易造成局部贴图残缺、拖拽窗口闪烁。所以一般在子窗口控件不随着主窗口拖拽而发生位置变化时采用后者的方式,其他建议采用前者的方式来完成。

由于以后会经常用到DirectUi进行界面美化,于是抽空打了一个DirectUi的开发平台,方便以后开发,DirectUi的开发平台要求如下:

1. 建立在VS2005的MFC Dialog工程之上

2. 实现最基本的一个空的Dialog的皮肤

3. 皮肤实现后,必须保留最基本的Dialog的功能,如:最大化、最小化、双击标题栏、单击任务栏按钮、拖拽等

4. 建立DirecrUi的引擎,已最简便的方式便于以后的程序扩展

OK,开工了。先建立MFC的Dialog的工程,保持所有属性都默认,去掉【确定】和【退出】按钮,如下:

之后我们必须解决一个又一个问题:

问题1:我们在什么地方重绘窗口

有3个消息处理可以重绘窗口:WM_ERASEBKGND、WM_PAINT、WM_NCPAINT,第一个只重绘窗口整个背景,包括客户区和非客户区,不重绘子窗口;第二个只重绘客户区,无法重绘非客户区;第三个重绘非客户区,也可以重绘客户区。很明显,我们应该处理第三个消息,但第一个消息我们也需要处理,整个函数,直接 return TRUE 即可。

问题2:顽固的系统默认标题栏

绘制第一步当然是重绘标题栏,在WM_NCPAINT里重绘标题栏后,发现那几个系统按钮在窗口激活或者拖动的时候是不是闪现在界面上,相当的顽固,如下方法即可解决:

1. 截获 WM_NCACTIVATE 消息,此消息函数修改如下:

BOOL CSkinTestDlg::OnNcActivate(BOOL bActive)
{
 this->SendMessage(WM_NCPAINT, 0, 0);
 return TRUE;
}
2. 在 WindowProc 函数中截获绘制标题栏的消息,代码如下:

LRESULT CSkinTestDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
 if(message == 0x00AE || // WM_NCUAHDRAWCAPTION
 message == 0x00AF)  // WM_NCUAHDRAWFRAME
 {
  return WM_NCPAINT;
 }

return __super::WindowProc(message, wParam, lParam);
}

以上两步,可以很完美的解决顽固的标题栏按钮问题。

问题3:变态的标题栏消息处理

系统自带的标题栏会随着桌面主题的变化,标题栏的高度、系统按钮的位置都会发生变化,这个相当烦人,咱们自定义的按钮的位置大小一般都不会和系统按钮相同。在处理这个问题的过程中,发现了一些导致了一些矛盾之处,几乎很难调和(抱歉,时间太久了,很多的矛盾忘了),比如:客户区坐标和非客户区坐标转换问题(两套坐标系,维护比较麻烦)、鼠标在标题栏的双击区域、最大化的边框问题... ... 结合这些问题,最后的处理方式是:截获 WM_NCCALCSIZE 消息,修改非客户区大小,让非客户区大小为0,所有自绘的东东都在客户区实现,包括标题栏和边框。代码如下:

// 截获此消息为了让窗口没有标题栏和边框
void CSkinTestDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
 // __super::OnNcCalcSize(bCalcValidRects, lpncsp);
}

问题4:没有边框的拖拽

问题3的衍生问题,没有了边框,当然就不能拖拽了,那我们自己处理拖拽吧,很简单,截获 WM_NCHITTEST 消息,代码如下:

LRESULT CSkinTestDlg::OnNcHitTest(CPoint point)
{
  // 注意:不是全屏的情况下,才可以拖拽,需要用户自己处理
  int nCheckPos = 2;
  int nRDPos = nCheckPos * 2;
  CRect WndRect(0, 0, 0, 0);
  GetWindowRect(&WndRect);

m_nMouseSizeType = -1;
  if(point.x >= WndRect.right - nRDPos && point.y >= WndRect.bottom - nRDPos)
  {
   // 右下角
   return HTBOTTOMRIGHT;
  }
  else if(point.x >= WndRect.right - nRDPos && point.y <= WndRect.top + nRDPos)
  {
   // 右上角
   return HTTOPRIGHT;
  }
  else if(point.x <= WndRect.left + nRDPos && point.y <= WndRect.top + nRDPos)
  {
   // 左上角
   return HTTOPLEFT;
  }
  else if(point.x <= WndRect.left + nRDPos && point.y >= WndRect.bottom - nRDPos)
  {
   // 左下角
   return HTBOTTOMLEFT;
  }
  else if(point.x >= WndRect.right - nCheckPos)
  {
   // 右边线
   return HTRIGHT;
  }
  else if(point.x <= WndRect.left + nCheckPos)
  {
   // 左边线
   return HTLEFT;
  }
  else if(point.y <= WndRect.top + nCheckPos)
  {
   // 上边线
   return HTTOP;
  }
  else if(point.y >= WndRect.bottom - nCheckPos)
  {
   // 下边线
   return HTBOTTOM;
  }

return __super::OnNcHitTest(point);
}

问题5:最大化的边框问题

一个正常的窗口,最大化后总是比当前屏幕大,刚好能将软件的边框盖住,我实在不想要这个效果,那我只能自己处理最大化的效果了。

我自定一个了最大化消息,当自绘的最大化按钮按下时,触发这个消息,接受到消息后,取得屏幕的工作区域,然后将窗口改变到工作区域大小即可,代码如下:

// 先记录最大化前的窗口位置,以便恢复的时候用。
    this->GetWindowRect(&m_MaxBeforeRect);
    CRect WndRect(0, 0, 0, 0);
    ::SystemParametersInfo(SPI_GETWORKAREA, 0, &WndRect, 0);

this->MoveWindow(&WndRect);

问题又来了:最大化动画没了,这个简单,再加一句代码,播放动画:

// 先记录最大化前的窗口位置,以便恢复的时候用。
    this->GetWindowRect(&m_MaxBeforeRect);
    CRect WndRect(0, 0, 0, 0);
    ::SystemParametersInfo(SPI_GETWORKAREA, 0, &WndRect, 0);

// 播放动画
    DrawAnimatedRects(IDANI_CAPTION, &m_MaxBeforeRect, &WndRect);

this->MoveWindow(&WndRect);

同样恢复窗口的代码如下:

// 恢复
    CRect WndRect(0, 0, 0, 0);
    ::SystemParametersInfo(SPI_GETWORKAREA, 0, &WndRect, 0);

// 播放动画
    DrawAnimatedRects(IDANI_CAPTION, &WndRect, &m_MaxBeforeRect);

this->MoveWindow(&m_MaxBeforeRect);

问题6:自定义系统菜单

系统默认的系统菜单(鼠标右击任务栏按钮的菜单),不能修改,那我们自己做一个,查了很多消息,终于找到啦,消息 0x0313 就是鼠标右击任务栏按钮弹出菜单的消息,代码如下:

定义消息:

#define WM_POPUPSYSTEMMENU    0x0313

截获消息:

ON_MESSAGE(WM_POPUPSYSTEMMENU, OnPopupSystemMenu)

处理消息:

afx_msg LRESULT OnPopupSystemMenu(WPARAM wParam, LPARAM lParam);

LRESULT CSkinTestDlg::OnPopupSystemMenu(WPARAM wParam, LPARAM lParam)
{
 CMenu PopMenu;
 CPoint point;
 GetCursorPos(&point);

PopMenu.CreatePopupMenu();

PopMenu.AppendMenu(MF_STRING, 111111, _T("关于界面测试"));
 PopMenu.AppendMenu(MF_SEPARATOR);
 PopMenu.AppendMenu(MF_STRING, IDCANCEL, _T("退出\tAlt+F4"));

PopMenu.TrackPopupMenu(TPM_RIGHTBUTTON, point.x, point.y, this);

PopMenu.DestroyMenu();

return 0L;
}
这样,想怎么处理就怎么处理。

最后,我们贴上皮肤,基本的DirecrUi的平台就构建好了,效果如下:

http://blog.csdn.net/qing666888/article/details/49734897

搭建DirectUi开发平台的更多相关文章

  1. 搭建J2EE开发平台-Eclipse+MySql+tomcat

    搭建J2EE开发平台-Eclipse+MySql+tomcat 分类: ·Java 2010-10-10 15:45 2596人阅读 评论(3) 收藏 举报 mysql平台eclipsetomcatj ...

  2. 在Windows下用Eclipse+CDT+MinGW搭建C++开发平台

    本文提供了在Windows下用Eclipse+CDT+MinGW搭建C / C++开发平台的方法, 测试平台为Windows XP Sp2 CHS.   以下软件均为Windows平台下的版本. 1. ...

  3. Windows搭建golang开发平台

    Golang是谷歌开发的一款开源性语言,暂时比较方便的IDE有Inteillj Idea.LiteIDE.Eclipse(Golipse)等,使用起来比较方便的IDE:LiteIDE和Inteillj ...

  4. Ubuntu下qemu环境搭建vexpress开发平台

    在查找资料过程中,发现自己搭建虚拟的arm环境的话,有一个比较好的软件就是qemu了,当然还有其他的,大家各投所好就好. 接下来说一下qemu环境搭建过程. 其实搭建很简单,作为小白,我还是捣鼓了两三 ...

  5. 搭建python开发平台

    转:http://www.cnblogs.com/xuqiang/archive/2011/04/18/2019484.html <1>. 建立Python的开发环境; 这里使用的Pyth ...

  6. 简单的搭建php开发平台 WAMP

    下载wamp,地址http://www.wampserver.com/en/#download-wrapper 和正常软件安装下就行了. 修改WAMP中mysql默认空密码 WAMP安装好后,mysq ...

  7. 搭建基于 STM32 和 rt-thread 的开发平台

    我们需要平台 如果说,SharePoint 的价值之一在于提供了几乎开箱即用的 innovation 环境,那么,智能设备的开发平台也一样.不必每次都从头开始,所以需要固定的工作室和开发平台作为创新的 ...

  8. Ubuntu 14.04下搭建Python3.4 + PyQt5.3.2 + Eric6.0开发平台

    引言 找了很多Python GUI工具集,还是觉得PyQt比较理想,功能强大跨平台,还支持界面设计器.花一天时间折腾了Ubuntu14.04(32位)+ Python3.4 + Qt5.3.2 + P ...

  9. 开发指南专题4:JEECG高速微云开发平台--JEECG开发环境的搭建

    开发指南专题4:JEECG微云高速开发平台开发环境搭建 1. JEECG开发环境搭建 JEECG推荐的开发环境为Myeclipse8.5/Eclipse3.7+JDK1.6+Tomcat6.0 1.1 ...

随机推荐

  1. 高性能爬虫为什么使用定制DNS客户端?

    DNS 解析是高性能网络爬虫的瓶颈,主要是因为: 1. 由于域名服务的分布式的特性,DNS解析可能需要多次的请求转发,有时需要几秒甚至更长的时间来解析出相应的IP 地址. 2. 现有的标准库对DNS解 ...

  2. ado.net 学习小结

    连接数据源 Connection对象.Connection对象处于最顶层,是所有数据访问请求的关口.我们通过其暴露的属性进行配置.下面是一段连接字符串的示例. if (string.IsNullOrE ...

  3. [Unity官方文档翻译]ScrollRect

    官方地址:http://docs.unity3d.com/Manual/script-ScrollRect.html 一边学习一边翻译不知效率如何= = Scroll Rect 在小区域里展示大量内容 ...

  4. ssh 无密码登录远程服务器

    在讲下文之前,我都默许大家都已经生成了自己的ssh公钥和密钥,在自己的~/.ssh 目录下面,如果没有,请使用 ssh-keygen -t rsa -C "你的邮箱" 命令生成 1 ...

  5. font awesome icon

    http://fontawesome.io/icons/ http://www.bootstrapicons.com/

  6. 如何下载到最新的版本的Oracle Database

    其实这不是一个很困难的事情,但是发现好多同学都不知道,其实只需直接访问Oracle的官网就可以找到,鉴于Oracle经常改到下载面也我这里直接粘贴下载地址 http://www.oracle.com/ ...

  7. POJ 2039 To and Fro(模拟)

    To and Fro Description Mo and Larry have devised a way of encrypting messages. They first decide sec ...

  8. php 解决大流量网站访问量问题

    当一个网站发展为知名网站的时候(如新浪,腾讯,网易,雅虎),网站的访问量通常都会非常大,如果使用虚拟主机的话,网站就会因为访问量过大而引起 服务器性能问题,这是很多人的烦恼,有人使用取消RSS等错误的 ...

  9. apache的ab进行页面的压力测试

    参考http://www.cnblogs.com/yjf512/archive/2011/05/24/2055723.html apache/bin/ab ./ab –n 1000 –c 100 ht ...

  10. UI图标不用愁:矢量字体图标Font-Awesome

    Font-Awesome,这个项目主要是css3的一个应用,准确的说是一段css,这里的把很多图标的东西做到了font文件里面,然后通过引用外部font文件的方式,来展现图标. Font Awesom ...