如何解决CDialog:为什么 SetParent(this) 改变视觉样式?
我在 CDialog
派生类 CView
中创建了一个非模态 m_wndTestDlg.Create(CTestDlg::IDD,this);
并使用以下代码显示/隐藏并移动对话框
h 文件:
class CTestView : public CView
{
:
CTestDlg m_wndTestDlg;
:
}
cpp 文件:
void CTestView::OnInitialUpdate()
{
CView::OnInitialUpdate();
m_wndTestDlg.Create(CTestDlg::IDD,this);
}
void CTestView::OnDialog1()
{
BOOL b = m_wndTestDlg.IsWindowVisible();
if (b)
m_wndTestDlg.ShowWindow(SW_HIDE);
else {
m_wndTestDlg.ShowWindow(SW_SHOW);
// if (!m_wndTestDlg.IsWindowVisible()) { // still not viewable,outside ParentScreen,move to top of CView
m_wndTestDlg.SetParent(this);
m_wndTestDlg.SetWindowPos(&CWnd::wndTop,SWP_NOSIZE | SWP_SHOWWINDOW);
}
}
我不明白为什么 SetParent
将视觉样式更改为旧的 WinXP 样式?
解决方法
如果 SetParent
的别有用心是将对话框保留在视图前面,那么以下可能有效(也可能无效,取决于 UI 细节)。但是,如果原因是将对话框剪辑到父视图,那么这将无济于事,尽管它仍然试图解释原因。
这里的主要问题是 Windows 如何将视觉样式应用于子窗口(的后代)不一致,或者更确切地说是不这样做。该问题不仅限于 VC++ 或 MFC,并且已注意到 [1]、[2]、[3]、[4](最后一个链接是 dotnet/winforms 上的未决案例,但还引用了 MFC)。由于这个问题,将对话框重新设置为视图的子级会“丢失”主题。
这里的另一个复杂问题是所讨论的窗口是一个对话框,而对话框是 owned windows。只需调用 SetParent
即可更改对话框的父级,但将所有者保留在原位。这违反了 A window can have a parent or an owner but not both 的规则。此外,SetParent
要求更新样式位以移除 WS_POPUP
并添加 WS_CHILD
。然而,一旦对话框成为视图的子级,无论是清除所有者还是修复样式位都不会改变样式行为。
另一种方法是更改对话框的所有者,而不是其父级,在这种情况下,视觉样式实际上会得到应用。这会将对话框按 Z 顺序保持在其所有者的前面,但不会将其剪辑到所有者区域。然而,需要注意的是,所有者必须是弹出窗口或重叠窗口,因此不能将其设置为视图本身,即子窗口,而是设置为其最近的弹出窗口/重叠祖先。在具有单个顶级窗口的 UI 中,这通常意味着一个且唯一的主窗口。
示例代码如下,内联了一些注释,以及 不 工作的 #if 0
部分。
void CTestView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// dialog gets created with parent = desktop window
// owner = app main window
m_wndTestDlg.Create(IDD_ABOUTBOX,this);
// visual styles *are* applied at this point
m_wndTestDlg.ShowWindow(SW_SHOW);
}
void CTestView::OnDialog1()
{
if (m_wndTestDlg.IsWindowVisible())
{ m_wndTestDlg.ShowWindow(SW_HIDE); }
else
{
#if 0 // visual styles *not* applied to test dialog
// the following make re-parenting consistent with the rules
// but visual styles are still not applied
// ::SetWindowLongPtr(m_wndTestDlg.m_hWnd,GWLP_HWNDPARENT,NULL);
// m_wndTestDlg.ModifyStyle(WS_POPUP | WS_CHILD,WS_CHILD);
m_wndTestDlg.SetParent(this);
#else // visual styles *are* applied to test dialog
// for an owned window,the following sets the owner,not the parent
// the new owner must be ws_popup or ws_overlapped,thus ga_root
::SetWindowLongPtr(m_wndTestDlg.m_hWnd,(LONG_PTR)::GetAncestor(m_hWnd,GA_ROOT));
#endif
m_wndTestDlg.SetWindowPos(&CWnd::wndTop,SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。