Hallo,
in diesem kleinen Tutorial möchte ich zeigen wie man bei einer Windows.Forms.Form mit dem Borderstyle = None ihre Größe während der Laufzeit anpasst. Ich habe schon mehrere Threads gesehen die dieses Thema behandeln und auch schon PN's mit Fragen bekommen, also hoffe ich hiermit helfen zu können
Zu Anfang erstellen wir ein neues Projekt (eine Windows Forms Anwendung) die bereits vorhandene Form nennen wir "Mainform" und fügen ein Modul mit dem Namen "Functions" hinzu. So nun hätten wir 2 Möglichkeiten:
1. Wir berechnen die Formgrößenänderung mit der Mouselocation
2. Wir verwenden API's
Ich habe mich für die zweite Möglichkeit entschieden
In unserem Modul fügen wir also die passenden API-Aufrufe ein und die dazugehörige Enumeration :
Durch die Enumeration geben wir in der Funktion "SendMessage" die 'Art' der Größenänderung an.
1. Die vier Ecken der Form: HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT und HTBOTTOMRIGHT
2. Die vier Ränder der Form: HTTOP, HTBOTTOM, HTLEFT und HTRIGHT
3. Der bereich zum verschieben oder bewegen der Form (normalerweise die Controlbox): HTCAPTION
Wir müssen also jetzt diese bereiche definieren. Dass könnten wir mit Buttons oder Panels machen, wäre aber ziemlich von nachteil, da man 'unnütze' Steuerelemente auf der Form hat also nehmen wir ein paar Graphicspaths
Oh Himmel erschreckend so viel auf einmal. Naja eigentlich nicht^^ Wir haben die nötigen GraphicsPath deklariert und angepasst. Wenn die Größe der Formm geändert wird, müssen auch die GraphicsPaths neu angepasst werden, deswegen das ganze im SizeChanged. Und 'WidthA' ist die breite des Randes in Pixeln ich hab sie extra deklariert um sie eventuell schnell anzupassen
So weit so gut , fangen wir jetzt an mit den Cursors an. Die wollen wir ja auch passend haben
Die Funktion GraphicsPath.IsVisible() prüft ob ein Punkt in ihm liegt , also hier wird überprüft ob die Maus sich in dem Graphicpath befindet. Wenn wir nun das Debugging starten und die Maus über die Ränder bewegen sehen wir das sich die Cursor so ändern wie bei der normalen 'Sizeable'-Form.
Um jetzt die Größe ändern zu können müssen wir prüfen ob man mit der Maus auf den passenden GraphicsPath drückt.
Bei erneutem debuggen stellen wir fest, dass die Größenänderung und auch das bewegen der Form funktioniert
Aber die Controlbox ist nicht wirklich zu erkennen also zeichnen wir schnell eine^^
Und wir müssen unter Mainform_SizeChanged hinzufügen. So wird unsere Form bei jeder Größenänderung neu gezeichnet und durch aktivieren des Doublebuffers hakt es nicht so
Zum Schluss noch ein paar Tipps:
1. Man sollte eine Minimumsize festlegen sonst lässt sich die Form bis auf 1 Pixel verkleinern
2. Bei Abgerundeten Ecken bzw. einer nicht Rechteckigen Form muss man die GraphicsPaths logischer Weise selbst erstellen
3. Wer langfristig selber komplexe schöne Designs erstellen möchte sollte sich überlegen zu WPF zu wechseln dort wird es einem etwas einfacher gemacht, ich persönlich bevorzuge aber WindowsForms
Hoffentlich ist alles klar geworden. Ich freue mich über Rückmeldungen oder Verbesserungsvorschläge
in diesem kleinen Tutorial möchte ich zeigen wie man bei einer Windows.Forms.Form mit dem Borderstyle = None ihre Größe während der Laufzeit anpasst. Ich habe schon mehrere Threads gesehen die dieses Thema behandeln und auch schon PN's mit Fragen bekommen, also hoffe ich hiermit helfen zu können
Zu Anfang erstellen wir ein neues Projekt (eine Windows Forms Anwendung) die bereits vorhandene Form nennen wir "Mainform" und fügen ein Modul mit dem Namen "Functions" hinzu. So nun hätten wir 2 Möglichkeiten:
1. Wir berechnen die Formgrößenänderung mit der Mouselocation
2. Wir verwenden API's
Ich habe mich für die zweite Möglichkeit entschieden
In unserem Modul fügen wir also die passenden API-Aufrufe ein und die dazugehörige Enumeration :
VB.NET-Quellcode
- Module Functions
- Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Int32, ByVal wParam As MouseHook, ByVal lParam As IntPtr) As Int32
- Public Declare Function ReleaseCapture Lib "user32.dll" () As Int32
- Public Enum MouseHook
- HTCAPTION = 2
- HTLEFT = 10
- HTRIGHT = 11
- HTTOP = 12
- HTTOPLEFT = 13
- HTTOPRIGHT = 14
- HTBOTTOM = 15
- HTBOTTOMLEFT = 16
- HTBOTTOMRIGHT = 17
- End Enum
- Public Const WM_NCLBUTTONDOWN As Int32 = &HA1
- End Module
Durch die Enumeration geben wir in der Funktion "SendMessage" die 'Art' der Größenänderung an.
1. Die vier Ecken der Form: HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT und HTBOTTOMRIGHT
2. Die vier Ränder der Form: HTTOP, HTBOTTOM, HTLEFT und HTRIGHT
3. Der bereich zum verschieben oder bewegen der Form (normalerweise die Controlbox): HTCAPTION
Wir müssen also jetzt diese bereiche definieren. Dass könnten wir mit Buttons oder Panels machen, wäre aber ziemlich von nachteil, da man 'unnütze' Steuerelemente auf der Form hat also nehmen wir ein paar Graphicspaths
VB.NET-Quellcode
- Imports System.Drawing.Drawing2D
- Public Class Mainform
- Dim htop, htopleft, htopright, hbottom, hbottomright, hbottomleft, hleft, hright, hcaption As New GraphicsPath
- Private Sub Mainform_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
- Dim WidthA As Integer = 4 'Randbreite
- With hright
- .Reset()
- .AddRectangle(New Rectangle(New Point(Me.Width - WidthA, WidthA), New Size(WidthA, Me.Height - 2 * WidthA)))
- .CloseFigure()
- End With
- With hleft
- .Reset()
- .AddRectangle(New Rectangle(New Point(0, WidthA), New Size(WidthA, Me.Height - 2 * WidthA)))
- .CloseFigure()
- End With
- With htop
- .Reset()
- .AddRectangle(New Rectangle(New Point(WidthA, 0), New Size(Me.Width - 2 * WidthA, WidthA)))
- .CloseFigure()
- End With
- With hbottom
- .Reset()
- .AddRectangle(New Rectangle(New Point(WidthA, Me.Height - WidthA), New Size(Me.Width - 2 * WidthA, WidthA)))
- .CloseFigure()
- End With
- With htopright
- .Reset()
- .AddRectangle(New Rectangle(New Point(Me.Width - WidthA, 0), New Size(WidthA, WidthA)))
- .CloseFigure()
- End With
- With hbottomright
- .Reset()
- .AddRectangle(New Rectangle(New Point(Me.Width - WidthA, Me.Height - WidthA), New Size(WidthA, WidthA)))
- .CloseFigure()
- End With
- With htopleft
- .Reset()
- .AddRectangle(New Rectangle(New Point(0, 0), New Size(WidthA, WidthA)))
- .CloseFigure()
- End With
- With hbottomleft
- .Reset()
- .AddRectangle(New Rectangle(New Point(0, Me.Height - WidthA), New Size(WidthA, WidthA)))
- .CloseFigure()
- End With
- With hcaption
- .Reset()
- .AddRectangle(New Rectangle(New Point(WidthA, WidthA), New Size(Me.Width - 2 * WidthA, 25)))
- .CloseFigure()
- End With
- End Sub
- End Class
Oh Himmel erschreckend so viel auf einmal. Naja eigentlich nicht^^ Wir haben die nötigen GraphicsPath deklariert und angepasst. Wenn die Größe der Formm geändert wird, müssen auch die GraphicsPaths neu angepasst werden, deswegen das ganze im SizeChanged. Und 'WidthA' ist die breite des Randes in Pixeln ich hab sie extra deklariert um sie eventuell schnell anzupassen
So weit so gut , fangen wir jetzt an mit den Cursors an. Die wollen wir ja auch passend haben
VB.NET-Quellcode
- Private Sub Mainform_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
- If htop.IsVisible(e.Location) = True OrElse hbottom.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNS
- ElseIf hright.IsVisible(e.Location) = True OrElse hleft.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeWE
- ElseIf htopright.IsVisible(e.Location) = True OrElse hbottomleft.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNESW
- ElseIf htopleft.IsVisible(e.Location) = True OrElse hbottomright.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNWSE
- Else
- Me.Cursor = Cursors.Default
- End If
- End Sub
Die Funktion GraphicsPath.IsVisible() prüft ob ein Punkt in ihm liegt , also hier wird überprüft ob die Maus sich in dem Graphicpath befindet. Wenn wir nun das Debugging starten und die Maus über die Ränder bewegen sehen wir das sich die Cursor so ändern wie bei der normalen 'Sizeable'-Form.
Um jetzt die Größe ändern zu können müssen wir prüfen ob man mit der Maus auf den passenden GraphicsPath drückt.
VB.NET-Quellcode
- Private Sub Mainform_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
- If e.Button = MouseButtons.Left Then 'Prüfen ob die linke Maustaste gedrückt it
- If htop.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNS
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTTOP, IntPtr.Zero)
- ElseIf hbottom.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNS
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTBOTTOM, IntPtr.Zero)
- ElseIf hleft.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeWE
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTLEFT, IntPtr.Zero)
- ElseIf hright.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeWE
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTRIGHT, IntPtr.Zero)
- ElseIf htopright.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNESW
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTTOPRIGHT, IntPtr.Zero)
- ElseIf hbottomright.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNWSE
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTBOTTOMRIGHT, IntPtr.Zero)
- ElseIf htopleft.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNWSE
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTTOPLEFT, IntPtr.Zero)
- ElseIf hbottomleft.IsVisible(e.Location) = True Then
- Me.Cursor = Cursors.SizeNESW
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTBOTTOMLEFT, IntPtr.Zero)
- ElseIf hcaption.IsVisible(e.Location) = True Then
- ReleaseCapture()
- SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTCAPTION, IntPtr.Zero)
- End If
- End If
- End Sub
Bei erneutem debuggen stellen wir fest, dass die Größenänderung und auch das bewegen der Form funktioniert
Aber die Controlbox ist nicht wirklich zu erkennen also zeichnen wir schnell eine^^
VB.NET-Quellcode
- Private Sub Mainform_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
- Dim z As Graphics = e.Graphics
- Dim lingrbru As New LinearGradientBrush(New Point(0, 0), New Point(Me.Width, 0), Color.Red, Color.FromArgb(200, Color.Black))
- z.FillRectangle(lingrbru, New Rectangle(0, 0, Me.Width, 25))
- End Sub
- Private Sub Mainform_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
- Me.DoubleBuffered = True
- End Sub
Und wir müssen unter Mainform_SizeChanged hinzufügen. So wird unsere Form bei jeder Größenänderung neu gezeichnet und durch aktivieren des Doublebuffers hakt es nicht so
Zum Schluss noch ein paar Tipps:
1. Man sollte eine Minimumsize festlegen sonst lässt sich die Form bis auf 1 Pixel verkleinern
2. Bei Abgerundeten Ecken bzw. einer nicht Rechteckigen Form muss man die GraphicsPaths logischer Weise selbst erstellen
3. Wer langfristig selber komplexe schöne Designs erstellen möchte sollte sich überlegen zu WPF zu wechseln dort wird es einem etwas einfacher gemacht, ich persönlich bevorzuge aber WindowsForms
Hoffentlich ist alles klar geworden. Ich freue mich über Rückmeldungen oder Verbesserungsvorschläge