gpt4 book ai didi

c++ - 为什么拥有窗口显示在拥有窗口上方?

转载 作者:可可西里 更新时间:2023-11-01 10:10:51 25 4
gpt4 key购买 nike

我有一个非常奇怪的问题。我正在尝试复制一个窗口层次结构。因此,在创建一级对话框时,我启动了二级对话框的实例。

我已经用很多不同的方式做到了这一点,但它总是显示为第 2 级低于第 1 级,然后通常会发生 zorder 反转(它们翻转位置)。偶尔,反转不会发生,但如果我点击所有者,拥有者立即跳到 zorder 的顶部。

下面是一个小例子的主要部分来展示这种情况:

const unsigned short WMA_DIALOGACTION        = WM_APP+1;
// Button event handler for the 0th level
void CdialogcallingdialogsDlg::OnBnClickedDlgLvl1()
{
CDlgLvl1 x(this);
x.DoModal();
}
BEGIN_MESSAGE_MAP(CDlgLvl1, CDialogEx)
ON_WM_WINDOWPOSCHANGED()
ON_MESSAGE(WMA_DIALOGACTION, OnDialogAction)
END_MESSAGE_MAP()

void CDlgLvl1::OnWindowPosChanged(WINDOWPOS* lpwndpos)
{
if (!m_shownDlg) {
m_shownDlg = true;
PostMessage(WMA_DIALOGACTION);
}
}

// Level 1 dialog opening up level 2 dialog
LRESULT CDlgLvl1::OnDialogAction(WPARAM wParam, LPARAM lParam)
{
ShowWindow(SW_SHOW);
CDlgLvl2 x(this);
x.DoModal();
return LRESULT();
}
BEGIN_MESSAGE_MAP(CDlgLvl2, CDialogEx)
ON_WM_WINDOWPOSCHANGING()
END_MESSAGE_MAP()

// Level 2 dialog offseting its position
void CDlgLvl2::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
ASSERT(lpwndpos->hwnd == m_hWnd);
// Offset dialog to see the problem of dlg2 showing up below dlg1
if (!(lpwndpos->flags & SWP_NOMOVE)) {
lpwndpos->x += 10;
lpwndpos->y += 10;
}
}

在示例中,您单击主对话框中的按钮。然后启动 CDlgLvl1,然后启动 CDlgLvl2。这些对话框是默认对话框,除了此处显示的消息处理和主应用程序对话框上的按钮。如果你仔细看,你可以看到反转。

我做错了什么?也许有更好的方法来做到这一点?

如果有所不同,该问题在 Windows 10 下更为明显,并且在 Windows 8.1 上似乎不可见。

可以从我的 git 存储库中提取解决方案的拷贝:

https://github.com/Ma-XX-oN/dialog-calling-dialogs.git

我刚刚在对话框中添加了一些位图来真正显示问题,但我还没有在我的 8.1 机器上进行测试。

我记录了它是如何弹出的,这是该记录的第 0、2 和 3 帧:

第 0 帧 frame-0

第 2 帧 frame-2

第 3 帧 frame-3

如您所见,在第 2 帧中 LVL1 出现在 LVL2 之上,然后在第 3 帧中翻转位置。

可以找到完整视频here .

使用这个示例项目,我无法复制 LVL1 并保持在 LVL2 之上,但我相信没有发生 zorder 反转的行为是某种竞争条件。

最佳答案

此问题是在启用 Windows“过渡动画”时引起的。 WM_WINDOWPOSCHANGED 在动画结束前发送。

要解决此问题,您可以简单地禁用对话框的转换:

BOOL CDlgLvl2::OnInitDialog()
{
BOOL res = CDialogEx::OnInitDialog();
BOOL attrib = TRUE;
DwmSetWindowAttribute(m_hWnd, DWMWA_TRANSITIONS_FORCEDISABLED, &attrib, sizeof(attrib));
return res;
}


如果您不想禁用转换,则必须等到此转换完成。我不知道如何检测它或如何确定过渡时间。好像是250毫秒。 SystemParametersInfo(SPI_SETMENUSHOWDELAY...) 给出了 400 毫秒的值,这似乎有点太长了。

假设我们知道时间,在转换结束后使用 SetTimer 运行函数:

BOOL CDlgLvl2::OnInitDialog()
{
BOOL res = CDialogEx::OnInitDialog();
ANIMATIONINFO info = { sizeof info };
SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &info, 0);
if (info.iMinAnimate)
SetTimer(1, 250, nullptr);
else
SetTimer(1, 1, nullptr);
return res;
}

void CDlgLvl2::OnTimer(UINT_PTR nIDEvent)
{
CDialogEx::OnTimer(nIDEvent);
if(nIDEvent == 1)
{
KillTimer(nIDEvent);
CDlgLvl2(this).DoModal();//note, PostMessage is not needed in SetTimer
}
}

关于c++ - 为什么拥有窗口显示在拥有窗口上方?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57066678/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com