在我目前正在使用的软件产品中,我们有几个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页面中阅读它),并在屏幕上“跟随”它的移动。正如预期的那样,它有用,但这些问题很难克服。最重要的是裁剪问题。如果所有者控件的父表单更改其大小,则覆盖表单仍会全部显示。在我的示例中,我有一个带有菜单的简单表单和一个包含日历的黑色面板(用于显示子控件与自有控件之间的裁剪差异)。我“奴役”了一个包含黑色面板属性网格的无边界表单。它成功地遵循形式的运动,但如果我缩小的主要形式,我得到这个:
说明如何将日历正确修剪(子窗口),并且覆盖不(独资窗口)。最小化/恢复主窗体时,我也会受到奇怪的影响。事实上,当最小化时,我的叠加层消失,但恢复时,它只是在生成主窗体的恢复动画时“产生”。但这不是一个问题,我想可以通过处理适当的事件(但哪些?)来解决。
根据我的理解,我必须使用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);
}
}
你已经订阅LocationChanged,只是认购ClientSizeChanged还有:每个窗口都可以有一个关联
Region
对象,它定义窗口渲染的限制:使用。摆脱最小化/恢复动画需要禁止DwmSetWindowAttribute()。 –
是的,但如果父窗体大小的变化并不意味着我想改变覆盖的大小:)反正thx为pinvoke提示,我会研究它! – StackOverFlorian