【问题标题】:Creating a Transparent Child window on top of non-transparent Parent Window (win32)在非透明父窗口之上创建一个透明子窗口(win32)
【发布时间】:2012-05-09 09:51:32
【问题描述】:

我有一个不是我写的程序。我没有它的来源,该程序的开发人员正在独立开发。他给了我那个程序的HWNDHINSTANCE 句柄。

我在他的窗口上创建了一个子窗口,使用win32 api。

我需要做的第一件事是让这个子窗口在某些区域具有透明性,而在其他区域不透明(例如游戏的平视显示器 (HUD)),以便用户可以在两个窗口中看到内容。

我需要的第二件事是将所有输入定向到父窗口。我的子窗口不需要输入。

我知道WS_EX_TRANSPARENT 只会让孩子像画家算法一样在最后绘制。

我不能使用WS_EX_LAYERED,因为它是一个子窗口。

附言

我到处寻找,但没有找到任何解决方案,尽管互联网上有类似的问题。

实际上,这是一款类似于 HUD 的游戏。由于多线程的复杂性以及其他许多原因,我无法直接在父窗口上绘制。

-- 编辑---------------

我仍在努力。我正在尝试不同的方式与你们所有人的建议。有没有办法将directXSetWindowRgn() 函数或directxBitBlt() 函数结合起来?我认为这会奏效。目前我正在测试所有的东西作为一个子窗口和一个分层窗口。

【问题讨论】:

  • 它很难看,但是您可以在窗口上方创建一个顶级框架并跟踪下方窗口的移动。然后设置透明区域:codeguru.com/cpp/w-d/dislog/non-rectangulardialogs/article.php/…
  • 如果你让窗口透明,那只会让你看到父窗口。你想在父窗口上打个洞吗?
  • 好吧,你至少需要 WS_EX_TRANSPARENT。您必须处理的一个问题是作者将在 WM_ERASEBKGND 消息上擦除他的窗口,这将消除您从样式标志中获得的背景像素。因此,您需要继承他的窗口过程并抑制或替换该消息。使用 WM_PAINT 绘制的内容是否仍然有效是一个悬而未决的问题,您需要自己找出答案。如果它包含任何具有抗锯齿边缘的文本或图形,则几率很低。鉴于成功的几率很低,作为评论发布。
  • @HansPassant,WS_EX_TRANSPARENT 是最令人困惑的窗口样式之一。它不会使窗口透明,它只是改变渲染顺序。
  • 是的,它也使命中测试透明..而不是可见性..呵呵

标签: c++ windows winapi


【解决方案1】:

好的朋友们,最后我做了一些疯狂的事情来实现它。但是效率不是很高,比如直接用DirectX画图。

我反对:

  • CreateWindowEx 上使用(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_ TOOLWINDOW)()
  • 创建窗口后,从窗口样式中删除(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE),并从扩展窗口样式中删除(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_APPWINDOW)
  • 这给了我一个没有边框的窗口,它现在也显示在任务栏中。 hittest 也会传递给我窗户后面的任何东西。
  • 子类化另一个窗口的窗口过程并得到
    • WM_CLOSE,WM_DESTROY,分别发送WM_CLOSEWM_DESTROY到我的窗口
    • WM_SIZE,WM_MOVE,根据另一个窗口调整和移动我的窗口
    • WM_LBUTTONUP,WM_RBUTTONUP,WM_MBUTTONUP,使我的窗口被带到顶部,并且仍然保持焦点在另一个窗口上,这样我的窗口就不会隐藏在另一个窗口后面
  • 使 DirectX 设备有两个通道:
    • 在第一遍中,它在白色背景上绘制黑色的所有元素,并将后缓冲数据复制到另一个表面(因此它给出了黑白的二进制图像)。
    • 在第二遍中,它会正常绘制事物。
  • 使用SetWindowRgn() 函数创建另一个线程,通过读取黑白表面来保持窗口透明。

这很好用,唯一的问题是它不太擅长让事情变得透明。

另一个问题是对绘制的对象进行 alpha 混合。

但您可以使用 SetLayeredWindowAttributes() 函数轻松设置总 alpha(透明度)。

感谢你们提供的所有帮助,你们告诉我的所有东西都被使用了,他们指导了我,正如你所看到的。 :)

遗憾的是,由于效率问题,我们决定不使用这种方法:(

但我学到了很多东西,这是一次很棒的经历。这对我来说很重要:)

谢谢你:)

【讨论】:

    【解决方案2】:

    在 Windows 8 及更高版本中,您可以将 WS_EX_LAYERED 用于 child windows

    要支持早期版本的窗口,只需创建一个水平分层窗口作为弹出窗口(无镶边)并确保其位于游戏窗口上方的适当位置。大多数用户不会一直移动他们正在使用的窗口,因此,虽然您需要监控父窗口的移动并重新定位 HUD,但这不应该成为显示停止器。

    不获取焦点(在子窗口的情况下)或激活(在弹出窗口的情况下)更有趣,但仍然相当可行:- 操作系统实际上不会自动分配焦点,或激活,到单击的窗口 - Windows WindowProc 始终通过调用SetFocusSetActiveWindowSetForegroundWindow 的某些变体来获取焦点或激活。这里重要的是,如果您使用所有鼠标和非客户端鼠标消息而不将它们传递给 DefWindowProc,那么您的 HUD 将永远不会因为单击而从游戏窗口中窃取激活或键盘焦点。

    作为弹出窗口或另一个线程上的窗口,您可能必须手动处理您的窗口 proc 收到的任何鼠标消息,并将它们发布到游戏窗口。否则,使用HTTRANSPARENT 响应WM_NCHITTEST(与WS_EX_TRANSPARENT 实现的效果类似)可以让系统继续将鼠标消息向下传递到堆栈,直到找到目标。

    【讨论】:

      【解决方案3】:

      您可以使用SetWindowRgn 在父窗口中打一个洞。

      另外,仅仅因为它不是你的窗口并不意味着你不能让它成为一个分层的窗口。

      http://msdn.microsoft.com/en-us/library/ms997507.aspx

      最后,您可以通过使用子类来控制另一个窗口 - 本质上,您用您的 Wndproc 代替他们的,来处理您希望处理的消息,然后将剩余部分传递给他们原来的 wndproc。

      【讨论】:

      • SetWindowRgn() 只是让屏幕在屏幕仪式的某个部分上绘制?我试过了,它可以帮助我。谢谢。 :)
      • 我之前看过那个链接,也试过了。但我担心如果它会以其他方式影响该程序(游戏)怎么办。所以我尽量不改变那个窗口,只是获取他的句柄和其他信息并操纵我的窗口。也感谢你的想法:)
      猜你喜欢
      • 2013-02-21
      • 2011-04-27
      • 1970-01-01
      • 2019-04-24
      • 2016-03-03
      • 1970-01-01
      • 2010-10-21
      • 2018-07-08
      • 2011-05-31
      相关资源
      最近更新 更多