类似QQ界面的实现
流浪狗
一、需求分析:
QQ是现在非常流行的一种及时通讯工具,它以强大的功能和漂亮、友好的界面获得了无数人的喜爱。本程序的目的是为了做出像QQ主界面的程序。
二、功能:
(1)、实现OUTLOOK风格的QQ主界面。
(2)、实现自动隐藏功能。
(3)、实现系统托盘,并动态的更换图标,就像QQ上线时托盘所表现的动态画面。
三、说明:
本程序复用了一些别人写的类,并在此基础上作出了部分修改,以实现本程序的功能,在此向CgfxOutBarCtrl类和CtrayIcon的作者表示感谢。
四、具体实现
(一)、创建一个单文档的应用程序,命命为MyQQ,接下来都选默认选项。
(1)编辑CMainFrame::PreCreateWindow。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
……
//设置窗口高度和宽度
cs.cx=150;
cs.cy=600;
//去出菜单
cs.hMenu=NULL;
//限定不能改变大小,去出最大化按钮
cs.style&=~(WS_THICKFRAME|WS_MAXIMIZEBOX);
}
(2)、编辑CMyQQApp::InitInstance在后面添加:
//设置窗口文字 和窗口位置
AfxGetMainWnd()->SetWindowText("MyQQ");
AfxGetMainWnd()->SetWindowPos(&CWnd::wndTopMost,400,0,150,600,
SWP_SHOWWINDOW);
(2)、准备一张图片 ,用做工具栏图标,删除原来的IDR_MAINFRAME图标,将新加的更名为IDR_MAINFRAME。
(二)、实现QQ界面功能
(1)、准备。准备CgfxOutBarCtrl类(你可以在网上找到)和两张图片,用作大图标和小图标,命名为IDB_IMAGELIST和IDB_SMALL_IMAGELIST。在QQ2005中将NEWFACE文件夹拷贝到当前工程目录下,准备一个声音文件folder.wav。
(2)、将CgfxOutBarCtrl和它要用到的一些类CgfxGroupEdit和CgfxPopupMenu一起导入工程。
(3)、在MainFrm.h中添加包含#include "GfxOutBarCtrl.h",并添加属性CgfxOutBarCtrl wndBar和 CimageList imaLarge, imaSmall
(4)、重载CmainFrame的OnCreateClient函数
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
DWORD dwf = CGfxOutBarCtrl::fDragItems|
CGfxOutBarCtrl::fEditGroups|
CGfxOutBarCtrl::fEditItems|
CGfxOutBarCtrl::fRemoveGroups|
CGfxOutBarCtrl::fRemoveItems|
CGfxOutBarCtrl::fAddGroups|
CGfxOutBarCtrl::fAnimation;
RECT rect;
GetClientRect(&rect);
wndBar.Create(WS_CHILD|WS_VISIBLE,rect,this,NULL,dwf);
wndBar.SetOwner(this);
//此处必须以真彩色显示
imaLarge.Create(40,40,ILC_COLOR24,0,0);
imaSmall.Create(16,16,ILC_COLOR24,0,0);
//此处由于将QQ里的一百张图片全部加载进内存,所以要耗费很多内存,可以在寻求一个更好的办法
for(int i=1;i<=100;i++)
{
CBitmap pBitmap;
CString str;
str.Format("NEWFACE//%d.bmp",i);
//加载位图
HBITMAP hBitmap; //定义位图对象句柄
hBitmap=(HBITMAP):: LoadImage
( AfxGetInstanceHandle(),
//取得应用程序句柄
str,
//位图文件名
IMAGE_BITMAP,
//类型为Windows位图
0,0,
LR_LOADFROMFILE);
if(NULL==hBitmap)
{
AfxMessageBox("不能打开文件");
return FALSE;
}
pBitmap.Attach(hBitmap);
imaLarge.Add(&pBitmap,RGB(0,0,0));
CBitmap sBitmap;
str.Format("NEWFACE//%d_m.bmp",i);
//加载位图
hBitmap=(HBITMAP):: LoadImage
( AfxGetInstanceHandle(),
//取得应用程序句柄
str,
//位图文件名
IMAGE_BITMAP,
//类型为Windows位图
0,0,
LR_LOADFROMFILE);
if(NULL==hBitmap)
{
AfxMessageBox("不能打开文件");
return FALSE;
}
sBitmap.Attach(hBitmap);
imaSmall.Add(&sBitmap,RGB(0,0,0));
}
wndBar.SetImageList(&imaLarge, CGfxOutBarCtrl::fLargeIcon);
wndBar.SetImageList(&imaSmall, CGfxOutBarCtrl::fSmallIcon);
wndBar.SetAnimationTickCount(10);
wndBar.SetAnimSelHighlight(200);
wndBar.SetIfQueryRemove(true);
wndBar.AddFolder("我的好友", 0);
wndBar.AddFolder("陌生人", 1);
wndBar.AddFolder("黑名单", 2);
wndBar.InsertItem(0, 0, "午夜", 0, 0);
wndBar.InsertItem(0, 1, "浪子", 1, 0);
wndBar.InsertItem(0, 2, "未来之城", 2, 0);
wndBar.InsertItem(0, 3, "黑色幽默", 3, 0);
wndBar.InsertItem(0, 4, "想飞", 4, 0);
……//这儿省略一部分
wndBar.InsertItem(2, 0, "酒鬼", 80, 0);
wndBar.InsertItem(2, 1, "痴人", 81, 0);
wndBar.InsertItem(2, 2, "逐梦人", 82, 0);
wndBar.InsertItem(2, 3, "陆小凤", 83, 0);
wndBar.SetSelFolder(0);
return TRUE;
}
完成后我们可以编译改程序,但是当点击陌生人时,由于里面没有成员,本不应该出现下拉按钮,但是出现了,当我们点击时,就会发生溢出。所以修改原来的CgfxOutBarCtrl源文件的OnPaint函数:
if (l < GetItemCount() - 1
//Modified By jamiandy@163.com
//Author:流浪狗 Date:2005Y-05M-13D::12:13
//在此处修改原来的语句,以便使得当item为0时,不出现向下的按钮,防止溢出
//修改if (l < GetItemCount() - 1)为if (l < GetItemCount() - 1&&GetItemCount()!=0)
&&GetItemCount()!=0)
{
……//此处省略
}
else bDownArrow = false;
(5)、修改CgfxOutBarCtrl类的OnLButtonDown,在里面适当位置即响应点击FOLDER时的地方添加语句:
BOOL r = sndPlaySound("sound//folder.wav",SND_SYNC |SND_NODEFAULT);//播放WAV
ASSERT(r); r = sndPlaySound("",SND_ASYNC|SND_NODEFAULT);//停止播放
(6)、在CmainFrame的头文件中,DECLARE_MESSAGE_MAP()上面添加afx_msg long OnOutBarNotify(WPARAM wParam, LPARAM lParam);消息映射,在实现文件中,BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)和END_MESSAGE_MAP()之间加入ON_MESSAGE(WM_OUTBAR_NOTIFY, OnOutBarNotify)。编写代码:
long CMainFrame::OnOutBarNotify(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case NM_SENDMSG:
{
int index = (int) lParam;
//弹出发送消息对话框
DoMsgDialog();
}
return 1;
//你可以在此添加你自己的消息,从CGfxOutBarCtrl中发送
}
return 0;
}
修改CgfxOutBarCtrl中的代码,实现向主框架发送消息,可以用GetOwner()->SendMessage(WM_OUTBAR_NOTIFY, NM_SENDMSG, iHitInternal2)实现,具体情况可以根据需要改变。然后从主框架中处理消息,从而保证用主框架来响应外界的消息。
经过这些,基本的QQ界面实现了,现在编译运行,就可以看到漂亮的界面了。
(三)、实现QQ的自动隐藏。
原理:在检测到窗口靠近屏幕边缘时,移动窗口到屏幕外边,从而实现自动隐藏,当检测到鼠标移近时,将窗口显示出来,从而实现自动弹出,实现过程如下:
(1)、在MainFrm.cpp中头部加入:
int ScreenX; //屏幕宽度
int ScreenY; //屏幕高度
int alignType; //全局变量,用于记录窗体停靠状态
enum
{
ALIGN_NONE, //不停靠
ALIGN_TOP, //停靠上边
ALIGN_LEFT, //停靠左边
ALIGN_RIGHT //停靠右边
};
#define NEAR_SIZE 5 //定义自动停靠有效距离
#define NEAR_SIDE 3 //窗体隐藏后在屏幕上保留的像素,以使鼠标可以触及
在OnCreate中加入:
ScreenX = GetSystemMetrics(SM_CXSCREEN);
ScreenY = GetSystemMetrics(SM_CYSCREEN);
SetTimer(WM_TIMER,50,NULL);
NearSide(GetSafeHwnd());
(2)、添加NearSide函数
void CMainFrame::NearSide(HWND hWnd)
{
int change = 0;
RECT rect;
GetWindowRect(&rect);
alignType = ALIGN_NONE;
if (rect.left < NEAR_SIZE)
{
alignType = ALIGN_LEFT;
if ((rect.left != 0) && rect.right != NEAR_SIDE)
{
rect.right -= rect.left;
rect.left = 0;
change = 1;
}
}
else if (rect.right > ScreenX - NEAR_SIZE)
{
alignType = ALIGN_RIGHT;
if (rect.right != ScreenX && rect.left != ScreenX - NEAR_SIDE)
{
rect.left += (ScreenX - rect.right);
rect.right = ScreenX;
change = 1;
}
}
//调整上下
if (rect.top < NEAR_SIZE)
{
alignType = ALIGN_TOP;
if (rect.top != 0 && rect.bottom != NEAR_SIDE)
{
rect.bottom -= rect.top;
rect.top = 0;
change = 1;
}
}
if (change)
{
MoveWindow(rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, TRUE);
}
}
(3)、重载OnTimer,编辑
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
POINT pt;
RECT rc;
GetCursorPos(&pt);
GetWindowRect(&rc);
if (!PtInRect(&rc, pt)) //若鼠标不在窗体内,隐藏窗体.
{
KillTimer(WM_TIMER);
HideSide(GetSafeHwnd(),TRUE);
}
CFrameWnd::OnTimer(nIDEvent);
}
(4)、添加HideSide,编辑:
void CMainFrame::HideSide(HWND hWnd, BOOL hide)
{
RECT rc;
int moves = 4; //动画滚动窗体的步数,如果你觉得不够平滑,可以增大该值.
int xStep, yStep;
int xEnd, yEnd;
int width;
int height;
register int i;
GetWindowRect(&rc);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
//下边判断窗体该如何移动,由停靠方式决定
switch (alignType)
{
case ALIGN_TOP:
{
//向上移藏
xStep = 0;
xEnd = rc.left;
if (hide)
{
yStep = -rc.bottom / moves;
yEnd = -height + NEAR_SIDE;
}
else
{
yStep = -rc.top / moves;
yEnd = 0;
}
break;
}
case ALIGN_LEFT:
{
//向左移藏
//此处省略,类似向上隐藏
……
break;
}
case ALIGN_RIGHT:
{
//向右移藏
//此处省略,类似向上隐藏
……
break;
}
default:
return;
}
//动画滚动窗体.
for (i = 0; i < moves; i++)
{
rc.left += xStep;
rc.top += yStep;
SetWindowPos(NULL, rc.left, rc.top, 0, 0,
SWP_NOSIZE | SWP_NOSENDCHANGING);
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
Sleep(5);
}
SetWindowPos(NULL, xEnd, yEnd, 0, 0, SWP_NOSIZE);
if (!hide) //如果窗体已被显示,设置定时器.监视鼠标.
{
SetTimer(WM_TIMER, 50, NULL);
}
}
(5)、最后重载OnNcMouseMove,添加代码如下:
void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point)
{
RECT rc;
GetWindowRect(&rc);
if (rc.left < 0 || rc.top < 0 || rc.right > ScreenX) //未显示
{
HideSide(GetSafeHwnd(), FALSE);
}else
{
HideSide(GetSafeHwnd(), FALSE);
SetTimer(WM_TIMER,50,NULL);
}
CFrameWnd::OnNcMouseMove(nHitTest, point);
}
这样,自动隐藏的功能就实现了,当你把它拖到屏幕边上的时候,就自动消失了,当鼠标移近时,又自动出现。
(四)、托盘程序的实现
(1)、将CtrayIcon(你可以从网上找到它)加入工程。添加两个图标,分别命名为IDI_ONLINE和IDI_OFFLINE,表示交替的两个图标。在MainFrm.h中加入私有变量CTrayIcon m_trayIcon; BOOL IsOnline;在构造函数中对其初始化,m_trayIcon(IDR_TRAYICON),IsOnline=FALSE。在MainFrm.cpp中添加#define WM_MY_TRAY_NOTIFICATION WM_USER+0
(2)、在OnCreate中添加:
m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION);
m_trayIcon.SetIcon(IDI_ONLINE);
SetTimer(2,500,NULL);
(3)、修改OnTimer:
if(nIDEvent==2)
{
IsOnline=!IsOnline;
m_trayIcon.SetIco(IsOnlineIDI_ONLINE:IDI_OFFLINE);
}
这样就可以动态改变图标了。
到此为止,我们要求的所有功能都实现了,现在可以编译运行,修改不正确的地方。效果如图所示:
cs.style&=~(WS_THICKFRAME|WS_MAXIMIZEBOX);
}
(2)、编辑CMyQQApp::InitInstance在后面添加:
//设置窗口文字 和窗口位置
AfxGetMainWnd()->SetWindowText("MyQQ");
AfxGetMainWnd()->SetWindowPos(&CWnd::wndTopMost,400,0,150,600,
SWP_SHOWWINDOW);
(2)、准备一张图片 ,用做工具栏图标,删除原来的IDR_MAINFRAME图标,将新加的更名为IDR_MAINFRAME。
(二)、实现QQ界面功能
(1)、准备。准备CgfxOutBarCtrl类(你可以在网上找到)和两张图片,用作大图标和小图标,命名为IDB_IMAGELIST和IDB_SMALL_IMAGELIST。在QQ2005中将NEWFACE文件夹拷贝到当前工程目录下,准备一个声音文件folder.wav。
(2)、将CgfxOutBarCtrl和它要用到的一些类CgfxGroupEdit和CgfxPopupMenu一起导入工程。
(3)、在MainFrm.h中添加包含#include "GfxOutBarCtrl.h",并添加属性CgfxOutBarCtrl wndBar和 CimageList imaLarge, imaSmall
(4)、重载CmainFrame的OnCreateClient函数
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
DWORD dwf = CGfxOutBarCtrl::fDragItems|
CGfxOutBarCtrl::fEditGroups|
CGfxOutBarCtrl::fEditItems|
CGfxOutBarCtrl::fRemoveGroups|
CGfxOutBarCtrl::fRemoveItems|
CGfxOutBarCtrl::fAddGroups|
CGfxOutBarCtrl::fAnimation;
RECT rect;
GetClientRect(&rect);
wndBar.Create(WS_CHILD|WS_VISIBLE,rect,this,NULL,dwf);
wndBar.SetOwner(this);
//此处必须以真彩色显示
imaLarge.Create(40,40,ILC_COLOR24,0,0);
imaSmall.Create(16,16,ILC_COLOR24,0,0);
//此处由于将QQ里的一百张图片全部加载进内存,所以要耗费很多内存,可以在寻求一个更好的办法
for(int i=1;i<=100;i++)
{
CBitmap pBitmap;
CString str;
str.Format("NEWFACE//%d.bmp",i);
//加载位图
HBITMAP hBitmap; //定义位图对象句柄
hBitmap=(HBITMAP):: LoadImage
( AfxGetInstanceHandle(),
//取得应用程序句柄
str,
//位图文件名
IMAGE_BITMAP,
//类型为Windows位图
0,0,
LR_LOADFROMFILE);
if(NULL==hBitmap)
{
AfxMessageBox("不能打开文件");
return FALSE;
}
pBitmap.Attach(hBitmap);
imaLarge.Add(&pBitmap,RGB(0,0,0));
CBitmap sBitmap;
str.Format("NEWFACE//%d_m.bmp",i);
//加载位图
hBitmap=(HBITMAP):: LoadImage
( AfxGetInstanceHandle(),
//取得应用程序句柄
str,
//位图文件名
IMAGE_BITMAP,
//类型为Windows位图
0,0,
LR_LOADFROMFILE);
if(NULL==hBitmap)
{
AfxMessageBox("不能打开文件");
return FALSE;
}
sBitmap.Attach(hBitmap);
imaSmall.Add(&sBitmap,RGB(0,0,0));
}
wndBar.SetImageList(&imaLarge, CGfxOutBarCtrl::fLargeIcon);
wndBar.SetImageList(&imaSmall, CGfxOutBarCtrl::fSmallIcon);
wndBar.SetAnimationTickCount(10);
wndBar.SetAnimSelHighlight(200);
wndBar.SetIfQueryRemove(true);
wndBar.AddFolder("我的好友", 0);
wndBar.AddFolder("陌生人", 1);
wndBar.AddFolder("黑名单", 2);
wndBar.InsertItem(0, 0, "午夜", 0, 0);
wndBar.InsertItem(0, 1, "浪子", 1, 0);
wndBar.InsertItem(0, 2, "未来之城", 2, 0);
wndBar.InsertItem(0, 3, "黑色幽默", 3, 0);
wndBar.InsertItem(0, 4, "想飞", 4, 0);
……//这儿省略一部分
wndBar.InsertItem(2, 0, "酒鬼", 80, 0);
wndBar.InsertItem(2, 1, "痴人", 81, 0);
wndBar.InsertItem(2, 2, "逐梦人", 82, 0);
wndBar.InsertItem(2, 3, "陆小凤", 83, 0);
wndBar.SetSelFolder(0);
return TRUE;
}
完成后我们可以编译改程序,但是当点击陌生人时,由于里面没有成员,本不应该出现下拉按钮,但是出现了,当我们点击时,就会发生溢出。所以修改原来的CgfxOutBarCtrl源文件的OnPaint函数:
if (l < GetItemCount() - 1
//Modified By jamiandy@163.com
//Author:流浪狗 Date:2005Y-05M-13D::12:13
//在此处修改原来的语句,以便使得当item为0时,不出现向下的按钮,防止溢出
//修改if (l < GetItemCount() - 1)为if (l < GetItemCount() - 1&&GetItemCount()!=0)
&&GetItemCount()!=0)
{
……//此处省略
}
else bDownArrow = false;
(5)、修改CgfxOutBarCtrl类的OnLButtonDown,在里面适当位置即响应点击FOLDER时的地方添加语句:
BOOL r = sndPlaySound("sound//folder.wav",SND_SYNC |SND_NODEFAULT);//播放WAV
ASSERT(r); r = sndPlaySound("",SND_ASYNC|SND_NODEFAULT);//停止播放
(6)、在CmainFrame的头文件中,DECLARE_MESSAGE_MAP()上面添加afx_msg long OnOutBarNotify(WPARAM wParam, LPARAM lParam);消息映射,在实现文件中,BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)和END_MESSAGE_MAP()之间加入ON_MESSAGE(WM_OUTBAR_NOTIFY, OnOutBarNotify)。编写代码:
long CMainFrame::OnOutBarNotify(WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case NM_SENDMSG:
{
int index = (int) lParam;
//弹出发送消息对话框
DoMsgDialog();
}
return 1;
//你可以在此添加你自己的消息,从CGfxOutBarCtrl中发送
}
return 0;
}
修改CgfxOutBarCtrl中的代码,实现向主框架发送消息,可以用GetOwner()->SendMessage(WM_OUTBAR_NOTIFY, NM_SENDMSG, iHitInternal2)实现,具体情况可以根据需要改变。然后从主框架中处理消息,从而保证用主框架来响应外界的消息。
经过这些,基本的QQ界面实现了,现在编译运行,就可以看到漂亮的界面了。
(三)、实现QQ的自动隐藏。
原理:在检测到窗口靠近屏幕边缘时,移动窗口到屏幕外边,从而实现自动隐藏,当检测到鼠标移近时,将窗口显示出来,从而实现自动弹出,实现过程如下:
(1)、在MainFrm.cpp中头部加入:
int ScreenX; //屏幕宽度
int ScreenY; //屏幕高度
int alignType; //全局变量,用于记录窗体停靠状态
enum
{
ALIGN_NONE, //不停靠
ALIGN_TOP, //停靠上边
ALIGN_LEFT, //停靠左边
ALIGN_RIGHT //停靠右边
};
#define NEAR_SIZE 5 //定义自动停靠有效距离
#define NEAR_SIDE 3 //窗体隐藏后在屏幕上保留的像素,以使鼠标可以触及
在OnCreate中加入:
ScreenX = GetSystemMetrics(SM_CXSCREEN);
ScreenY = GetSystemMetrics(SM_CYSCREEN);
SetTimer(WM_TIMER,50,NULL);
NearSide(GetSafeHwnd());
(2)、添加NearSide函数
void CMainFrame::NearSide(HWND hWnd)
{
int change = 0;
RECT rect;
GetWindowRect(&rect);
alignType = ALIGN_NONE;
if (rect.left < NEAR_SIZE)
{
alignType = ALIGN_LEFT;
if ((rect.left != 0) && rect.right != NEAR_SIDE)
{
rect.right -= rect.left;
rect.left = 0;
change = 1;
}
}
else if (rect.right > ScreenX - NEAR_SIZE)
{
alignType = ALIGN_RIGHT;
if (rect.right != ScreenX && rect.left != ScreenX - NEAR_SIDE)
{
rect.left += (ScreenX - rect.right);
rect.right = ScreenX;
change = 1;
}
}
//调整上下
if (rect.top < NEAR_SIZE)
{
alignType = ALIGN_TOP;
if (rect.top != 0 && rect.bottom != NEAR_SIDE)
{
rect.bottom -= rect.top;
rect.top = 0;
change = 1;
}
}
if (change)
{
MoveWindow(rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, TRUE);
}
}
(3)、重载OnTimer,编辑
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
POINT pt;
RECT rc;
GetCursorPos(&pt);
GetWindowRect(&rc);
if (!PtInRect(&rc, pt)) //若鼠标不在窗体内,隐藏窗体.
{
KillTimer(WM_TIMER);
HideSide(GetSafeHwnd(),TRUE);
}
CFrameWnd::OnTimer(nIDEvent);
}
(4)、添加HideSide,编辑:
void CMainFrame::HideSide(HWND hWnd, BOOL hide)
{
RECT rc;
int moves = 4; //动画滚动窗体的步数,如果你觉得不够平滑,可以增大该值.
int xStep, yStep;
int xEnd, yEnd;
int width;
int height;
register int i;
GetWindowRect(&rc);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
//下边判断窗体该如何移动,由停靠方式决定
switch (alignType)
{
case ALIGN_TOP:
{
//向上移藏
xStep = 0;
xEnd = rc.left;
if (hide)
{
yStep = -rc.bottom / moves;
yEnd = -height + NEAR_SIDE;
}
else
{
yStep = -rc.top / moves;
yEnd = 0;
}
break;
}
case ALIGN_LEFT:
{
//向左移藏
//此处省略,类似向上隐藏
……
break;
}
case ALIGN_RIGHT:
{
//向右移藏
//此处省略,类似向上隐藏
……
break;
}
default:
return;
}
//动画滚动窗体.
for (i = 0; i < moves; i++)
{
rc.left += xStep;
rc.top += yStep;
SetWindowPos(NULL, rc.left, rc.top, 0, 0,
SWP_NOSIZE | SWP_NOSENDCHANGING);
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
Sleep(5);
}
SetWindowPos(NULL, xEnd, yEnd, 0, 0, SWP_NOSIZE);
if (!hide) //如果窗体已被显示,设置定时器.监视鼠标.
{
SetTimer(WM_TIMER, 50, NULL);
}
}
(5)、最后重载OnNcMouseMove,添加代码如下:
void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point)
{
RECT rc;
GetWindowRect(&rc);
if (rc.left < 0 || rc.top < 0 || rc.right > ScreenX) //未显示
{
HideSide(GetSafeHwnd(), FALSE);
}else
{
HideSide(GetSafeHwnd(), FALSE);
SetTimer(WM_TIMER,50,NULL);
}
CFrameWnd::OnNcMouseMove(nHitTest, point);
}
这样,自动隐藏的功能就实现了,当你把它拖到屏幕边上的时候,就自动消失了,当鼠标移近时,又自动出现。
(四)、托盘程序的实现
(1)、将CtrayIcon(你可以从网上找到它)加入工程。添加两个图标,分别命名为IDI_ONLINE和IDI_OFFLINE,表示交替的两个图标。在MainFrm.h中加入私有变量CTrayIcon m_trayIcon; BOOL IsOnline;在构造函数中对其初始化,m_trayIcon(IDR_TRAYICON),IsOnline=FALSE。在MainFrm.cpp中添加#define WM_MY_TRAY_NOTIFICATION WM_USER+0
(2)、在OnCreate中添加:
m_trayIcon.SetNotificationWnd(this, WM_MY_TRAY_NOTIFICATION);
m_trayIcon.SetIcon(IDI_ONLINE);
SetTimer(2,500,NULL);
(3)、修改OnTimer:
if(nIDEvent==2)
{
IsOnline=!IsOnline;
m_trayIcon.SetIco(IsOnlineIDI_ONLINE:IDI_OFFLINE);
}
这样就可以动态改变图标了。
到此为止,我们要求的所有功能都实现了,现在可以编译运行,修改不正确的地方。效果如图所示: