Größenänderung bei Forms mit dem Borderstyle None

    • VB.NET

      Größenänderung bei Forms mit dem Borderstyle None

      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 :

      VB.NET-Quellcode

      1. Module Functions
      2. 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
      3. Public Declare Function ReleaseCapture Lib "user32.dll" () As Int32
      4. Public Enum MouseHook
      5. HTCAPTION = 2
      6. HTLEFT = 10
      7. HTRIGHT = 11
      8. HTTOP = 12
      9. HTTOPLEFT = 13
      10. HTTOPRIGHT = 14
      11. HTBOTTOM = 15
      12. HTBOTTOMLEFT = 16
      13. HTBOTTOMRIGHT = 17
      14. End Enum
      15. Public Const WM_NCLBUTTONDOWN As Int32 = &HA1
      16. 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

      1. Imports System.Drawing.Drawing2D
      2. Public Class Mainform
      3. Dim htop, htopleft, htopright, hbottom, hbottomright, hbottomleft, hleft, hright, hcaption As New GraphicsPath
      4. Private Sub Mainform_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
      5. Dim WidthA As Integer = 4 'Randbreite
      6. With hright
      7. .Reset()
      8. .AddRectangle(New Rectangle(New Point(Me.Width - WidthA, WidthA), New Size(WidthA, Me.Height - 2 * WidthA)))
      9. .CloseFigure()
      10. End With
      11. With hleft
      12. .Reset()
      13. .AddRectangle(New Rectangle(New Point(0, WidthA), New Size(WidthA, Me.Height - 2 * WidthA)))
      14. .CloseFigure()
      15. End With
      16. With htop
      17. .Reset()
      18. .AddRectangle(New Rectangle(New Point(WidthA, 0), New Size(Me.Width - 2 * WidthA, WidthA)))
      19. .CloseFigure()
      20. End With
      21. With hbottom
      22. .Reset()
      23. .AddRectangle(New Rectangle(New Point(WidthA, Me.Height - WidthA), New Size(Me.Width - 2 * WidthA, WidthA)))
      24. .CloseFigure()
      25. End With
      26. With htopright
      27. .Reset()
      28. .AddRectangle(New Rectangle(New Point(Me.Width - WidthA, 0), New Size(WidthA, WidthA)))
      29. .CloseFigure()
      30. End With
      31. With hbottomright
      32. .Reset()
      33. .AddRectangle(New Rectangle(New Point(Me.Width - WidthA, Me.Height - WidthA), New Size(WidthA, WidthA)))
      34. .CloseFigure()
      35. End With
      36. With htopleft
      37. .Reset()
      38. .AddRectangle(New Rectangle(New Point(0, 0), New Size(WidthA, WidthA)))
      39. .CloseFigure()
      40. End With
      41. With hbottomleft
      42. .Reset()
      43. .AddRectangle(New Rectangle(New Point(0, Me.Height - WidthA), New Size(WidthA, WidthA)))
      44. .CloseFigure()
      45. End With
      46. With hcaption
      47. .Reset()
      48. .AddRectangle(New Rectangle(New Point(WidthA, WidthA), New Size(Me.Width - 2 * WidthA, 25)))
      49. .CloseFigure()
      50. End With
      51. End Sub
      52. End Class

      Oh Himmel 8| 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

      1. Private Sub Mainform_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
      2. If htop.IsVisible(e.Location) = True OrElse hbottom.IsVisible(e.Location) = True Then
      3. Me.Cursor = Cursors.SizeNS
      4. ElseIf hright.IsVisible(e.Location) = True OrElse hleft.IsVisible(e.Location) = True Then
      5. Me.Cursor = Cursors.SizeWE
      6. ElseIf htopright.IsVisible(e.Location) = True OrElse hbottomleft.IsVisible(e.Location) = True Then
      7. Me.Cursor = Cursors.SizeNESW
      8. ElseIf htopleft.IsVisible(e.Location) = True OrElse hbottomright.IsVisible(e.Location) = True Then
      9. Me.Cursor = Cursors.SizeNWSE
      10. Else
      11. Me.Cursor = Cursors.Default
      12. End If
      13. 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

      1. Private Sub Mainform_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
      2. If e.Button = MouseButtons.Left Then 'Prüfen ob die linke Maustaste gedrückt it
      3. If htop.IsVisible(e.Location) = True Then
      4. Me.Cursor = Cursors.SizeNS
      5. ReleaseCapture()
      6. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTTOP, IntPtr.Zero)
      7. ElseIf hbottom.IsVisible(e.Location) = True Then
      8. Me.Cursor = Cursors.SizeNS
      9. ReleaseCapture()
      10. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTBOTTOM, IntPtr.Zero)
      11. ElseIf hleft.IsVisible(e.Location) = True Then
      12. Me.Cursor = Cursors.SizeWE
      13. ReleaseCapture()
      14. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTLEFT, IntPtr.Zero)
      15. ElseIf hright.IsVisible(e.Location) = True Then
      16. Me.Cursor = Cursors.SizeWE
      17. ReleaseCapture()
      18. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTRIGHT, IntPtr.Zero)
      19. ElseIf htopright.IsVisible(e.Location) = True Then
      20. Me.Cursor = Cursors.SizeNESW
      21. ReleaseCapture()
      22. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTTOPRIGHT, IntPtr.Zero)
      23. ElseIf hbottomright.IsVisible(e.Location) = True Then
      24. Me.Cursor = Cursors.SizeNWSE
      25. ReleaseCapture()
      26. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTBOTTOMRIGHT, IntPtr.Zero)
      27. ElseIf htopleft.IsVisible(e.Location) = True Then
      28. Me.Cursor = Cursors.SizeNWSE
      29. ReleaseCapture()
      30. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTTOPLEFT, IntPtr.Zero)
      31. ElseIf hbottomleft.IsVisible(e.Location) = True Then
      32. Me.Cursor = Cursors.SizeNESW
      33. ReleaseCapture()
      34. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTBOTTOMLEFT, IntPtr.Zero)
      35. ElseIf hcaption.IsVisible(e.Location) = True Then
      36. ReleaseCapture()
      37. SendMessage(Me.Handle, WM_NCLBUTTONDOWN, MouseHook.HTCAPTION, IntPtr.Zero)
      38. End If
      39. End If
      40. End Sub


      Bei erneutem debuggen stellen wir fest, dass die Größenänderung und auch das bewegen der Form funktioniert :thumbsup:
      Aber die Controlbox ist nicht wirklich zu erkennen also zeichnen wir schnell eine^^

      VB.NET-Quellcode

      1. Private Sub Mainform_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      2. Dim z As Graphics = e.Graphics
      3. Dim lingrbru As New LinearGradientBrush(New Point(0, 0), New Point(Me.Width, 0), Color.Red, Color.FromArgb(200, Color.Black))
      4. z.FillRectangle(lingrbru, New Rectangle(0, 0, Me.Width, 25))
      5. End Sub
      6. Private Sub Mainform_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      7. Me.DoubleBuffered = True
      8. End Sub


      Und wir müssen unter Mainform_SizeChanged

      VB.NET-Quellcode

      1. Me.Invalidate
      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 :)
      Dateien
      • FormBorderNone.zip

        (14,27 kB, 217 mal heruntergeladen, zuletzt: )