2013-07-28 49 views
1

正如標題所述,是否有可能/如何創建自定義窗口來繪製?通常情況下,你只需要使用一個窗體和表單控件,但是我希望自己的窗口具有一個可以掛鉤並處理繪製事件等的句柄。這可能嗎?從本質上講,我只需要一個容器來存放我的程序的圖像,而不是一個Form。如果不在VB.Net中,是否可以在C#中使用?如何在VB.net中創建自定義窗口(不是表單對象)?

編輯: 我只是不是很喜歡窗口如何繪製(即使對繪畫事件的控制)。我刪除了窗體邊框和控件欄,並用我自己的函數(放置最大/最小/退出按鈕,標題,窗體邊框和尺寸等)替換它們,所以我使用的窗體基本上只是一個浮動面板 - 雖然內置掛鉤,當然很好。但形式依然閃爍過多,所以我想自己處理所有事情。我在所有使用的控件上使用doublebuffering,我使用setbounds來移動/調整控件的大小,而不是單獨設置寬度/高度(減少一些閃爍)。我在窗體的繪畫事件中繪製窗體邊框,其餘部分繪製爲控件(包括窗體的頂部欄)。

我大多討厭我擴展窗體時看到的黑盒子(通常在縮小窗口大小時看不到,但仍有一些閃爍)。另一種方法,或許是一種不同的繪製方式(在VB 2010中)或者其他的方法,我猜也可以。

編輯(再次): 不管窗體上有多少個控件,都會發生黑框問題。如果我嘗試手動調整它的大小(從表單繼承的下面發佈的自定義空表單控件),在單擊和拖動事件期間在每個鼠標移動過程中使用setbounds(不會在沒有預期的情況下發生,所以我知道它沒有運行超過它必須)。

EDIT(代碼):沒有控制 http://img211.imageshack.us/img211/900/j9c.png 因此,即使在空白的「SimpleForm」(如張貼在第一個答案「),當調整爲較大(在PIC,調整東北),黑匣子在那裏的形式將畫繪製的ControlStyles/backbuffering做,張貼在第二個答案,以及張貼漢斯的CreateParams這是我用來設置形式界限:。

Protected Overrides ReadOnly Property CreateParams() As CreateParams 
    Get 
     Dim cp As CreateParams = MyBase.CreateParams 
     cp.ExStyle = cp.ExStyle Or &H2000000 
     cp.Style = cp.Style Or &H2000000 
     Return cp 
    End Get 
End Property 'CreateParams 

Public Sub New(ByRef ContentFolder As String, ByRef x As Integer, ByRef y As Integer, ByRef w As Integer, ByRef h As Integer) 
    FormBorderStyle = FormBorderStyle.None 
'Note, I have tried the original suggested control styles in many combinations 
    Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint 
    UpdateStyles() 

    OL = x 'Used for resizing, to know what the original bounds were - especially in maximizing, didn't like the standards maximize call 
    OT = y 
    OW = w 
    OH = h 
    BackColor = Color.White 
    BorderColor = New Pen(BarColor.Color) 
    MinimumSize = New Size(200, 200) 
    TransparencyKey = Color.FromArgb(255, 255, 0, 128) 
    CF = ContentFolder 
    ControlBar = New FormBar(Me, "Explorer woo", CF) 

    AddHandler Me.Load, AddressOf EF_Load 
    AddHandler Me.MouseUp, AddressOf EF_MouseUp 
    AddHandler Me.MouseDown, AddressOf EF_MouseDown 
    AddHandler Me.MouseMove, AddressOf EF_MouseMove 
    AddHandler Me.LostFocus, AddressOf EF_LostFocus 
End Sub 

Public Sub EF_Load(ByVal sender As Object, ByVal e As EventArgs) 
    SetFormBounds(OL, OT, OW, OH) 
End Sub 

Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs) 
    ControlBar.SetBar(Width) 'Sets the width of controlbar to new width, and updates position of the 3 top-right form buttons 
    If Not (_backBuffer Is Nothing) Then 
     _backBuffer.Dispose() 
     _backBuffer = Nothing 
    End If 
    RaiseEvent Resized(Me, e) 'Resizes controls in custom handler, in this example, it is unused - with controls, they don't flicker when resized though 
    MyBase.OnSizeChanged(e) 
End Sub 

Private Sub SetFormBounds(ByRef l As Integer, ByRef t As Integer, ByRef w As Integer, ByRef h As Integer) 
    If w < Me.MinimumSize.Width Then 
     w = Me.MinimumSize.Width 
     l = Left 
    End If 
    If h < Me.MinimumSize.Height Then 
     h = Me.MinimumSize.Height 
     t = Top 
    End If 
    If l = Left AndAlso t = Top AndAlso w = Width AndAlso h = Height Then Exit Sub 
    ControlBar.SetBar(w) 
    SetBounds(l, t, w, h) 
    'Used for detecting if user coords are on the form borders with L-shaped areas so as to not include too much of the interior of the bar, Borderthickness = pixel width of border 
    CornerRects = New List(Of Rectangle) From {{New Rectangle(0, 0, BorderThickness, 15)}, {New Rectangle(0, 0, 15, BorderThickness)}, {New Rectangle(Width - 15, 0, 15, BorderThickness)}, {New Rectangle(Width - BorderThickness, 0, BorderThickness, 15)}, {New Rectangle(0, Height - 15, BorderThickness, 15)}, {New Rectangle(BorderThickness, Height - BorderThickness, 10, BorderThickness)}, {New Rectangle(Width - BorderThickness, Height - 15, BorderThickness, 15)}, {New Rectangle(Width - 15, Height - BorderThickness, 10, BorderThickness)}} 
End Sub 

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) 
    If _backBuffer Is Nothing Then 
     _backBuffer = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height) 
    End If 

    Dim g As Graphics = Graphics.FromImage(_backBuffer) 
    g.Clear(SystemColors.Control) 
    'Draw Control Box 
    g.TextRenderingHint = Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit 
    g.FillRectangle(BarColor, 0, 0, Width, ControlBar.Height) 
    If ControlBar.Title <> "" Then g.DrawString(ControlBar.Title, ControlBar.Font, ControlBar.FontBrush, ControlBar.TextLeft, ControlBar.TextTop) 
    g.DrawImage(FormBar.bmpCorners(0), 0, 0) 'Makes transparent corner, very small bitmap created at run-time 
    g.DrawImage(FormBar.bmpCorners(1), Width - FormBar.bmpCorners(0).Width, 0) 
    'Draw Control Box buttons top right 
    If ControlBar.ExitButton.Enabled = True Then g.DrawImage(ControlBar.ExitButton.Img, ControlBar.ExitButton.Rect.X, ControlBar.ExitButton.Rect.Y) 
    If ControlBar.MaximizeButton.Enabled = True Then g.DrawImage(ControlBar.MaximizeButton.Img, ControlBar.MaximizeButton.Rect.X, ControlBar.MaximizeButton.Rect.Y) 
    If ControlBar.MinimizeButton.Enabled = True Then g.DrawImage(ControlBar.MinimizeButton.Img, ControlBar.MinimizeButton.Rect.X, ControlBar.MinimizeButton.Rect.Y) 
    If Not ControlBar.Ico Is Nothing Then g.DrawImage(ControlBar.Ico, 5, 5) 'Draw Control Box icon (program icon) if it is set 

    'Draw the form border 
    For i = 0 To BorderThickness - 1 
     g.DrawLine(BorderColor, i, ControlBar.Height, i, Height - 1) 
     g.DrawLine(BorderColor, Width - 1 - i, ControlBar.Height, Width - 1 - i, Height - 1) 
     g.DrawLine(BorderColor, BorderThickness, Height - 1 - i, Width - BorderThickness, Height - 1 - i) 
    Next 
    g.Dispose() 
    e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0) 
End Sub 

Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs) 
End Sub 
+0

這是非常* *不清楚爲什麼你正在尋找一種替代。 Form類是一個很好的.NET封裝類,用於本地窗口,並允許任何你想用窗口做的事情。具體說明你想要解決什麼問題。 –

+0

是什麼讓你認爲「自己處理所有事情」不會引起閃爍?這是孩子窗戶工作方式的先天,你會做一堆工作,最終會遇到完全相同的問題。只是不要使用兒童窗戶。檢查[這個答案](http://stackoverflow.com/questions/2612487/how-to-fix-the-flickering-in-user-controls/2613272#2613272)快速修復。 –

+0

嗯,我看到這個問題已經編輯,因爲我寫了我的答案。在這種情況下,漢斯是對的:如果你做錯了,你自己畫的東西仍然會閃爍。有更好的方法來解決這個問題。我認爲它可以作爲[XY問題]的一般示例(http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem),以及爲什麼你應該解釋所有這些細節你第一次嘗試完成什麼。 –

回答

1

這是不真的有可能在任何語言中,這不是一種語言的東西,甚至不是一個框架(即WinForms)的東西,而是更多的是因爲Windows本身的設計本質上,在Windows中的所有內容是一個窗口,Form類表示可以直接在桌面上顯示的基本頂級窗口。如果你想在桌面上顯示一個窗口,你需要使用Form類。而且,如果你想擁有一個你可以掛鉤的窗口句柄,你需要使用這個類;這是所有必要的管理工作去完成的。

但這並不意味着它必須看起來像一個默認的Form對象那樣。外觀是無限可定製的。首先設置表單的FormBorderStyle屬性以刪除默認的窗口框/ chrome。這會給你一個完全空白的石板。然後,像你說的那樣去處理它的Paint事件。除了當您想要處理派生類的事件時,您應該直接覆蓋OnXxx方法,而不是訂閱事件。所以,你有這樣的代碼:

Public Class SimpleForm : Inherits Form 

    Public Sub New() 
     ' Alter the form's basic appearance by removing the window frame, 
     ' which gives you a blank slate to draw onto. 
     FormBorderStyle = FormBorderStyle.None 

     ' Indicate that we're painting our own background. 
     SetStyle(ControlStyles.Opaque, True) 
    End Sub 

    Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs) 
     ' Call the base class. 
     MyBase.OnPaint(e) 

     ' Paint the background... 
     e.Graphics.FillRectangle(Brushes.MediumAquamarine, Me.ClientRectangle) 

     ' ...and then the foreground. 
     ' For example, drawing an 'X' to mark the spot! 
     Using p As New Pen(Color.Navy, 4.0) 
     e.Graphics.DrawLine(p, 0, 0, Me.Width, Me.Height) 
     e.Graphics.DrawLine(p, Me.Width, 0, 0, Me.Height) 
     End Using 
    End Sub 

End Class 

當然,這樣的窗口有嚴重可用性問題。對於初學者來說,用戶無法在屏幕上移動它或關閉它。如果您要消除默認邊框,則需要自己處理這些內容。

+0

我會嘗試這個並回復你,謝謝。 –

+0

我做到了這一點,它減少了幾乎完全縮小窗體的閃爍,但在擴展窗體時我仍然看到了黑框,特別是在快速擴展窗體時。 –

0

你能展示你用來啓用雙緩衝的方法嗎?這是一篇解決這個問題的文章。也許它會有所幫助。

http://bobpowell.net/doublebuffer.aspx

基本上,代碼是這樣的(文章):

Private _backBuffer As Bitmap 

Public Sub New 
    InitializeComponents() 

    Me.SetStyle(ControlStyles.AllPaintingInWmPaint OR _ 
       ControlStyles.UserPaint OR _ 
       ControlStyles.DoubleBuffer, True) 
End Sub 

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs) 
    If _backBuffer Is Nothing Then 
     _backBuffer = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height) 
    End If 

    Dim g As Graphics = Graphics.FromImage(_backBuffer) 

    'Paint on the Graphics object here 

    g.Dispose() 

    'Copy the back buffer to the screen 
    e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0) 

End Sub 'OnPaint 


'Don't allow the background to paint 
Protected Overrides Sub OnPaintBackground(ByVal pevent As PaintEventArgs) 
End Sub 'OnPaintBackground 


Protected Overrides Sub OnSizeChanged(ByVal e As EventArgs) 
    If Not (_backBuffer Is Nothing) Then 
     _backBuffer.Dispose() 
     _backBuffer = Nothing 
    End If 
    MyBase.OnSizeChanged(e) 
End Sub 'OnSizeChanged 
+0

我用過這個,結果仍然差不多。調整大小後,黑色框會不斷顯示在調整窗體大小的位置。縮小時,表單似乎乾淨地調整大小。控制器沒有閃爍。 –