在我目前正在使用的軟件產品中,我們有幾個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