我不确定为什么我会得到这个视觉神器?
下面是重现的方法:
我正在使用Visual Studio 2017社区。创建新的C++ -> MFC项目:

然后指定“基于对话”:

然后构建为“调试”x86应用程序并运行它。
所以我在Windows10上运行它。
当这个基于对话框的过程具有焦点时,它看起来就像我所期望的那样:

但是,如果我将键盘焦点切换到其他应用程序(通过单击它),这个基于对话框的过程仍然保留其标题栏颜色:

我不确定这只是一个视觉问题,还是在窗口消息处理方面有更深层次的混乱。我怎么纠正它呢?(对于较旧的MFC项目,这不是问题。)
发布于 2018-12-14 03:34:38
我设法复制了您的问题,并找到了一个快速解决方案。您需要将WM_ACTIVATE消息处理程序添加到主对话框中,注释掉基类OnActivate,然后像这样修改它:
void CMFCApplication1Dlg::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
//CDialogEx::OnActivate(nState, pWndOther, bMinimized);
// TODO: Add your message handler code here
this->Default();
}CWnd::Default调用需要保持默认按钮的活动/非活动可视化。
发布于 2018-12-15 17:49:30
好吧,虽然我非常欣赏@VuVirt的解决方案,但它并没有完全消除VS2017中默认的基于对话框的解决方案中的所有错误。它解决了标题栏焦点问题,但在继续开发我的项目时,我遇到了另一个bug。所以我从我的评论中复制并粘贴到他的回答中:
这里还是有些混乱。我不确定它是否与这个修复有关。例如:如果你创建了一个按钮,然后在它的处理程序中尝试这样做: CFileDialog d(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_EXPLORER,NULL,this);d.DoModal();打开一个文件选择器对话框。当文件选取器打开时,将其关闭并查看父MFC对话框窗口的标题栏是否恢复活动。在我的例子中,它保持非活动状态,直到我单击Windows任务栏,然后返回到MFC应用程序。
在试着把头撞到墙上看看发生了什么之后,我决定尝试@zett42在对我最初的问题的评论中提出的更早的解决方案(即用CDialog替换CDialogEx ),它起作用了!所有的虫子都不见了!
所以我的结论是:CDialogEx是有buggy的。
解决方法非常简单:当您创建一个新的基于对话框的项目时,使用项目范围内的查找和替换(在“编辑”菜单中),并将所有出现的CDialogEx替换为CDialog。就是这样。(我试着使用VS2017的重构工具来解决这个问题,但是它把它搞乱了,并没有完全取代它。因此,简单的搜索和替换就可以完成这项工作。)
如果你认为没有CDialogEx你会错过一些功能,那么你就不会错过,它所做的(除了引入bug之外)就是在对话框中添加背景图片和颜色。
因此,在微软修复其模板中的那些明显的错误之前,我坚持使用这种方法。
发布于 2018-12-16 04:26:26
这似乎是CDialogImpl::OnActivate和CDialogImpl::OnNcActivate中的一个错误
void CDialogImpl::OnNcActivate(BOOL& bActive) { if (m_Dlg.m_nFlags & WF_STAYACTIVE) bActive = TRUE;if (!m_Dlg.IsWindowEnabled()) bActive = FALSE;} void CDialogImpl::OnActivate(UINT nState,CWnd* pWndOther) { m_Dlg.m_nFlags &= ~WF_STAYACTIVE;CWnd* pWndActive = (nState == WA_INACTIVE)?pWndOther:&m_Dlg;if (pWndActive != NULL) { BOOL bStayActive = (pWndActive->GetSafeHwnd() == m_Dlg.GetSafeHwnd() || pWndActive->SendMessage(WM_FLOATSTATUS,FS_SYNCACTIVE));if (bStayActive) m_Dlg.m_nFlags |= WF_STAYACTIVE;} else { m_Dlg.SendMessage(WM_NCPAINT,1);}}
这意味着当显示CMFCPopupMenu时,CDialogEx能够保持活动状态。
但m_Dlg.SendMessage(WM_NCPAINT, 1)是个可疑电话。用法与WM_NCPAINT的文档不匹配
参数
wParam窗口更新区域的句柄。将更新区域裁剪到窗口框架。
lParam
不使用此参数。
此外,OnNcActivate还具有基于IsWindowEnabled()的覆盖。这似乎是修复OnActivate中早期问题的补丁。但它会在其他地方引发问题,例如在CDialogEx中使用CFileDialog时
建议的解决方案:
修改CDialogEx::OnActivate,使其运行默认过程。或者,将其更改为强制重新绘制。
BOOL CDialogEx::OnNcActivate(BOOL active)
{
if(m_nFlags & WF_STAYACTIVE)
active = TRUE;
return(BOOL)DefWindowProc(WM_NCACTIVATE, active, 0L);
}
void CDialogEx::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
Default();
}或
void CDialogEx::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
Default();
//save the previous flag
UINT previous_flag = m_nFlags;
m_nFlags &= ~WF_STAYACTIVE;
// Determine if this window should be active or not:
CWnd* pWndActive = (nState == WA_INACTIVE) ? pWndOther : this;
if(pWndActive != NULL)
{
BOOL bStayActive = pWndActive->GetSafeHwnd() == GetSafeHwnd() ||
pWndActive->SendMessage(WM_FLOATSTATUS, FS_SYNCACTIVE);
if(bStayActive)
m_nFlags |= WF_STAYACTIVE;
}
if(previous_flag != m_nFlags && previous_flag & WF_STAYACTIVE)
{
//if the flag is changed,
//and if WF_STAYACTIVE was previously set,
//then OnNcActivate had handled it wrongly, do it again
SendMessage(WM_NCACTIVATE, FALSE); //<- less wrong!
}
}例如,这应该适用于CMFCPopupMenu。MFC菜单将打开,但不会停用该对话框。
我不确定SendMessage(WM_FLOATSTATUS, FS_SYNCACTIVE)是用来做什么的,我还没能测试它……如果有必要,似乎可以将代码添加到OnNcActivate上,然后OnActivate就不用管了。
https://stackoverflow.com/questions/53768653
复制相似问题