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. c语言输入输出

    一 #include "stdio.h"int main(){ FILE *fp; int ninzu=0; char name[100]; double hsum=0.0; do ...

  2. 关于js中return false、event.preventDefault()和event.stopPropagation()

    在平时项目中,如果遇到需要阻止浏览器默认行为,大家经常会用return false;和event.preventDefault()来阻止,但对它俩的区别还是有些一知半解,于是看了文档,查了些资料,在此 ...

  3. JavaScript判断数据类型总结

    最近做项目中遇到了一些关于javascript数据类型的判断处理,上网找了一下资料,并且亲自验证了各种数据类型的判断网页特效,在此做一个总结吧! 一.JS中的数据类型  1.数值型(Number):包 ...

  4. 3G/4G网卡使用

    整体架构: pppd call option & ----------↓---------- option脚本(设置PPP连接) ----------↓---------- chat脚本(进行 ...

  5. “System.Transactions.Diagnostics.DiagnosticTrace”的类型初始值设定项引发异常。

    今天在项目中用log4net,App.config文件中增加了configSections节点,程序运行报错“System.Transactions.Diagnostics.DiagnosticTra ...

  6. Asp.net Mvc对比Php的4大误解

    一:asp.net技术已过时,Php技术更新 Asp.net mvc 5 发布于2014 夏天. 二:php开发者更多,所以更能得到帮助 2者对比犹如下图,会拿电锯的肯定多少会点锯子, 会用锯子的不一 ...

  7. 一个操作Sql2005数据库的类(备份,还原,分离,附加,添加删除用户等操作)(转载)

    /* * 更新时间 :2011-09-01 16:06 * 更 新 人 :苏飞 */ using System; using System.Collections.Generic; using Sys ...

  8. Windows 7 + Visual Studio 2012 + cocos2d-x 2.1.5

    下载cocos2d-x google code : http://code.google.com/p/cocos2d-x/downloads/list cocos2d 官网: http://cocos ...

  9. 'EntityValidationErrors' property for more details

    很多小猿遇到这个Exception 的时候,都会有点无厘头.这个时候最好try-- catch下,找到出错的地方.本人习惯在页面上加个lable标签,把exc msg(exception messag ...

  10. SQL生成一柱双色球

    数据库环境:SQL SERVER 2005 以前用C/JAVA穷举双色球的所有排列,今天想着换成用SQL实现,只生成一柱双色球. 简单说下双色球的规则,双色球由红色球和蓝色球组成,每注投注号码由6个红 ...