在 VS2008 MFC 專案中引入 Skin++ 庫實現動態換膚時,主視窗與大部分控件外觀更新正常,但按鈕等部分控件未即時刷新,必須將滑鼠游標移至按鈕上方觸發 WM_PAINT 才會套用新皮膚。
Skin++ 套用新皮膚後,僅對主視窗發送重繪訊息,子控件(如 CButton)未主動使其客戶區失效,導致舊外觀殘留。
在換膚完成後,手動枚舉視窗所有子控件,呼叫 InvalidateRgn 與 UpdateWindow 強制立即重繪:
// 範例碼:在換膚函式結束處加入
void CMyDialog::OnSkinChanged()
{
// ... 原換膚邏輯 ...
// 遞迴或迴圈取得所有子視窗句柄
HWND hWndChild = ::GetWindow(m_hWnd, GW_CHILD);
while (hWndChild)
{
// 使整個客戶區失效
::InvalidateRgn(hWndChild, NULL, TRUE);
// 立即處理 WM_PAINT
::UpdateWindow(hWndChild);
hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT);
}
}
InvalidateRgn(hwnd, NULL, TRUE):將整個客戶區標記為需重繪,TRUE 表示同時清除背景。UpdateWindow(hwnd):繞過訊息佇列,直接發送 WM_PAINT,確保即時見效。RefreshSkin() 方法,統一管理。第三方換膚庫常忽略子控件同步更新,開發者需在換膚流程末端補上全控件 InvalidateRgn + UpdateWindow,即可徹底解決按鈕、編輯框等控件「滑鼠經過才變色」的尷尬。