Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14523420
  • 博文数量: 5645
  • 博客积分: 9880
  • 博客等级: 中将
  • 技术积分: 68081
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-28 13:35
文章分类

全部博文(5645)

文章存档

2008年(5645)

我的朋友

分类:

2008-04-28 21:03:27

下载本文示例代码
  摘要:  某天在论坛上看到有人发帖询问QQ自动伸缩窗口是怎么实现的,我也好想知道,于是到百度一搜索,结果不多,来来去去都是那几篇,下载那些demo运行一下,发觉效果与QQ相差很大,于是决定自己动手做个,要求要近乎完美地模仿这个功能。由于是些效果的东西,贴图也看不出来,所以文章里就不截图了,想看效果的就直接运行源代码的demo吧。   一、观察  模仿前最重要的一步就是观察,经过半天对QQ的摆弄和摸索,总结出了以下一些特点:  1、窗口开始粘附时,检测的是鼠标坐标与桌面边界的距离,特别地,粘附在下面的时候,检测的是与任务栏的距离;  2、在向上移动窗口时,窗口边界永远不会超出桌面上面边界;  3、窗口是个 TopMost 风格;  4、当窗口粘附在上面、左边或右边并显示时,你把鼠标移动到最顶端,光标变成改变窗口大小的图标,而单单是把窗口的top坐标设置为0是不行的;  5、粘附在下面的时候,当处于移动状态,那么窗口的底边是与任务栏顶边对齐的,但从隐藏到显示的时候,窗口的底端是与屏幕底边对齐的;  6、隐藏后显露出来的那条线可能是一个Border,但肯定的是绝不包含Client区域;  7、关于响应鼠标的进入与移出窗口,绝对不是WM_MOUSEMOVE、WM_MOUSELEAVE。证明:你以及其慢的速度接触隐藏状态的QQ边界,你会发现几乎是“一触即发”,你又以及其慢的速度移出显示状态的QQ,你会发现它的收缩反而不是“一触即发”的,而是离边缘10象素左右。而WM_MOUSEMOVE,WM_MOUSELEAVE,只有在进入、移出Client区域才响应,明显和QQ不同,其实从第6点也可以知道;  8、粘附在两边的时候,高度会调整为桌面上边界到任务栏下边界的距离;  9、在“拖动时显示窗口内容”模式下(桌面属性-外观-效果),粘附在两边的拖动出来时;如果收缩之前高度比收缩后小则回复原来高度,在非“拖动时显示窗口内容”模式下,光栅会回复原来高度,但释放左键时,高度却是收缩时调整后的高度,一开始我以为这是个BUG,但我编写时同样出现这个问题,发现这两种模式会影响WM_MOVING参数的意义;  10、粘附在两边的时候当你设置任务栏自动隐藏,QQ窗口会自动调整高度充满屏幕高度;  11、窗口显示或隐藏不是一瞬间的,这点在第9点提到的两种模式下,会有所不同;  12、任务栏并不显示QQ窗口;  二、编写代码   观察完毕,就开始编写了。  首先新建一个基于对话框的MFC程序,命名为QQHideWnd,在对话框属性的styles页把border改为Resizing,你也可同时把Entended styles 的 tool window 钩上,对于这点我在程序了动态修改了。在QQHideWndDlg.h头文件添加以下成员函数: protected://修正移动时窗口的大小void FixMoving(UINT fwSide, LPRECT pRect);//从收缩状态显示窗口void DoShow();//从显示状态收缩窗口void DoHide();//重载函数,只是为了方便调用,实际调用CWnd的SetWindowPos(…)BOOL SetWindowPos(const CWnd* pWndInsertAfter,LPCRECT pCRect, UINT nFlags = SWP_SHOWWINDOW);  继续添加成员变量: private::BOOL m_isSizeChanged;//窗口大小是否改变了BOOL m_isSetTimer;//是否设置了检测鼠标的TimerINTm_oldWndHeight;//旧的窗口宽度INTm_taskBarHeight;//任务栏高度INTm_edgeHeight;//边缘高度INTm_edgeWidth;//边缘宽度INTm_hideMode;//隐藏模式BOOL m_hsFinished;//隐藏或显示过程是否完成BOOL m_hiding;//该参数只有在!m_hsFinished才有效//真:正在隐藏,假:正在显示  增加消息响应,需要注意的是有些消息你只有把右下角的 Filter for message设置为window才能看到。 WM_ NCHITTESTWM_MOVINGWM_CREATEWM_TIMER  然后来到对应的cpp文件,在头部定义一些宏: //收缩模式#define HM_NONE0//不收缩#define HM_TOP1//向上收缩#define HM_BOTTOM2//向下收缩#define HM_LEFT3//向左收缩#define HM_RIGHT4//向右收缩#define CM_ELAPSE200 //检测鼠标是否离开窗口的时间间隔#define HS_ELAPSE5//伸缩过程每步的时间间隔#define HS_STEPS10//伸缩过程分成多少步完成#define INTERVAL20//触发粘附时鼠标与屏幕边界的最小间隔,单位为象素#define INFALTE10//触发收缩时鼠标与窗口边界的最小间隔,单位为象素  然后在构造函数初始化成员变量: m_isSizeChanged = FALSE;m_isSetTimer = FALSE;m_hsFinished = TRUE;m_hiding = FALSE;m_oldWndHeight = MINCY;m_taskBarHeight = 30;m_edgeHeight = 0;m_edgeWidth=0;m_hideMode = HM_NONE;  完成了一些初始的工作,那么就开始进入关键的函数实现了。首先是在OnCreate做些窗口的初始化和获得一些系统信息。  【代码一】 int CQQHideWndDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) {if (CDialog::OnCreate(lpCreateStruct) == -1)return -1; // TODO: Add your specialized creation code here //获得任务栏高度CWnd* p;p = this->FindWindow("Shell_TrayWnd",NULL);if(p != NULL){CRect tRect;p->GetWindowRect(tRect);m_taskBarHeight = tRect.Height();} //修改风格使得他不在任务栏显示ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);//去掉关闭按键(如果想画3个按键的话)//ModifyStyle(WS_SYSMENU,NULL); //获得边缘高度和宽度m_edgeHeight = GetSystemMetrics(SM_CYEDGE);m_edgeWidth = GetSystemMetrics(SM_CXFRAME); return 0;}  接着如何知道鼠标进入或移出窗口呢?在前面我已经证明了WM_MOUSEMOVE和WM_MOUSELEAVE不符合我们的要求,于是我用了WM_ NCHITTEST这个消息,你可以看到我在这个消息响应函数中用了两个SetTimer,一个用于检测鼠标是否离开,一个用于伸缩过程,不管你喜欢不喜欢,要达到第7点和第11点,这个是必须的,考虑的效率问题,在不需要的时候关闭这些Timer就好了。  【代码二】 UINT CQQHideWndDlg::OnNcHitTest(CPoint point) {// TODO: Add your message handler code here and/or call defaultCString str;str.Format("Mouse (%d,%d)",point.x,point.y);GetDlgItem(IDC_CURSOR)->SetWindowText(str);if(m_hideMode != HM_NONE && !m_isSetTimer &&//防止鼠标超出屏幕右边时向右边收缩造成闪烁point.x < GetSystemMetrics(SM_CXSCREEN) INFALTE){ //鼠标进入时,如果是从收缩状态到显示状态则开启TimerSetTimer(1,CM_ELAPSE,NULL);m_isSetTimer = TRUE; m_hsFinished = FALSE;m_hiding = FALSE;SetTimer(2,HS_ELAPSE,NULL); //开启显示过程}return CDialog::OnNcHitTest(point);}  然后在OnTimer中  【代码三】 void CQQHideWndDlg::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call defaultif(nIDEvent == 1 ){POINT curPos;GetCursorPos(&curPos); CString str;str.Format("Timer On(%d,%d)",curPos.x,curPos.y);GetDlgItem(IDC_TIMER)->SetWindowText(str); CRect tRect;//获取此时窗口大小GetWindowRect(tRect);//膨胀tRect,以达到鼠标离开窗口边沿一定距离才触发事件tRect.InflateRect(INFALTE,INFALTE); if(!tRect.PtInRect(curPos)) //如果鼠标离开了这个区域{KillTimer(1); //关闭检测鼠标Timerm_isSetTimer = FALSE;GetDlgItem(IDC_TIMER)->SetWindowText("Timer Off"); m_hsFinished = FALSE; m_hiding = TRUE;SetTimer(2,HS_ELAPSE,NULL); //开启收缩过程}} if(nIDEvent == 2){if(m_hsFinished) //如果收缩或显示过程完毕则关闭Timer KillTimer(2);elsem_hiding ? DoHide() : DoShow();}CDialog::OnTimer(nIDEvent);}  暂时不管OnTimer中的DoHide(); DoShow();共2页。 1 2 :   摘要:  某天在论坛上看到有人发帖询问QQ自动伸缩窗口是怎么实现的,我也好想知道,于是到百度一搜索,结果不多,来来去去都是那几篇,下载那些demo运行一下,发觉效果与QQ相差很大,于是决定自己动手做个,要求要近乎完美地模仿这个功能。由于是些效果的东西,贴图也看不出来,所以文章里就不截图了,想看效果的就直接运行源代码的demo吧。   一、观察  模仿前最重要的一步就是观察,经过半天对QQ的摆弄和摸索,总结出了以下一些特点:  1、窗口开始粘附时,检测的是鼠标坐标与桌面边界的距离,特别地,粘附在下面的时候,检测的是与任务栏的距离;  2、在向上移动窗口时,窗口边界永远不会超出桌面上面边界;  3、窗口是个 TopMost 风格;  4、当窗口粘附在上面、左边或右边并显示时,你把鼠标移动到最顶端,光标变成改变窗口大小的图标,而单单是把窗口的top坐标设置为0是不行的;  5、粘附在下面的时候,当处于移动状态,那么窗口的底边是与任务栏顶边对齐的,但从隐藏到显示的时候,窗口的底端是与屏幕底边对齐的;  6、隐藏后显露出来的那条线可能是一个Border,但肯定的是绝不包含Client区域;  7、关于响应鼠标的进入与移出窗口,绝对不是WM_MOUSEMOVE、WM_MOUSELEAVE。证明:你以及其慢的速度接触隐藏状态的QQ边界,你会发现几乎是“一触即发”,你又以及其慢的速度移出显示状态的QQ,你会发现它的收缩反而不是“一触即发”的,而是离边缘10象素左右。而WM_MOUSEMOVE,WM_MOUSELEAVE,只有在进入、移出Client区域才响应,明显和QQ不同,其实从第6点也可以知道;  8、粘附在两边的时候,高度会调整为桌面上边界到任务栏下边界的距离;  9、在“拖动时显示窗口内容”模式下(桌面属性-外观-效果),粘附在两边的拖动出来时;如果收缩之前高度比收缩后小则回复原来高度,在非“拖动时显示窗口内容”模式下,光栅会回复原来高度,但释放左键时,高度却是收缩时调整后的高度,一开始我以为这是个BUG,但我编写时同样出现这个问题,发现这两种模式会影响WM_MOVING参数的意义;  10、粘附在两边的时候当你设置任务栏自动隐藏,QQ窗口会自动调整高度充满屏幕高度;  11、窗口显示或隐藏不是一瞬间的,这点在第9点提到的两种模式下,会有所不同;  12、任务栏并不显示QQ窗口;  二、编写代码   观察完毕,就开始编写了。  首先新建一个基于对话框的MFC程序,命名为QQHideWnd,在对话框属性的styles页把border改为Resizing,你也可同时把Entended styles 的 tool window 钩上,对于这点我在程序了动态修改了。在QQHideWndDlg.h头文件添加以下成员函数: protected://修正移动时窗口的大小void FixMoving(UINT fwSide, LPRECT pRect);//从收缩状态显示窗口void DoShow();//从显示状态收缩窗口void DoHide();//重载函数,只是为了方便调用,实际调用CWnd的SetWindowPos(…)BOOL SetWindowPos(const CWnd* pWndInsertAfter,LPCRECT pCRect, UINT nFlags = SWP_SHOWWINDOW);  继续添加成员变量: private::BOOL m_isSizeChanged;//窗口大小是否改变了BOOL m_isSetTimer;//是否设置了检测鼠标的TimerINTm_oldWndHeight;//旧的窗口宽度INTm_taskBarHeight;//任务栏高度INTm_edgeHeight;//边缘高度INTm_edgeWidth;//边缘宽度INTm_hideMode;//隐藏模式BOOL m_hsFinished;//隐藏或显示过程是否完成BOOL m_hiding;//该参数只有在!m_hsFinished才有效//真:正在隐藏,假:正在显示  增加消息响应,需要注意的是有些消息你只有把右下角的 Filter for message设置为window才能看到。 WM_ NCHITTESTWM_MOVINGWM_CREATEWM_TIMER  然后来到对应的cpp文件,在头部定义一些宏: //收缩模式#define HM_NONE0//不收缩#define HM_TOP1//向上收缩#define HM_BOTTOM2//向下收缩#define HM_LEFT3//向左收缩#define HM_RIGHT4//向右收缩#define CM_ELAPSE200 //检测鼠标是否离开窗口的时间间隔#define HS_ELAPSE5//伸缩过程每步的时间间隔#define HS_STEPS10//伸缩过程分成多少步完成#define INTERVAL20//触发粘附时鼠标与屏幕边界的最小间隔,单位为象素#define INFALTE10//触发收缩时鼠标与窗口边界的最小间隔,单位为象素  然后在构造函数初始化成员变量: m_isSizeChanged = FALSE;m_isSetTimer = FALSE;m_hsFinished = TRUE;m_hiding = FALSE;m_oldWndHeight = MINCY;m_taskBarHeight = 30;m_edgeHeight = 0;m_edgeWidth=0;m_hideMode = HM_NONE;  完成了一些初始的工作,那么就开始进入关键的函数实现了。首先是在OnCreate做些窗口的初始化和获得一些系统信息。  【代码一】 int CQQHideWndDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) {if (CDialog::OnCreate(lpCreateStruct) == -1)return -1; // TODO: Add your specialized creation code here //获得任务栏高度CWnd* p;p = this->FindWindow("Shell_TrayWnd",NULL);if(p != NULL){CRect tRect;p->GetWindowRect(tRect);m_taskBarHeight = tRect.Height();} //修改风格使得他不在任务栏显示ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);//去掉关闭按键(如果想画3个按键的话)//ModifyStyle(WS_SYSMENU,NULL); //获得边缘高度和宽度m_edgeHeight = GetSystemMetrics(SM_CYEDGE);m_edgeWidth = GetSystemMetrics(SM_CXFRAME); return 0;}  接着如何知道鼠标进入或移出窗口呢?在前面我已经证明了WM_MOUSEMOVE和WM_MOUSELEAVE不符合我们的要求,于是我用了WM_ NCHITTEST这个消息,你可以看到我在这个消息响应函数中用了两个SetTimer,一个用于检测鼠标是否离开,一个用于伸缩过程,不管你喜欢不喜欢,要达到第7点和第11点,这个是必须的,考虑的效率问题,在不需要的时候关闭这些Timer就好了。  【代码二】 UINT CQQHideWndDlg::OnNcHitTest(CPoint point) {// TODO: Add your message handler code here and/or call defaultCString str;str.Format("Mouse (%d,%d)",point.x,point.y);GetDlgItem(IDC_CURSOR)->SetWindowText(str);if(m_hideMode != HM_NONE && !m_isSetTimer &&//防止鼠标超出屏幕右边时向右边收缩造成闪烁point.x < GetSystemMetrics(SM_CXSCREEN) INFALTE){ //鼠标进入时,如果是从收缩状态到显示状态则开启TimerSetTimer(1,CM_ELAPSE,NULL);m_isSetTimer = TRUE; m_hsFinished = FALSE;m_hiding = FALSE;SetTimer(2,HS_ELAPSE,NULL); //开启显示过程}return CDialog::OnNcHitTest(point);}  然后在OnTimer中  【代码三】 void CQQHideWndDlg::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call defaultif(nIDEvent == 1 ){POINT curPos;GetCursorPos(&curPos); CString str;str.Format("Timer On(%d,%d)",curPos.x,curPos.y);GetDlgItem(IDC_TIMER)->SetWindowText(str); CRect tRect;//获取此时窗口大小GetWindowRect(tRect);//膨胀tRect,以达到鼠标离开窗口边沿一定距离才触发事件tRect.InflateRect(INFALTE,INFALTE); if(!tRect.PtInRect(curPos)) //如果鼠标离开了这个区域{KillTimer(1); //关闭检测鼠标Timerm_isSetTimer = FALSE;GetDlgItem(IDC_TIMER)->SetWindowText("Timer Off"); m_hsFinished = FALSE; m_hiding = TRUE;SetTimer(2,HS_ELAPSE,NULL); //开启收缩过程}} if(nIDEvent == 2){if(m_hsFinished) //如果收缩或显示过程完毕则关闭Timer KillTimer(2);elsem_hiding ? DoHide() : DoShow();}CDialog::OnTimer(nIDEvent);}  暂时不管OnTimer中的DoHide(); DoShow();共2页。 1 2 : 下载本文示例代码


Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口Visual C 设计超强仿QQ自动伸缩窗口
阅读(123) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~