2013-01-03 110 views
2

在我目前正在使用的软件产品中,我们有几个3D视图控件。出现需要在这些3D视图之上叠加信息的情况。我不会去考虑太多的背景细节,因为这不是重点,但这里有我们所面临的制约因素:将顶层窗口重叠在另一个顶层窗口

  • 我们必须使用两种不同的3D视图控件
  • 我们没有源
  • 它们嵌入在Windows中为他们的代码窗体控件,并围绕这些控制所有我们自己的图形用户界面在Windows窗体
  • 我们使用的.NET Framework 3.5SP1和Windows 7

我们希望能够显示各种ov因为我们通常通过在大屏幕上显示全屏3D视图来演示我们的产品,而不显示我们的GUI,它们具有必要的信息和控制。在我们只使用一种类型的3D视图的日子里,我通过各种涉及反射的黑客手段管理我自己的覆盖窗口系统(基于WorldWind .NET覆盖小部件,3D视图确实如此)。基于WorldWind当时)。 3D View产品的下一个版本对渲染核心代码进行了巨大改动,当然这些攻击是不兼容的(是的,我知道了,我知道:-))。而且,由于其他产品的不同需求,我们现在正在使用另一种类型的3D视图,即闭源。

我强调我们没有它们的源代码,因为我们无法访问渲染循环,因此无法挂钩3D引擎的窗口系统,例如CEGUI(自己搜索它,我不允许发布太多的超链接,对不起)。因此,我有以下想法:由于我们的3D视图嵌入在winforms控件中,为什么我们不将代码覆盖控件编写为纯winforms,并将其覆盖在3D视图的顶部?该解决方案的优势是巨大的:

  • 这将是既3D视图兼容,使我们能够跨越引擎重用叠加,如果需要的话
  • ,我们将能够重复使用,我们已经为开发定制控件或窗体GUI的其余部分。的确,这是一个相当大的项目,我们开始拥有相当多的这样的控制库。

唯一的问题是我们希望能够管理覆盖层的变化,就像我在DirectX中使用我以前的系统一样。我们买不起完全不透明的叠加层,因为它会混淆视图太多。想象一下,像是几乎看不见的覆盖层,当鼠标悬停在它上面时变得更加不透明。 Windows提供了在其他窗口或控件内部使用子窗口的可能性(Win32 API并没有真正在窗口和控件之间做出区别,这是我理解的非常多的MFC/WinForms抽象),但是由于它不是顶级窗口,我们无法调整这些的流畅性,所以这不是我们可以使用的。我看到了here,但是这在Windows 8上是可行的,但是很快就不可能切换到Windows 8,因为我们的软件部署在不少机器上,运行着7个。我怎么能解决这个问题。看来我必须将顶级窗口“奴役”到我的3D视图控件。我已经通过一个控件在窗体中直接尝试了类似的东西,拥有一个窗体(不是父元素,有明确的区别,在先前链接的MS页面中阅读它),并在屏幕上“跟随”它的移动。正如预期的那样,它有用,但这些问题很难克服。最重要的是裁剪问题。如果所有者控件的父表单更改其大小,则覆盖表单仍会全部显示。在我的示例中,我有一个带有菜单的简单表单和一个包含日历的黑色面板(用于显示子控件与自有控件之间的裁剪差异)。我“奴役”了一个包含黑色面板属性网格的无边界表单。它成功地遵循形式的运动,但如果我缩小的主要形式,我得到这个:

Clipping issue screenshot

说明如何将日历正确修剪(子窗口),并且覆盖不(独资窗口)。最小化/恢复主窗体时,我也会受到奇怪的影响。事实上,当最小化时,我的叠加层消失,但恢复时,它只是在生成主窗体的恢复动画时“产生”。但这不是一个问题,我想可以通过处理适当的事件(但哪些?)来解决。

根据我的理解,我必须使用win32 API调用和钩子来处理至少一些裁剪。我已经开始记录自己,但这是相当复杂的东西。 Win32 API是一个真正的混乱,我自己是一位前Unix开发人员通过伟大的.NET框架介绍给Windows编程,我没有任何真正的经验在Win32,因此不知道从哪里开始,以及如何让自己成为这个丛林中的一条小路...

所以如果一个winapi古鲁正在路过,或者如果有人有其他想法来实现我的目标,我会很乐意阅读它: - )

在此先感谢,并通过订阅只提问一个这样的stackoverflow“leecher”道歉,但我没有在我的工作站上直接访问互联网(是的,真的,我必须去这个特定的计算机),所以参与这个伟大的社区对我来说并不是那么容易。

最后,这里是(可设计的代码,如果你问)我的示例代码:

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); 
    } 
} 
+0

你已经订阅LocationChanged,只是认购ClientSizeChanged还有:每个窗口都可以有一个关联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); } } 

使用。摆脱最小化/恢复动画需要禁止DwmSetWindowAttribute()。 –

+0

是的,但如果父窗体大小的变化并不意味着我想改变覆盖的大小:)反正thx为pinvoke提示,我会研究它! – StackOverFlorian

回答

1

裁剪可以使用Region财产可以轻松实现。所以你知道什么时候调整覆盖

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

非常好,这很好(至少在我的示例中),谢谢! – StackOverFlorian

相关问题