C++ CDialog:为什么SetParent(this)更改视觉样式?

C++ CDialog:为什么SetParent(this)更改视觉样式?,c++,visual-studio,winapi,visual-c++,mfc,C++,Visual Studio,Winapi,Visual C++,Mfc,我在CView派生类m_wndTestDlg.create(CTestDlg::IDD,this)中创建一个非模态的CDialog并使用以下代码显示/隐藏和移动对话框 h文件: class CTestView : public CView { : CTestDlg m_wndTestDlg; : } cpp文件: void CTestView::OnInitialUpdate() { CView::OnInitialUpdate(); m_wndTest

我在
CView
派生类
m_wndTestDlg.create(CTestDlg::IDD,this)中创建一个非模态的
CDialog
并使用以下代码显示/隐藏和移动对话框

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, 0, 0, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
    }
}

我不明白为什么
SetParent
将视觉样式更改为旧的WinXP样式?

如果
SetParent
的目的是将对话框保持在视图前面,那么以下操作可能会起作用(也可能不起作用,取决于UI的具体情况)。但是,如果原因是将对话框剪裁到父视图,那么这将没有帮助,尽管它仍试图解释原因

这里的主要问题是Windows如何将视觉样式应用于子窗口(子窗口的后代)的不一致性,或者更确切地说,它没有这样做。这个问题不仅限于VC++或MFC,而且已经注意到,,(最后一个链接是dotnet/winforms上的开放案例,但也有参考)。由于此问题,将对话框作为视图的子对象重新设置父对象将“丢失”主题

这里的另一个复杂之处是,所讨论的窗口是一个对话框,而对话框是。只需调用
SetParent
即可更改对话框的父级,但保留其所有者。这违反了我们的规则。此外,要求更新样式位以删除
WS\u弹出窗口
,并添加
WS\u子项
。但是,一旦对话框成为视图的子对象,清除所有者或修复样式位都不会更改样式设置行为

另一种方法是更改对话框的所有者,而不是其父对象,在这种情况下,实际上会应用视觉样式。这将按Z顺序将对话框保持在其所有者面前,但不会将其剪裁到所有者区域。但是,需要注意的是,所有者必须是弹出窗口或重叠窗口,因此不能将其设置为视图本身(即子窗口),而是设置为其最近的弹出/重叠祖先窗口。在具有单个顶级窗口的UI中,这通常意味着只有一个主窗口

下面是示例代码,内联了一些注释,以及不起作用的
#if 0
部分


应用程序是否已启用?是的,我不想在这里意外禁用SetParent的对话视觉样式(此),那么您肯定遇到了与以下问题不同的问题。A会有帮助。@dxlv谢谢链接,不,这是同样的问题。SetParent(此)将CDialog作为CView的子级。有人评论说:这是Windows10的东西,不能改变。他们放弃了保持视觉样式渲染器兼容的尝试,你只能获得传统的Win7外观。或者,这可能有一天会实现。是的,这就解释了问题。然而,这并不能解决我的问题。我对一个文档使用多个视图,并且每个无模式对话框都与特定视图相关联,因此这里强制要求每个对话框都是父视图的子视图。使用带有嵌入CTestDlg的CDockablePane?@TomTomTom问题是,对话框是自有窗口,不能也是子窗口。您仍然可以让他们通过处理
WM\u WINDOWPOSCHANGING
消息来管理自己在Z顺序中的位置,以便将每个对话框保持在其关联视图的顶部。我已尝试使用
WM\u WINDOWPOSCHANGING
来管理它。管理所有条件都是非常复杂和棘手的。而且并不总是像预期的那样工作。我现在终于使用了
CDockablePane
并嵌入了CTestDlg。此解决方法解决了无模式对话框的视觉样式问题。
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, GWLP_HWNDPARENT, (LONG_PTR)::GetAncestor(m_hWnd, GA_ROOT));
#endif
        m_wndTestDlg.SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
    }
}