基于CWinAppEx的MFC程序休眠后恢复时菜单工具栏尺寸异常
MFC应用休眠后恢复最小化窗口时菜单栏尺寸异常的解决方法
针对你遇到的MFC应用在系统休眠后,恢复最小化窗口时菜单栏尺寸异常的问题,以下是几种针对性的解决思路和实现方案:
1. 在窗口状态变更时强制菜单栏重布局
利用WM_WINDOWPOSCHANGED消息(覆盖窗口位置、大小、显示状态变化的所有场景,包括休眠后的状态切换),在窗口从最小化恢复时强制菜单栏重新计算布局:
void CMainFrame::OnWindowPosChanged(WINDOWPOS* lpwndpos) { CFrameWndEx::OnWindowPosChanged(lpwndpos); // 判断是否是从最小化状态恢复显示 if ((lpwndpos->flags & SWP_SHOWWINDOW) && (GetPrevWindowPlacement()->showCmd == SW_SHOWMINIMIZED)) { if (m_wndMenuBar.GetSafeHwnd()) { // 强制菜单栏重新布局 m_wndMenuBar.LayoutMenuBar(); // 让主框架重新计算客户区及子控件位置 RecalcLayout(); } } }
注意:需要在主框架类的消息映射中添加ON_WM_WINDOWPOSCHANGED()宏。
2. 监听系统电源广播消息,提前处理状态
通过捕获WM_POWERBROADCAST消息,在系统休眠前保存菜单栏状态,恢复时针对性刷新:
首先在消息映射中添加ON_MESSAGE(WM_POWERBROADCAST, OnPowerBroadcast),然后实现处理函数:
// 主框架类中添加成员变量:CRect m_menuRect; BOOL m_bNeedMenuRefresh = FALSE; LRESULT CMainFrame::OnPowerBroadcast(WPARAM wParam, LPARAM lParam) { switch (wParam) { case PBT_APMRESUMEAUTOMATIC: // 系统从休眠自动恢复,若当前窗口是最小化状态,标记需要刷新菜单栏 if (IsIconic()) { m_bNeedMenuRefresh = true; } break; case PBT_APMSUSPEND: // 系统即将休眠,保存当前菜单栏的尺寸信息 if (m_wndMenuBar.GetSafeHwnd()) { m_wndMenuBar.GetWindowRect(m_menuRect); } break; } return CFrameWndEx::OnPowerBroadcast(wParam, lParam); } // 再在WM_SHOWWINDOW消息中处理刷新 void CMainFrame::OnShowWindow(BOOL bShow, UINT nStatus) { CFrameWndEx::OnShowWindow(bShow, nStatus); if (bShow && m_bNeedMenuRefresh) { CRect clientRect; GetClientRect(clientRect); // 重置菜单栏宽度为客户区宽度,高度沿用休眠前的数值 m_wndMenuBar.SetWindowPos(nullptr, 0, 0, clientRect.Width(), m_menuRect.Height(), SWP_NOMOVE | SWP_NOZORDER); m_wndMenuBar.LayoutMenuBar(); RecalcLayout(); m_bNeedMenuRefresh = false; } }
3. 调整菜单栏的布局缓存策略
部分场景下MFC菜单栏的布局缓存会在休眠后失效,可通过修改菜单栏样式强制动态布局:
BOOL CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (!CFrameWndEx::OnCreate(lpCreateStruct)) return FALSE; // 初始化菜单栏后,设置动态尺寸样式 m_wndMenuBar.SetMenuBarStyle(CBRS_TOP | CBRS_SIZE_DYNAMIC); // 禁用可能导致缓存的静态尺寸样式 // m_wndMenuBar.SetMenuBarStyle(m_wndMenuBar.GetMenuBarStyle() & ~CBRS_SIZE_FIXED); return TRUE; }
4. 强制窗口全局重绘
若以上方案均无效,可在窗口激活时强制触发全局重绘和非客户区计算:
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) { CFrameWndEx::OnActivate(nState, pWndOther, bMinimized); // 当窗口从最小化状态激活时,强制重绘 if (nState == WA_ACTIVE && IsIconic()) { Invalidate(); UpdateWindow(); // 强制重新计算非客户区(包含菜单栏)的尺寸 SendMessage(WM_NCCALCSIZE, TRUE, 0); } }
注意:需添加ON_WM_ACTIVATE()消息映射宏。
内容的提问来源于stack exchange,提问作者Spencer Manwell
相关产品推荐
相关产品推荐

