介紹
從零開發自定義控件常常是不需要的,因為標准控件組是相當全面的,如果不夠用,子類化或自繪等方法就可以搞掂這個工作。這是一個不應被忽略的要點。在從零開發一個自定義控件時,千辛萬苦獲得的控件往往會不如標准(控件)。
那就是說,這裡只有少數真地缺少的控件,如果我們想要在我們的應用程序中部署它們,除了無中生有地構建它們別無他法。有一個這樣的情況就是名稱為“層疊式窗體控件”,或無論什麼它的其他稱呼,例如:Spybot或Outlook。因為它不在標准控件之中並且因為它是一個有趣的練習,本指南講解了如何開發這類控件,並一步一步地給予講解。
本指南的目標讀者為程序員新手,在開始之前,我想挑戰你一下:即在不閱讀本文的情況下先嘗試自己開發這個控件。盡管這看起來可能會讓人退縮或你可能不知道從哪裡開始,它不是像你想像得那樣難。嘗試一下,看看你能走多遠,這時再回來看看本指南並檢驗一下我所說的話。提示:它完全與窗體的重新恢復尺寸和重新復位有關,沒有其他。
我們要完成什麼
目標是一個“層疊式窗體控件”。就是它。它將會被盡可能地泛型化並會闡明如何聚集該類控件的一個。
熱心的讀者可能希望知道我在寫這個演示工程時寫了這個指南。下面的指導、解釋和代碼實際上就是在上面的截屏中的層疊窗體控件(准確地說來就是圖中左邊那個控件)的開發。本文發表於http://bianceng.cn(編程入門網)
讓我們從代碼開始。
過程詳解
工程開始
創建工作是簡單的。創建一個新的基於對話框的工程,並設置警告級別為4(工程設置,C/C++標簽)。級別4將確保任何可疑事物給我們帶來注意以使得由我們來決定要做什麼“這裡提示的警告在絕大多數情況下可以被安全地忽略”(此語出自文檔)
讓我們在該控件上開始工作。創建一個用CStatic作為基類的新的MFC類命名為CStackedWndCtrl。
在資源編輯器中,添加一個圖片控件ID號為IDC_SWC。保留Type的值為缺省的Frame並將Color置為Black。
使用MFC ClassWizard添加一個數據變量到IDC_SWC命名為m_StackedWndCtrl,確保選擇了Control作為Category以及CStackedWndCtrl作為變量類型。
在OK上點擊,彈出一個消息框提示我們確保我們已經為類CStackedWndCtrl包含頭文件在我們的對話框代碼中。如果你沒有包含它現在就要做了。
數據結構
任何控件的主要部分就是一個數據結構,數據結構可以保持將要顯示的信息。
好的,什麼將會被顯示?該控件用面板制作出來,每個面板包含兩個窗體,一個標題窗體和一個內容窗體。下面的圖片說明了這個概念。
控件的機制要求只有一個面板的內容窗體在一個時間內顯示。在一個面板上點擊標題窗體將觸發其相應的內容窗體顯示,並且也隱藏了當前顯示面板的內容窗體。
因此,數據結構將包含一對指向CWnd 對象的指針和一個布爾標識值以指出是否顯示或隱藏這個面板的內容窗體。不需要任何其他的東西了。
#include <afxtempl.h>
class CStackedWndCtrl : public CStatic
{
....
....
// Attributes
protected:
typedef struct
{
CWnd* m_pwndRubric;
CWnd* m_pwndContent;
BOOL m_bOpen;
} TDS_PANE, *PTDS_PANE;
CArray<PTDS_PANE, PTDS_PANE> m_arrPanes;
....
....
}對於這些結構的保存、檢索和操作,用一個數組是一個方便的且足夠的方法。記住為了使用這個數組模版,我們需要包含相應的頭文件。
下一個任務是寫一個允許我們添加面板到控件上的public方法。這沒有什麼困難。我們使窗體對象的指針作為參數傳遞,並設置新的面板如其所顯示的一樣。
int CStackedWndCtrl::AddPane( CWnd* pwndRubric, CWnd* pwndContent )
{
// 隱藏無論哪一個正在顯示面板的內容窗體
//我們將總是顯示最近添加的面板的內容窗體
for( int i = 0; i < m_arrPanes.GetSize(); i++ )
if( m_arrPanes[ i ]->m_bOpen )
m_arrPanes[ i ]->m_bOpen = FALSE;
//創建一個新的面板結構
PTDS_PANE pPane = new TDS_PANE;
if( pPane == NULL )
{
AfxMessageBox( "Failed to add a new pane to"
" the stack.
Out of memory." );
return -1;
}
// 拷貝指針到標題和內容窗體
//同時,設置這個面板為打開狀態
pPane->m_pwndRubric = pwndRubric;
pPane->m_pwndContent = pwndContent;
pPane->m_bOpen = TRUE;
// 添加該新面板到棧的尾部
int iIndex = m_arrPanes.Add( pPane );
// 重新排列棧
RearrangeStack();
// 返回新面板的索引號
return iIndex;
}
在我們擔心排列和顯示面板之前(如果你想要測試這個代碼,只要參考RearrangeStack
方法的調用 ),我們要確保在退出時該結構體被完全刪除是非常重要的,以免內存洩漏。我們在析構器中執行該任務,如下所示:
CStackedWndCtrl::~CStackedWndCtrl()
{
for( int i = 0; i < m_arrPanes.GetSize(); i++ )
{
//刪除標題窗體
m_arrPanes[ i ]->m_pwndRubric->DestroyWindow();
delete m_arrPanes[ i ]->m_pwndRubric;
// 刪除內容窗體
m_arrPanes[ i ]->m_pwndContent->DestroyWindow();
delete m_arrPanes[ i ]->m_pwndContent;
// 刪除結構體
delete m_arrPanes[ i ];
}
m_arrPanes.RemoveAll();
}
簡單填充。我們遍歷該面板上的數組,銷毀每個窗體,然後刪除每個窗體對象,然後刪除每個面板對象,並且最後,從數組中移除所有指針。
這個功能足以使得CStackedWndCtrl類可以做它的工作。我們可以添加面板,同時它們(譯注:指面板)在控件被銷毀時被適當釋放。
可視的魔力
None of it, 我想.排列和顯示控件的算法是相當簡單的。
我們遍歷
[1] [2] [3] 下一頁