MFC控制條視窗布局原理

2021-04-27 09:07:33 字數 3223 閱讀 3782

一、框架視窗

框架視窗在其大小被改變的時候會收到wm_size訊息,這個訊息的處理函式是cframewnd::onsize,此函式接著呼叫recalclayout來重新安置各子視窗,它的主體**如下:

if(getstyle() & fws_snaptobars)

else

這裡有兩個小的地方要注意,第一是fws_snaptobars風格。一般來說,都是框架視窗主動改變大小,子視窗隨之要修改自己來適應框架視窗的改變,但是這個fws_snaptobars風格卻相反,是讓框架視窗改變大小來適應它的子視窗,但我一路跟蹤下來沒有發現有哪個框架視窗有這個風格,都是走else分支的(事實上這個風格是為cminidockframewnd準備的,這個框架視窗的大小是根據它內部的控制條來定的);第二是要注意recalclayout是不可重入的,mfc防止重入的方法雖然非常的簡單有效,但是它的方法要不能防止多執行緒的重入——話說回來mfc本身就不是乙個執行緒安全的庫j

好了現在我們進入了整個重布局動作的主體函式repositionbars,讓我們仔細分析一下它都幹了些啥見不得人的「勾當」(這個函式在msdn裡有文件記載,關於它的幾個引數的含義就不在這裡贅述了):

首先,它建立乙個afx_sizeparentparams結構,並填寫好它的成員變數,最主要的就是兩個:bstretch和rect,前乙個是bool型變數,表明子視窗是否需要拉伸(拉伸到和客戶區同寬或同高),後乙個是當前客戶區大小。

接著,框架視窗按照z-order,從最上面的子視窗開始,依次向它的所有子視窗傳送wm_sizeparent訊息(id為nidleftover的子視窗除外),以通知它們,按照新的客戶區,重新計算自己的大小和位置,並從afx_sizeparentparams::rect中將自己所佔的那一塊rectangle扣除,這樣所有的子視窗計算完畢後框架視窗就可以知道剩餘客戶區的大小(ps:到底都傳送給了誰?又是按照什麼次序?以mdidemo為例,該例子建立了乙個c*******、乙個cthumbnaillistctrlbar,在都是dock狀態下,跟蹤記錄下的所傳送的視窗的id,依次是0xe801à0xe81bà0xe81eà0xe81cà0xe81d,察看各子視窗id的定義得知次序是狀態列à上方的dock barà下方的dock barà左邊的dock barà右邊的dock bar,這裡要注意的是,所找到的第乙個子視窗的id是0xe900(0xe900被定義成afx_idw_pane_first,在這個例子裡它是view的視窗id,與這個id對應的還有另乙個id叫afx_idw_pane_last,sdi的view視窗,mdi的mdiclient視窗,分隔條視窗等的id都要介於上面兩個id值之間),等於nidleftover,所以wm_sizeparent訊息是不發給它的。那麼為什麼tool bar和thumbnail bar也收不到訊息呢?因為dock bar是它的父視窗,訊息發給dock bar了,dock bar會計算它內部停靠的全部子視窗的大小,就不需要框架視窗操心了,除此之外,浮動的控制條也是不接受wm_sizeparent訊息的,原因很簡單,浮動的控制條不會跟隨主框架視窗的大小改變而改變)。

傳送完畢之後(這裡有個細節,框架視窗傳送wm_sizeparent訊息用的是sendmessage,這意味著只有子視窗處理完該訊息後,sendmessage才返回,框架視窗才會接著傳送訊息給下乙個子視窗,全部傳送完畢也就意味了所有的子視窗都已經從afx_sizeparentparams::rect中把自己要的那一塊rectangle給拿掉了),剩下的就是最後可用的客戶區了,根據nflags的值,執行不同的返回動作。其中reposquery表示只查詢,不做實際的重布局動作,把最後剩下的客戶區,拷貝到lprectparam就返回了,如果不是reposquery那就要做重布局了,對reposdefault,我們要把id為nidleftover的子視窗的大小和位置調整到被其他子視窗切剩后剩下的可用客戶區內,使這個子視窗正好完全覆蓋最後的可用區域(也就是說所有的子視窗把客戶區全部擠滿了)。而當nflag等於repo***tra時,在調整 nidleftover子視窗的大小和位置前,用 lprectparam來對最後剩下的可用區域做修正,具體來說就是把afx_sizeparentparams::rect向裡縮,縮的距離由lprectparam指定,這樣就使最後剩下的客戶區不被nidleftover子視窗佔滿,而是空出一些地方。修正完畢後最後一次性重布局所有的子視窗。

至此,框架視窗所做的動作全部完成。

二、控制條子視窗

分析完了框架視窗,接著分析控制條這邊所要做的響應動作。根據前面的跟蹤我們知道除了cstatusbar和cdockbar,從ccontrolbar繼承下來的控制條諸如c*******、cdialogbar等,是收不到wm_sizeparent訊息的,它們的父視窗cdockbar代替它們接收這個訊息。因此整個重布局過程的起點是cdockbar對wm_sizeparent訊息的處理函式cdockbar::onsizeparent(對cstatusbar而言,其起點是ccontrolbar::onsizeparent,這裡不打算對它作進一步分析,有興趣可以自己完成)。第一步讓我們來分析這個函式所做的動作,這個函式不長,把完整**列出:

lresult cdockbar::onsizeparent(wparam wparam, lparam lparam)

如前所述,wm_sizeparent訊息傳遞乙個afx_sizeparentparams結構體的指標作為引數,在這裡我們先取出這個結構體,然後判斷afx_sizeparentparams::hdwp是否為空,是的話說明父視窗僅僅是想查詢,並不要真的進行重布局動作(回到repositionbars,當nflags為reposquery時,並不呼叫begindeferwindowpos,故而afx_sizeparentparams::hdwp就一定是null),完成必要的變數保護後,進入父類ccontrolbar的onsizeparent,在此,根據控制條視窗的風格,決定如何計算控制條的尺寸,具體是這樣的;

dword dwmode = lplayout->bstretch ? lm_stretch : 0; //拉伸否?

if((m_dwstyle & cbrs_size_dynamic) && m_dwstyle & cbrs_floating) //浮動,形狀可變

else if(dwstyle & cbrs_orient_horz) //水平停靠

else

csize size = calcdynamiclayout(-1, dwmode);

要注意的是最後一行呼叫,calcdynamiclayout,這個函式是乙個虛函式,先被呼叫的是ccontrolbar:: calcdynamiclayout,這個函式呼叫了calcfixedlayout(也是乙個虛函式),注意到cdockbar對此函式進行了過載,所以轉了一圈我們又回到了cdockbar中。

TCP滑動視窗控制流量的原理

tcp的滑動視窗機制 tcp這個協議是網路中使用的比較廣泛,他是乙個面向連線的可靠的傳輸協議。既然是乙個可靠的傳輸協議就需要對資料進行確認。tcp協議裡視窗機制有2種 一種是固定的視窗大小 一種是滑動的視窗。這個視窗大小就是我們一次傳輸幾個資料。對所有資料幀按順序賦予編號,傳送方在傳送過程中始終保持...

TCP滑動視窗控制流量的原理

tcp的滑動視窗機制 tcp這個協議是網路中使用的比較廣泛,他是乙個面向連線的可靠的傳輸協議。既然是乙個可靠的傳輸協議就需要對資料進行確認。tcp協議裡視窗機制有2種 一種是固定的視窗大小 一種是滑動的視窗。這個視窗大小就是我們一次傳輸幾個資料。對所有資料幀按順序賦予編號,傳送方在傳送過程中始終保持...

MFC對話方塊新增控制台視窗

呼叫allocconsole 函式為程序建立乙個控制台視窗console,程序attach到該console上。allocconsole 建立console freopen count wr std out 重定向stdout輸出到console,第乙個引數為重定向的讀寫位置 freopen d l...