使用 CTabCtrl 實現多頁面控件切換時,傳統做法需在 OnSelchange 中手動 ShowWindow 每個控件,程式碼冗長、難維護、易出錯。本文提出CTabContainer 容器類別,以鏈表管理各分頁控件 ID,一行程式碼完成切換。
nTabs)。CList 鏈表,儲存該分頁隸屬的控件 ID。AddCtrlId/Delete 管理 ID,Show(nTab) 一鍵切換顯示/隱藏。// TabContainer.h
class CTabContainer
{
public:
CTabContainer();
virtual ~CTabContainer();
BOOL Init(int nTabs, CWnd* pParent); // 初始化:分頁數、父視窗
BOOL AddCtrlId(int nTab, int nID); // 將控件 ID 加入指定分頁
BOOL Delete(int nTab, int nID); // 移除控件 ID
void Show(int nTab); // 顯示指定分頁,隱藏其他
void Clear(); // 釋放資源
protected:
typedef CList CIntList;
CIntList* m_pIDGroups; // 鏈表陣列,大小 = nTabs
int m_nLCount; // 分頁數
CWnd* m_pParent; // 父視窗指標 (用於 GetDlgItem)
};
// TabContainer.cpp
CTabContainer::CTabContainer() : m_pParent(NULL), m_pIDGroups(NULL), m_nLCount(0) {}
CTabContainer::~CTabContainer() { Clear(); }
BOOL CTabContainer::Init(int nTabs, CWnd* pParent)
{
ASSERT(nTabs > 0 && pParent != NULL);
Clear();
m_nLCount = nTabs;
m_pParent = pParent;
m_pIDGroups = new CIntList[nTabs];
return (m_pIDGroups != NULL);
}
BOOL CTabContainer::AddCtrlId(int nTab, int nID)
{
ASSERT(nTab < m_nLCount);
m_pIDGroups[nTab].AddTail(nID);
return TRUE;
}
BOOL CTabContainer::Delete(int nTab, int nID)
{
ASSERT(nTab < m_nLCount);
POSITION pos = m_pIDGroups[nTab].Find(nID);
if (pos) m_pIDGroups[nTab].RemoveAt(pos);
return TRUE;
}
void CTabContainer::Show(int nTab)
{
ASSERT(nTab < m_nLCount);
for (int i = 0; i < m_nLCount; i++) {
POSITION pos = m_pIDGroups[i].GetHeadPosition();
while (pos) {
int nID = m_pIDGroups[i].GetNext(pos);
m_pParent->GetDlgItem(nID)->ShowWindow((i == nTab) ? SW_SHOW : SW_HIDE);
}
}
}
void CTabContainer::Clear()
{
if (m_pIDGroups) {
delete[] m_pIDGroups;
m_pIDGroups = NULL;
m_nLCount = 0;
}
}
// 對話框成員
CTabContainer* m_pTabContainer;
CTabCtrl m_tab;
// OnInitDialog
m_pTabContainer = new CTabContainer;
m_pTabContainer->Init(3, this); // 3 個分頁
m_pTabContainer->AddCtrlId(0, IDC_BUTTON1);
m_pTabContainer->AddCtrlId(0, IDC_BUTTON4);
m_pTabContainer->AddCtrlId(0, IDC_BUTTON5);
m_pTabContainer->AddCtrlId(1, IDC_BUTTON2);
m_pTabContainer->AddCtrlId(1, IDC_BUTTON6);
m_pTabContainer->AddCtrlId(2, IDC_BUTTON3);
m_pTabContainer->AddCtrlId(2, IDC_BUTTON7);
m_pTabContainer->AddCtrlId(2, IDC_BUTTON8);
m_pTabContainer->Show(0); // 預設顯示第 0 頁
// TabCtrl 切換事件
void CMyDialog::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
m_pTabContainer->Show(m_tab.GetCurSel());
*pResult = 0;
}
// 記得在 OnDestroy 釋放
void CMyDialog::OnDestroy()
{
delete m_pTabContainer;
CDialog::OnDestroy();
}
| 傳統寫法 | CTabContainer 方案 |
|---|---|
| OnSelchange 中硬編碼每個控件 Show/Hide | 資料驅動,ID 列表集中管理 |
| 新增控件需修改多處 Switch/If | 僅需一行 AddCtrlId |
| 控件 ID 分散在程式碼各處 | 初始化時集中宣告,一目了然 |
| 難以動態增減分頁控件 | 支援運行時 Add/Delete |
CTabContainer 將「分頁-控件」對應關係資料化,以最小程式碼解決 TabCtrl 分組顯示的維護難題。專案中可直接複製使用,或依需求擴充(如支援巢狀 Tab、動態建立控件等)。