类似QQ界面的实现

来源:互联网 发布:软件质量工程师 编辑:程序博客网 时间:2024/05/03 22:11

类似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_IMAGELISTIDB_SMALL_IMAGELIST。在QQ2005中将NEWFACE文件夹拷贝到当前工程目录下,准备一个声音文件folder.wav

2)、将CgfxOutBarCtrl和它要用到的一些类CgfxGroupEditCgfxPopupMenu一起导入工程。

3)、在MainFrm.h中添加包含#include "GfxOutBarCtrl.h",并添加属性CgfxOutBarCtrl wndBar CimageList imaLarge, imaSmall

4)、重载CmainFrameOnCreateClient函数

 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_IMAGELISTIDB_SMALL_IMAGELIST。在QQ2005中将NEWFACE文件夹拷贝到当前工程目录下,准备一个声音文件folder.wav

2)、将CgfxOutBarCtrl和它要用到的一些类CgfxGroupEditCgfxPopupMenu一起导入工程。

3)、在MainFrm.h中添加包含#include "GfxOutBarCtrl.h",并添加属性CgfxOutBarCtrl wndBar CimageList imaLarge, imaSmall

4)、重载CmainFrameOnCreateClient函数

 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);

    }

这样就可以动态改变图标了。

到此为止,我们要求的所有功能都实现了,现在可以编译运行,修改不正确的地方。效果如图所示:

原创粉丝点击