c# - 在另一个窗口之上叠加一个顶层窗口

标签 c# .net winforms winapi

在我目前正在使用的软件产品中,我们有几个3D View控件。似乎需要在这些3D视图之上具有叠加信息。我不会涉及太多的背景细节,因为这不是重点,但这是我们面临的限制:


我们必须使用两个不同的3D视图控件
我们没有他们的源代码
它们嵌入Windows窗体控件中,而我们围绕这些控件的所有GUI都位于Windows窗体中
我们使用.NET Framework 3.5SP1和Windows 7


我们希望能够在这些3D视图之上显示各种叠加信息和控件,因为我们通常通过在大屏幕上显示全屏3D视图来演示我们的产品,而不显示具有必要信息和控件的GUI。

过去,我们仅使用一种类型的3D视图,通过各种涉及反射的黑客,我设法钩住了自己用DirectX编写的覆盖窗口系统(基于WorldWind .NET覆盖小部件,该3D视图确实基于WorldWind时间)。下一个版本的3D View产品对渲染核心代码进行了巨大的更改,并且当然使这些hack不兼容(是的,我知道了,我知道:-)。而且,由于其他产品的需求不同,我们现在也在使用另一种类型的3D视图,即封闭源。

我强调一个事实,我们没有源代码,因为我们无法访问渲染循环,因此无法挂接为3D引擎制作的窗口系统,例如CEGUI(我自己搜索,不允许发布太多超链接,抱歉)。

因此,我有以下想法:由于我们的3D视图嵌入在winforms控件中,为什么我们不将覆盖控件编码为纯Winforms,然后将其覆盖在3D视图之上?该解决方案的优点是巨大的:


这将与两个3D视图都兼容,从而使我们能够在需要时跨引擎重用叠加层
我们将能够重用已经为GUI其余部分开发的自定义控件或表单。确实,这是一个相当大的项目,而且我们开始拥有相当多的此类控件库。


唯一的小问题(!)是我们希望能够管理覆盖层的透明度,就像我在DirectX中使用以前的系统一样。我们负担不起完全不透明的叠加层,因为它会使视图过于混乱。想象一下几乎看不见的覆盖物,例如,当鼠标悬停在其上时,它变得更加不透明。

Windows提供了在其他窗口或控件中添加子窗口的可能性(Win32 API并没有在窗口和控件之间真正发挥作用,据我所知这几乎是MFC / WinForms抽象),但由于它不是顶级的,级别窗口,我们无法调整这些窗口的透明度,因此我们无法使用此功能。我看到了here,但是这在Windows 8上是可行的,但很快就不可能切换到Windows 8,因为我们的软件已部署在许多运行7的计算机上。

因此,我开始了一次激烈的谷歌搜索会议,讨论如何解决该问题。看来我必须将顶级窗口“奴役”到我的3D视图控件中。我已经直接在winforms中尝试了类似的方法,通过控件拥有了一个窗体(没有父窗体,有明显的区别,在先前链接的MS页中对其进行了读取),然后“跟随”它在屏幕上的移动。正如预期的那样,它确实可行,但是这些问题很难克服。最重要的是剪辑问题。如果所有者控件的父窗体更改其大小,则覆盖窗体仍将完整显示。在我的示例中,我有一个带有菜单的简单表单,以及一个包含日历的黑色面板(以显示子控件和自有控件之间的剪切差异)。我将包含属性网格的无边界表单“奴役”到了黑色面板上。它成功地跟随了表单的移动,但是如果我缩小主表单,则会得到以下信息:

Clipping issue screenshot

请注意日历是如何正确裁剪的(子窗口),而叠加层不是(自有窗口)。最小化/还原主要形式时,我也会得到怪异的效果。的确,最小化时我的叠加消失了,但是在还原时,它只是在生成主要形式的还原动画时“生成”。但这不是什么大问题,我想可以通过处理适当的事件来解决(但是哪些事件呢?)。

据我了解,我必须使用Win32 API调用和挂钩至少自己处理一些剪辑。我已经开始记录自己了,但这是相当复杂的内容。 Win32 API真是一团糟,我本人是以前的Unix开发人员,是通过出色的.NET框架引入Windows编程的,我对Win32没有任何实际经验,因此我真的不知道从哪里开始以及如何开始。使自己成为这片丛林中的一条小路...

因此,如果有一个Winapi专家过去了,或者在上述限制下,如果有人有其他想法可以实现我的目标,那么我将很乐意阅读:-)

在此先感谢您,并通过仅提出问题来成为这样的stackoverflow“ leecher”表示歉意,但是我在工作站上没有直接的Internet访问权限(是的,实际上,我必须使用特定的计算机这样),所以对我来说,参加这个大社区并不容易。

最后,这是我的示例代码(如果需要,可以提供设计者代码):

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    Point _myLoc;

    private void formToolStripMenuItem_Click(object sender, EventArgs e)
    {
        var ctrl = new PropertyGrid();
        var obj = this.panel1;
        ctrl.SelectedObject = obj;
        var form = new Form();
        ctrl.Dock = DockStyle.Fill;
        form.Controls.Add(ctrl);
        form.Opacity = 0.7;
        var rect = obj.RectangleToScreen(obj.DisplayRectangle);
        form.StartPosition = FormStartPosition.Manual;
        form.Location = new Point(rect.Left + 10, rect.Top + 10);

        var parentForm = this;
        _myLoc = parentForm.Location;
        form.FormBorderStyle = FormBorderStyle.None;

        parentForm.LocationChanged += (s, ee) => {
            int deltaX = parentForm.Location.X - _myLoc.X;
            int deltaY = parentForm.Location.Y - _myLoc.Y;
            var loc = form.Location;
            form.Location = new Point(loc.X + deltaX, loc.Y + deltaY);
            _myLoc = parentForm.Location;
        };
        form.Show(this.panel1);
    }
}

最佳答案

使用Region属性可以轻松实现剪切。每个窗口可以有一个关联的Region对象,该对象定义了窗口渲染约束:

static void ManualClipping(Control clipRegionSource, Form formToClip)
{
    var rect = clipRegionSource.DisplayRectangle;
    rect = clipRegionSource.RectangleToScreen(rect);
    rect = formToClip.RectangleToClient(rect);
    rect = Rectangle.Intersect(rect, formToClip.ClientRectangle);
    if(rect == formToClip.ClientRectangle)
    {
        formToClip.Region = null;
    }
    else
    {
        formToClip.Region = new Region(rect);
    }
}


用法:

/* ... */
parentForm.SizeChanged += (s, ee) => ManualClipping(panel1, form);
form.Show(this.panel1);

关于c# - 在另一个窗口之上叠加一个顶层窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14139248/

相关文章:

c# - 如何在 VS 2013 中公开托管 WCF 服务

.net - 解析实例 - Autofac

c# - 尝试从 Cosmos DB 中删除时找不到资源

.NET 对缓存项 (DataTable) 的引用

c# - 如何使 Form 和 HWND 相互重新定位?

c# - 单元测试 unityContainer.Resolve

c# - 为 Azure Function (v3) 的 RequestTelemetry 添加自定义属性

c# - 如何从 C# 中的 SQL 查询结果填充类?

c# - 在Winforms中,从不为任何键触发PreviewKeyDown()

c# - Asp.Net 4.5 Web API - 返回 HTTP 状态代码 207