傳統換膚需逐個控件映射變量、調用 SubclassDlgItem,工程大時維護極其痛苦。本方案採用運行時自動掃描對話框子控件、按類別/樣式動態子類化,實現零侵入式換膚。
class CLxpSkin {
public:
CLxpSkin(HWND hDlg); // 一個實例對應一個對話框
~CLxpSkin();
// 各類美化控件鏈表
CList<CXPButton*, CXPButton*> m_btnList;
CList<CEditEx*, CEditEx*> m_edtList;
CList<CLineStatic*, CLineStatic*> m_lineList;
CList<CFlatComboBox*, CFlatComboBox*> m_cmbList;
CList<CExCheckBox*, CExCheckBox*> m_chkList;
CList<CExGroupBox*, CExGroupBox*> m_grpList;
// 靜態映射表:HWND -> CLxpSkin*
static CMap<HWND, HWND, CLxpSkin*, CLxpSkin*> m_mapSkin;
static BOOL InstallSkin(HWND hDlg); // 安裝皮膚
static void UnInstallSkin(HWND hDlg); // 卸載皮膚
private:
HWND m_hDlg;
};
在對話框類中:
BOOL CMyDlg::OnInitDialog() {
CDialog::OnInitDialog();
CLxpSkin::InstallSkin(m_hWnd); // 一行代碼全搞定
return TRUE;
}
void CMyDlg::OnDestroy() {
CLxpSkin::UnInstallSkin(m_hWnd); // 清理
CDialog::OnDestroy();
}
CLxpSkin 實例,存入靜態 m_mapSkin。GetWindow(hDlg, GW_CHILD) 遍歷所有子控件。GetClassName 獲取類名,GetWindowLong(GWL_STYLE) 獲取樣式。SubclassWindow:CEditExBS_DEFPUSHBUTTON/BS_PUSHBUTTON → CXPButtonBS_AUTOCHECKBOX/BS_CHECKBOX → CExCheckBoxBS_GROUPBOX → CExGroupBoxSS_ETCHEDHORZ) → CLineStatic (分割線美化)CFlatComboBoxdelete 釋放。void CLxpSkin::UnInstallSkin(HWND hDlg) {
CLxpSkin* pSkin = NULL;
if (m_mapSkin.Lookup(hDlg, pSkin)) {
delete pSkin; // 析構函數會遞刪所有子類化控件
pSkin = NULL;
}
}
InstallSkin 判斷邏輯與鏈表。UnInstallSkin 恢復原生控件外觀與行為。