新增大小可改變的dialogbar,建立及其銷燬
我在VS2008下做的。
步驟如下:
1)新增一個IDD_DIALOGBAR模板型別的對話方塊,使用class wizard產生類時,選擇基類為CDialog,因為沒有CdialogBar
2)把新建的類中的CDialog都改為CDialogBar,特別注意的是:該類建構函式的成員初值列的初始值為
3)給類新增三個成員變數
4)給類過載成員函式:兩個create和CBRS_SIZE_DYNAMIC 的響應函式CalcDynamicLayout()。
之所以有兩個Create函式,是因為該類的基類就有兩個版本的Create函式。
這裡需要說明的是:關鍵就是這個CalcDynamicLayout()函式,因為雖然MFC提供了CBRS_SIZE_DYNAMIC樣式,但是預設情況下並沒有呼叫相關的大小響應函式,所以要過載該函式使之生效,而也正是為了配合該過載函式,才添加了以上三個成員變數。
當然,相應的要在該類定義中新增這三個函式的宣告。
這樣,就可以讓該dialog在浮動的時候改變大小了,但是不能同時改變寬和高,所以你無法看到一般的斜著的箭頭。
可以看到,上述的dialog Bar的建立是把該類物件作為CMainframe的成員變數,這樣dialogBar的生存期就等同於Mainframe。這和非模態對話方塊非常類似,MSDN上面也說DialogBar和modeless dialog類似。因為對話方塊有其相關的資源,不能隨便釋放,所以這裡的dialog Bar物件不能是一個區域性變數,其解決方法就是:
1)將之放入一個生存期較長的類中或者(上述所用的方法)
2)為之申請一個堆記憶體
後者在非模態對話方塊中似乎用的更常見:
而在後者情況下,因為申請了堆記憶體,所以當不再使用該類物件(無論是Modeless dialog還是用create建立的dialog bar)都需要釋放其記憶體。而釋放的最好方式莫過於讓該類自身銷燬之。這就提示我們過載PostNcDestroy()函式達到該目的。因為PostNcDestroy()是該類呼叫的最後一個函式。銷燬一個視窗(該dialog自然也是繼承自CWnd的)的一般過程就是WM_CLOSE訊息呼叫DestroyWindow(),然後發出WM_NCDESTORY訊息呼叫OnNcDestroy()函式,在該函式中呼叫PostNcDestroy()虛擬函式。所以釋放記憶體的最好時機就是在該視窗按照規矩銷燬了一切後,最後把這些申請的資源從記憶體中釋放掉。從這個方面講,用delete myClassObj的方式直接釋放資源的方式是不好的,因為沒有正常的去銷燬對話方塊(銷燬對話方塊和釋放資源是不同的),這種方式具體的壞處我還沒有細究,我試了一下似乎還沒發現異常,應該是還沒觸發到相關異常。無論如何,還是建議過載PostNcDestroy()函式,在其最後delete this。
還需要說明的是,在上述兩種方法建立dialogbar或Modeless dialog中,在不需要手動銷燬dialog情況下,直接將之放入別的類中即可(第一種方式),這樣就免得自己再去到堆裡面申請記憶體然後過載PostNcDestroy()函式什麼的,讓他和程式一起結束得了。但是如果在程式執行過程中需要手動銷燬之,比如對於dialogbar,我想在原來的dialog bar的地方將之銷燬再新建一個dialog bar,那麼第一種方式就有點不好搞了,因為不方便確定怎麼銷燬該dialog物件,直接呼叫其解構函式?那麼下次產生一個新的dialog怎麼產生呢?產生的就將是一個區域性物件變量了,要麼就只能模仿第二種方式申請堆記憶體了。所以在這種情況下,還是用第二種方法合適些:只需要在要銷燬的時候呼叫該dialog的DestroyWindow()即可,因為正如前所述,它會一步一步呼叫PostNcDestroy()函式,而你,難道還沒有在其最後新增上delete this;嗎?
最後,需要注意的是:銷燬掉該對話方塊後,還是有一個影子留在窗口裡面,那是因為沒有重繪新的客戶區的緣故。而直接使之響應WM_PAINT時無效的,因為它重繪的客戶區似乎還是以前的大小。所以我用了一個折中的欺騙使用者的手法:使得視窗寬度增減1個畫素。需要指明的是,我使用MoveWindow()使之重繪該視窗似乎也無效,具體的參見以下程式碼及其註釋: