MFC实现主窗口与所属非模态对话框标题栏同步激活显示
实现MFC主窗口与非模态对话框同步激活样式
核心思路
Windows系统同一时间仅允许一个窗口处于激活状态,但我们可以通过手动控制窗口的非客户区(标题栏属于此区域)绘制逻辑,模拟出应用内任意窗口激活时,所有窗口标题栏均显示激活样式;应用失活时,所有窗口标题栏同步失活的效果。关键是通过全局状态标记应用激活状态,并重写窗口的非客户区激活消息处理。
具体实现步骤
1. 定义全局激活状态标记
在项目公共头文件中定义全局变量,标记当前应用的激活状态:
// 全局变量,标记应用是否处于激活状态 bool g_bAppActive = true; // 程序启动时主窗口默认激活,初始化为true
2. 重写主窗口的激活相关消息处理
在主窗口类(如CMainFrame)中处理WM_ACTIVATE、WM_NCACTIVATE、WM_ACTIVATEAPP消息:
处理WM_ACTIVATE消息
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CFrameWnd::OnActivate(nState, pWndOther, bMinimized); if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) { g_bAppActive = true; // 同步刷新非模态对话框的非客户区为激活样式 if (m_pModelessDlg && m_pModelessDlg->IsWindowVisible()) { m_pModelessDlg->SendMessage(WM_NCACTIVATE, TRUE); } } else { // 检查对话框是否仍处于激活状态,避免误设应用为失活 if (!(m_pModelessDlg && ::GetActiveWindow() == m_pModelessDlg->GetSafeHwnd())) { g_bAppActive = false; if (m_pModelessDlg && m_pModelessDlg->IsWindowVisible()) { m_pModelessDlg->SendMessage(WM_NCACTIVATE, FALSE); } } } }
处理WM_NCACTIVATE消息
覆盖默认的非客户区激活逻辑,使用全局状态标记决定显示样式:
BOOL CMainFrame::OnNcActivate(BOOL bActive) { // 忽略系统传入的激活状态,改用应用全局激活标记 return CFrameWnd::OnNcActivate(g_bAppActive); }
处理WM_ACTIVATEAPP消息
当整个应用被切换到后台/前台时,同步更新所有窗口的样式:
void CMainFrame::OnActivateApp(BOOL bActive, DWORD dwThreadID) { CFrameWnd::OnActivateApp(bActive, dwThreadID); g_bAppActive = bActive; // 刷新自身非客户区样式 SendMessage(WM_NCACTIVATE, bActive); // 同步刷新对话框样式 if (m_pModelessDlg && m_pModelessDlg->IsWindowVisible()) { m_pModelessDlg->SendMessage(WM_NCACTIVATE, bActive); } }
3. 重写非模态对话框的激活相关消息处理
在对话框类(如CMyModelessDlg)中处理WM_ACTIVATE和WM_NCACTIVATE消息:
处理WM_ACTIVATE消息
void CMyModelessDlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CDialogEx::OnActivate(nState, pWndOther, bMinimized); if (nState == WA_ACTIVE || nState == WA_CLICKACTIVE) { g_bAppActive = true; // 同步刷新主窗口的非客户区为激活样式 CWnd* pMainWnd = AfxGetMainWnd(); if (pMainWnd && pMainWnd->IsWindowVisible()) { pMainWnd->SendMessage(WM_NCACTIVATE, TRUE); } } else { // 检查主窗口是否仍处于激活状态,避免误设应用为失活 CWnd* pMainWnd = AfxGetMainWnd(); if (!(pMainWnd && ::GetActiveWindow() == pMainWnd->GetSafeHwnd())) { g_bAppActive = false; if (pMainWnd && pMainWnd->IsWindowVisible()) { pMainWnd->SendMessage(WM_NCACTIVATE, FALSE); } } } }
处理WM_NCACTIVATE消息
BOOL CMyModelessDlg::OnNcActivate(BOOL bActive) { // 忽略系统传入的激活状态,改用应用全局激活标记 return CDialogEx::OnNcActivate(g_bAppActive); }
4. 注意事项
- 非模态对话框创建时,必须指定主窗口为拥有者,确保窗口归属关系正确:
m_pModelessDlg = new CMyModelessDlg(); m_pModelessDlg->Create(IDD_MODELESS_DLG, this); // this为主窗口指针 m_pModelessDlg->ShowWindow(SW_SHOW); - 确保全局变量
g_bAppActive的初始化值与程序启动状态一致,避免初始样式错误。
内容的提问来源于stack exchange,提问作者xMRi
相关产品推荐
相关产品推荐

