• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-161  評論-223  文章-30  trackbacks-0
               著名的千千靜聽音樂播放器,其界面簡潔優(yōu)雅、美觀大方,特別是它那種幾個窗口像磁石般相互吸引,當(dāng)拖動主窗口時,粘在一起的其它窗口會跟隨著一起移動,當(dāng)拖動其它窗口時,又能脫離不粘在一起,這種窗口效果讓用戶操作方便,省心省力。為描述方便,本文稱這種效果為多窗口的組合分離,它的主要特點是僅用鼠標(biāo)任意移動窗口,就可組合或分離,當(dāng)組合在一起時,移動某窗口(如主窗口,暫稱為老板窗口)能整體移動,移動其口窗口(非老板窗口,暫稱為工人窗口)又能將自己脫離出來。近來由于工作需要實現(xiàn)了類似于此的窗口效果,經(jīng)過幾天的測試,終于穩(wěn)定。在開發(fā)過程中,考慮了以下幾個問題:
                 (1)  組合分離的條件如何決定判斷。
                 (2)  當(dāng)窗口大小改變時,包括最小化,最大化,縮放窗口等,如何保證不影響組合分離,能正常整體移動。
                 (3)  窗口個數(shù)是可變的,當(dāng)新建或銷毀窗口時,如何保證不影響組合分離,能正常整體移動(千千靜聽窗口個數(shù)是有限的,而且可能只是隱藏窗口)。
                 (4)  采用什么數(shù)據(jù)結(jié)構(gòu)較好,如何維護(hù)任意兩個窗口間的距離關(guān)系(相交或相切視為組合,相離視為分離)。
                 (5)  當(dāng)拖動老板窗口時,如何拖動與其組合的所有窗口,關(guān)鍵是如何得到所有與其組合的窗口列表。
                 (6)  如何針對這種效果設(shè)計一個通用的組件類,只需調(diào)用幾個方法便可搞定。
               
               針對以上問題,主要思路是視屏幕上任意多個窗口為頂點,以其窗口矩形中心點來看待這個窗口,如果任意兩個窗口間關(guān)系為組合,則視這兩個頂點間是相通的,即兩個頂點存在邊。如果為分離,則視兩頂點間是不通的,即兩頂點不存邊。因此可以用無向圖來存儲窗口和關(guān)系,為簡單起見,我用的是鄰接矩陣,問題(4)得以解決。既然用鄰接矩陣來存儲,那么如何得到所有與老板窗口相關(guān)的組合窗口呢?由于實際多個窗口在移動過程中,會改變其組合分離關(guān)系,這就會得到多個無向圖的連通分量,而我們需要的是包含老板窗口的那一個連通分量,因此可以用DFS深度搜索遍歷這個無向圖連通分量,起始頂點是老板窗口,遍歷完后就會得所有與其組合的窗口列表,問題(5)得以解決?,F(xiàn)在討論問題(1),這里有個細(xì)節(jié)問題就是組合分離的條件判斷有兩種情況,一是當(dāng)移動窗口時的條件,稱為條件1,因為實際向一個窗口A移入另一個窗口B時,要達(dá)到還沒有接近窗口A時便一下子靠近A就像被A吸引的效果,當(dāng)移出B時還沒完全移到A窗口外面時便一下子遠(yuǎn)離就像被A排斥的效果。二是當(dāng)大小改變時的條件,稱為條件2,這個不同于條件1,因為它不需要那種吸引排斥的效果,也沒必要,這個條件2就是簡單的判斷A和B矩形是否相交,API函數(shù)IntersectRect即可完成這一判斷。條件1的判斷如下圖所示:
                                                                       
               在B向A移入過程中,當(dāng)B的中心點在矩形left,top,right,bottom范圍內(nèi),可認(rèn)為是發(fā)生組合,實現(xiàn)吸引效果;當(dāng)在center矩形內(nèi),認(rèn)為是已經(jīng)組合了;同理,B向A移出過程中,當(dāng)B的中心點在矩形left,top,right,bottom范圍內(nèi),可認(rèn)為是發(fā)生分離,實現(xiàn)排斥效果。當(dāng)都不在left,top,right,bottom,center矩形范圍時,認(rèn)為是已經(jīng)分離了。至此,問題(1)得到解決。當(dāng)窗口大小改變時,需要更新鄰接矩陣反映窗口間關(guān)系的變化,而后更新組合窗口列表,組合窗口列表的計算依賴于鄰接矩陣,運用DFS算法來更新,這在WM_SIZE消息事件處理內(nèi)完成,問題(2)得到解決。當(dāng)新建窗口時,需要向無向圖中增加(窗口)頂點,擴(kuò)充鄰接矩陣以備存儲與其它窗口的關(guān)系;當(dāng)銷毀窗口時,需要從無向圖中刪除對應(yīng)的頂點,而后從鄰接矩陣中刪除對應(yīng)的關(guān)系,問題(3)得到解決。
               上述問題(1)--(5)都已分析并得到解決,總的來說,就是以數(shù)據(jù)結(jié)構(gòu)中無向圖的觀點和算法來建模解決這些問題的,特別是運用到了DFS搜索算法來重建已組合的所有窗口列表,只有這樣,在移動老板窗口過程中,才能保證其它窗口跟隨著一起移動。接下來就是最后一個問題,也就是怎么封裝設(shè)計組件類,以達(dá)到方便應(yīng)用的目的,綜上所述,設(shè)計接口方法與以下窗口4種消息相關(guān):
               1) 創(chuàng)建窗口發(fā)生的消息,如WM_CREATE,WM_INITDIALOG等。
               2) 關(guān)閉或銷毀窗口發(fā)生的消息,如WM_CLOSE,WM_DESTROY等。
               3) 窗口大小改變后消息,WM_SIZE。
               4) 窗口移動中消息,WM_MOVING。
               
               另外提供一個設(shè)置獲取老板窗口的方法,在應(yīng)用程序中,只需在窗口4種消息處理內(nèi)調(diào)用以上對應(yīng)4個方法即可實現(xiàn)多窗口組合分離的效果,注意該類沒有考慮多線程,因此是非安全的,適用于多窗口屬于同一線程內(nèi)的情況。類聲明如下 
             1class CWndMagnet
             2{
             3public:
             4    CWndMagnet();
             5  virtual ~CWndMagnet();
             6
             7public:
             8    void SetLeadWindow(HWND hWnd) { m_hLead = hWnd; }
             9    HWND GetLeadWindow() const return m_hLead; }
            10    
            11    void AddMagnetWnd(HWND hWnd);
            12    void RemoveMagnetWnd(HWND hWnd);
            13    void OnLButtonDown(HWND hWnd);
            14    void OnNcLButtonDown(HWND hWnd);
            15    void OnMoving(HWND hWnd, LPRECT lpRect);
            16    void OnSize(HWND hWnd, UINT uType);
            17
            18protected:
            19    void MoveLeadWndSet(HWND hWnd, LPCRECT lpRect);
            20    void UpdateLeadWndSet(HWND hWnd, LPCRECT lpRect = 0);
            21    void DeleteMagWnd(HWND hWnd);
            22    void Add2DMatrix();
            23    void Delete2DMatrix(HWND hWnd);
            24    void Update2DMatrix(HWND hWnd, LPRECT lpRect = 0);
            25
            26private:
            27    int GetFirstNeighbor(int v);
            28    int GetNextNeighbor(int v, int w);
            29    void DFS(int v, std::vector<bool>& vecVisited, std::vector<int>& vecNeighbor);
            30
            31private:
            32    static const int      s_c_iThreshold = 10///< 偏移閥值
            33    HWND                  m_hLead;        ///< 老板窗口
            34    std::map<HWND,POINT>      m_map_leadWnd;  ///< 粘合窗口列表
            35    std::map<HWND,int>        m_map_magWnd;   ///< 需要組合分離的窗口列表
            36    std::vector<std::vector<bool> > m_vec_2DMatrix; ///< 表示任意兩個窗口間相交或相切的鄰接矩陣
            37    

            38}
            ;
            posted on 2011-07-04 11:14 春秋十二月 閱讀(2825) 評論(0)  編輯 收藏 引用 所屬分類: C/C++
            久久无码专区国产精品发布| 久久精品二区| 久久久国产视频| 久久久久亚洲AV无码去区首| 国产精品久久国产精品99盘 | 一个色综合久久| 久久精品国产亚洲Aⅴ蜜臀色欲| 69久久精品无码一区二区| 亚洲色欲久久久综合网东京热| 四虎国产精品成人免费久久| 日本欧美国产精品第一页久久| 久久丝袜精品中文字幕| 亚洲午夜无码久久久久小说| 综合久久精品色| 色婷婷综合久久久中文字幕| 色偷偷偷久久伊人大杳蕉| 久久天天躁狠狠躁夜夜96流白浆| 蜜臀av性久久久久蜜臀aⅴ| 久久精品国产亚洲77777| 国产亚洲色婷婷久久99精品| 国产成人精品白浆久久69| 国产精品99久久99久久久| 国产成人综合久久精品红| 久久综合亚洲鲁鲁五月天| 伊人久久无码中文字幕| 九九精品99久久久香蕉| 精品久久久久久国产91| 精品久久久久久无码人妻热| 区亚洲欧美一级久久精品亚洲精品成人网久久久久| 久久久久国色AV免费观看| 久久午夜夜伦鲁鲁片免费无码影视| 成人妇女免费播放久久久| Xx性欧美肥妇精品久久久久久| 午夜精品久久久久久影视777| 精品久久久中文字幕人妻| 国产麻豆精品久久一二三| 久久久久亚洲AV成人网人人软件| 久久人人爽人人爽人人片AV东京热 | 狠狠综合久久综合88亚洲| 久久久九九有精品国产| 一本色道久久综合狠狠躁篇|