搭建DirectUi开发平台
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开发平台的更多相关文章
- 搭建J2EE开发平台-Eclipse+MySql+tomcat
搭建J2EE开发平台-Eclipse+MySql+tomcat 分类: ·Java 2010-10-10 15:45 2596人阅读 评论(3) 收藏 举报 mysql平台eclipsetomcatj ...
- 在Windows下用Eclipse+CDT+MinGW搭建C++开发平台
本文提供了在Windows下用Eclipse+CDT+MinGW搭建C / C++开发平台的方法, 测试平台为Windows XP Sp2 CHS. 以下软件均为Windows平台下的版本. 1. ...
- Windows搭建golang开发平台
Golang是谷歌开发的一款开源性语言,暂时比较方便的IDE有Inteillj Idea.LiteIDE.Eclipse(Golipse)等,使用起来比较方便的IDE:LiteIDE和Inteillj ...
- Ubuntu下qemu环境搭建vexpress开发平台
在查找资料过程中,发现自己搭建虚拟的arm环境的话,有一个比较好的软件就是qemu了,当然还有其他的,大家各投所好就好. 接下来说一下qemu环境搭建过程. 其实搭建很简单,作为小白,我还是捣鼓了两三 ...
- 搭建python开发平台
转:http://www.cnblogs.com/xuqiang/archive/2011/04/18/2019484.html <1>. 建立Python的开发环境; 这里使用的Pyth ...
- 简单的搭建php开发平台 WAMP
下载wamp,地址http://www.wampserver.com/en/#download-wrapper 和正常软件安装下就行了. 修改WAMP中mysql默认空密码 WAMP安装好后,mysq ...
- 搭建基于 STM32 和 rt-thread 的开发平台
我们需要平台 如果说,SharePoint 的价值之一在于提供了几乎开箱即用的 innovation 环境,那么,智能设备的开发平台也一样.不必每次都从头开始,所以需要固定的工作室和开发平台作为创新的 ...
- Ubuntu 14.04下搭建Python3.4 + PyQt5.3.2 + Eric6.0开发平台
引言 找了很多Python GUI工具集,还是觉得PyQt比较理想,功能强大跨平台,还支持界面设计器.花一天时间折腾了Ubuntu14.04(32位)+ Python3.4 + Qt5.3.2 + P ...
- 开发指南专题4:JEECG高速微云开发平台--JEECG开发环境的搭建
开发指南专题4:JEECG微云高速开发平台开发环境搭建 1. JEECG开发环境搭建 JEECG推荐的开发环境为Myeclipse8.5/Eclipse3.7+JDK1.6+Tomcat6.0 1.1 ...
随机推荐
- python学习笔记--Django入门四 管理站点
上一节 Django入门三 Django 与数据库的交互:数据建模 "管理员界面"是基础功能中的重要部分. django.contrib 包 Django自动管理工具是djang ...
- python sklearn.linear_model.LinearRegression.score
score(self, X, y, sample_weight=None) 作用:返回该次预测的系数R2 其中R2 =(1-u/v).u=((y_true - y_pred) ** 2).su ...
- ASP.NET MVC 第七回 UrlHelper
这节讲 一下ASP.NET MVC中的Helper. 何谓Helper,其实就是在View中为了实现一些灵活功能而写的方法组. 其实ASP.NET MVC的View是Aspx的页面,本身可以声明定义方 ...
- HTML+CSS基础学习笔记(1)
一.了解HTML.CSS.JS 1.HTML是网页内容的载体. 内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字.图片.视频等. 2.CSS样式是表现. 用来改变内容外观的东西称之为表现 ...
- java命名规则
java变量命名是不能以#开头的.Java变量的命名规则如下:$ .字母.下划线开头都行,不能以数字开头 后面的可以是数字.字母.下划线, 其他的命名方式,都会报错,且不能运行. 以字母.下划线( _ ...
- Mysql INNER,LEFT ,RIGHT join的使用
JOIN 按照功能大致分为如下三类: INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录. LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录. RIG ...
- [上传下载] C#修改DownLoadHelper上传下载帮助类 (转载)
点击下载 DownLoadHelper.rar 主要功能如下 /// <summary> /// 输出硬盘文件,提供下载 支持大文件.续传.速度限制.资源占用小 /// </summ ...
- javascript 动态操作Html
<html> <body> <p>aaaaa</p> <input type="button" value="con ...
- fmt:formatDate标签的输出格式
http://blog.csdn.net/lidawei201/article/details/7197834
- 冒泡排序--c#
//冒泡排序 Console.WriteLine("请输入一个程序的数值"); int[] array = { 111, 2, 5, 32, 321 }; int temp = 0 ...