VisualC++設(shè)計超強(qiáng)仿QQ自動伸縮窗口

字號:

某天在論壇上看到有人發(fā)帖詢問QQ自動伸縮窗口是怎么實現(xiàn)的,我也好想知道,于是到百度一搜索,結(jié)果不多,來來去去都是那幾篇,下載那些demo運行一下,發(fā)覺效果與QQ相差很大,于是決定自己動手做個,
    要求要近乎完美地模仿這個功能。由于是些效果的東西,貼圖也看不出來,所以文章里就不截圖了,想看效果的就直接運行源代碼的demo吧。
    一、觀察
    模仿前最重要的一步就是觀察,經(jīng)過半天對QQ的擺弄和摸索,總結(jié)出了以下一些特點:
    1、窗口開始粘附時,檢測的是鼠標(biāo)坐標(biāo)與桌面邊界的距離,特別地,粘附在下面的時候,檢測的是與任務(wù)欄的距離;
    2、在向上移動窗口時,窗口邊界永遠(yuǎn)不會超出桌面上面邊界;
    3、窗口是個 TopMost 風(fēng)格;
    4、當(dāng)窗口粘附在上面、左邊或右邊并顯示時,你把鼠標(biāo)移動到最頂端,光標(biāo)變成改變窗口大小的圖標(biāo),而單單是把窗口的top坐標(biāo)設(shè)置為0是不行的;
    5、粘附在下面的時候,當(dāng)處于移動狀態(tài),那么窗口的底邊是與任務(wù)欄頂邊對齊的,但從隱藏到顯示的時候,窗口的底端是與屏幕底邊對齊的;
    6、隱藏后顯露出來的那條線可能是一個Border,但肯定的是絕不包含Client區(qū)域;
    7、關(guān)于響應(yīng)鼠標(biāo)的進(jìn)入與移出窗口,絕對不是WM_MOUSEMOVE、WM_MOUSELEAVE。證明:你以及其慢的速度接觸隱藏狀態(tài)的QQ邊界,你會發(fā)現(xiàn)幾乎是“一觸即發(fā)”,你又以及其慢的速度移出顯示狀態(tài)的QQ,你會發(fā)現(xiàn)它的收縮反而不是“一觸即發(fā)”的,而是離邊緣10象素左右。而WM_MOUSEMOVE,WM_MOUSELEAVE,只有在進(jìn)入、移出Client區(qū)域才響應(yīng),明顯和QQ不同,其實從第6點也可以知道;
    8、粘附在兩邊的時候,高度會調(diào)整為桌面上邊界到任務(wù)欄下邊界的距離;
    9、在“拖動時顯示窗口內(nèi)容”模式下(桌面屬性-外觀-效果),粘附在兩邊的拖動出來時;如果收縮之前高度比收縮后小則回復(fù)原來高度,在非“拖動時顯示窗口內(nèi)容”模式下,光柵會回復(fù)原來高度,但釋放左鍵時,高度卻是收縮時調(diào)整后的高度,一開始我以為這是個BUG,但我編寫時同樣出現(xiàn)這個問題,發(fā)現(xiàn)這兩種模式會影響WM_MOVING參數(shù)的意義;
    10、粘附在兩邊的時候當(dāng)你設(shè)置任務(wù)欄自動隱藏,QQ窗口會自動調(diào)整高度充滿屏幕高度;
    11、窗口顯示或隱藏不是一瞬間的,這點在第9點提到的兩種模式下,會有所不同;
    12、任務(wù)欄并不顯示QQ窗口;
    二、編寫代碼
    觀察完畢,就開始編寫了。
    首先新建一個基于對話框的MFC程序,命名為QQHideWnd,在對話框?qū)傩缘膕tyles頁把border改為Resizing,你也可同時把Entended styles 的 tool window 鉤上,對于這點我在程序了動態(tài)修改了。
    在QQHideWndDlg.h頭文件添加以下成員函數(shù):
    protected:
    //修正移動時窗口的大小
    void FixMoving(UINT fwSide, LPRECT pRect);
    //從收縮狀態(tài)顯示窗口
    void DoShow();
    //從顯示狀態(tài)收縮窗口
    void DoHide();
    //重載函數(shù),只是為了方便調(diào)用,實際調(diào)用CWnd的SetWindowPos(…)
    BOOL SetWindowPos(const CWnd* pWndInsertAfter,LPCRECT pCRect, UINT nFlags = SWP_SHOWWINDOW);
    繼續(xù)添加成員變量:
    private::BOOL m_isSizeChanged;//窗口大小是否改變了
    BOOL m_isSetTimer;//是否設(shè)置了檢測鼠標(biāo)的Timer
    INTm_oldWndHeight;//舊的窗口寬度INTm_taskBarHeight;//任務(wù)欄高度INTm_edgeHeight;//邊緣高度
    INTm_edgeWidth;//邊緣寬度
    INTm_hideMode;//隱藏模式
    BOOL m_hsFinished;//隱藏或顯示過程是否完成
    BOOL m_hiding;//該參數(shù)只有在!m_hsFinished才有效
    //真:正在隱藏,假:正在顯示
    增加消息響應(yīng),需要注意的是有些消息你只有把右下角的 Filter for message設(shè)置為window才能看到。
    WM_ NCHITTEST
    WM_MOVING
    WM_CREATE
    WM_TIMER
    然后來到對應(yīng)的cpp文件,在頭部定義一些宏:
    //收縮模式#define HM_NONE0//不收縮
    #define HM_1//向上收縮
    #define HM_BOTTOM2//向下收縮
    #define HM_LEFT3//向左收縮
    #define HM_RIGHT4//向右收縮
    #define CM_ELAPSE200 //檢測鼠標(biāo)是否離開窗口的時間間隔
    #define HS_ELAPSE5//伸縮過程每步的時間間隔
    #define HS_STEPS10//伸縮過程分成多少步完成
    #define INTERVAL20//觸發(fā)粘附時鼠標(biāo)與屏幕邊界的最小間隔,單位為象素
    #define INFALTE10//觸發(fā)收縮時鼠標(biāo)與窗口邊界的最小間隔,單位為象素