2013-01-03 154 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

相關問題