Eigenes Form Design zeichnen

    • VB.NET

    Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von Samus Aran.

      Eigenes Form Design zeichnen

      Hallo erstmal.

      Ich wollte schon immer eigene Controls. Bloß mit Pictureboxen wollte ich es nicht machen, weil es blöd aussieht und schlecht zu handhaben ist.
      Also habe ich mal gegooglet und herausgefunden, wie man eigene Controls zeichnet.
      Diese Technik kann man für alle Controls verwenden. (Form, Progressbar, Button, Textbox, etc)
      Hier erkläre ich aber, wie man eine eigene Form zeichnet.

      Und da schon viele hier gefragt haben, habe ich mal ein Tut dafür gemacht.
      In den Spoilern ist der jeweilige abschnitt.
      ACHTUNG!!! Copy&Paste wird hier nicht unterstützt. Ich erkläre alles, damit ihr was lernt!!!!!

      Schritt 1:
      Als erstes erstellen wir ein neues Projekt mit einer "Class Libary".
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Class Class1
      2. End Class

      Schritt 2:
      Zum zeichnen importieren wir System.Windows.Forms, System.Drawing.Drawing2D und System.Drawing.
      Wenn ein Fehler auftritt, fügt dem Projekt eine Form hinzu. Direkt danach könnt ihr sie wieder löschen.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports System.Windows.Forms
      2. Imports System.Drawing.Drawing2D
      3. Imports System.Drawing

      Schritt 3:
      Das Programm muss auch noch wissen, von was es erben soll.
      Also Inherits Form. (Oder Inherits Progressbar, Button, Listbox)
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Inherits Form

      Schritt 4:
      Natürlich soll das Programm wissen, dass wir es selbst zeichnen.
      Dafür erstellen wir den Sub "Public Sub New" und machen dort ein paar Einstellungen (Siehe Code)
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Sub New()
      2. MyBase.New()
      3. MyBase.SetStyle(ControlStyles.UserPaint, True) 'Sagt, dass wir selbst zeichnen
      4. MyBase.SetStyle(ControlStyles.DoubleBuffer, True) 'Sagt, dass die Form doppelt gebuffert wird
      5. MyBase.SetStyle(ControlStyles.SupportsTransparentBackColor, True) 'Eigentlich unwichtig. Sagt, dass Transparenter Hintergrund unterstützt wird
      6. End Sub

      Schritt 5:
      Somit haben wir die Grundlagen. Jetzt kommt der Part, wo wir die Form (bzw. das Control) zeichnen.
      Dies erfolgt in einem Sub, der auslöst, wenn die Form neu gezeichnet wird.
      Als erstes legen wir aber unsere Zeichenqualität fest.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Private Sub Grafik(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
      2. e.Graphics.SmoothingMode = SmoothingMode.HighQuality
      3. End Sub

      Schritt 6:
      Jetzt könnt ihr eurer Fantasie freien lauf lassen xD
      Gezeichnet wird mit "e.Graphics.Draw..."
      Spoiler anzeigen

      VB.NET-Quellcode

      1. e.Graphics.FillRectangle(Brushes.White, 0, 0, MyBase.Width - 1, MyBase.Height - 1) 'Die Form ansich
      2. e.Graphics.DrawRectangle(Pens.DarkGray, 0, 0, MyBase.Width - 1, MyBase.Height - 1) 'Rahmen um die Form
      3. e.Graphics.DrawRectangle(Pens.DarkGray, 0, 0, MyBase.Width - 1, 23) 'Die Leiste oben
      4. e.Graphics.DrawIcon(MyBase.Icon, New Rectangle(1, 1, 23, 23)) 'Zeichnet das Icon in der Leiste
      5. e.Graphics.DrawString(MyBase.Text, New Font("Arial", 12), Brushes.Black, 24, 3) 'Zeichnet den Titel des Fenster
      6. e.Graphics.DrawString("Schließen", New Font("Arial", 10), Brushes.Black, MyBase.Width - 70, 4) 'Zeichnet das "Schließen", kann auch Bild sein

      Schritt 7:
      So, die Form ist gezeichnet, aber lässt sich nicht verschieben.
      Dies lösen wir, indem wir temporär diePosition der Maus und der Fensters speichern und bei einer bewegung die Diferenz ausrechnen und anwenden.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Private Sub MetroFormxd_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown 'Wenn Maustaste gedrückt wird
      2. If MousePosition.X > MyBase.Location.X And MousePosition.X < MyBase.Location.X + (MyBase.Width- 70) Then 'Wenn zwischen Anfang und Ende der Form in X-Richtung
      3. If MousePosition.Y > MyBase.Location.Y And MousePosition.Y < MyBase.Location.Y + 23 Then 'Wenn zwischen Anfang und Ende der Form in Y-Richtung
      4. temp_mouse_X = MousePosition.X 'Dann Positionen temporär speichern
      5. temp_mouse_Y = MousePosition.Y
      6. temp_windo_X = MyBase.Location.X
      7. temp_windo_Y = MyBase.Location.Y
      8. schieben = True ' Und speichern, dass verschoben wird
      9. End If
      10. End If
      11. End Sub
      12. Private Sub MetroFormxd_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove 'Wenn Maus bewegt wird
      13. If schieben = True Then 'Wenn die Form verschoben wird
      14. Dim tx As Integer = MousePosition.X - temp_mouse_X 'Dann differenz ausrechnen
      15. Dim ty As Integer = MousePosition.Y - temp_mouse_Y
      16. Dim sx As Integer = temp_windo_X + tx 'Und anwenden
      17. Dim sy As Integer = temp_windo_Y + ty
      18. MyBase.Location = New Point(sx, sy) 'Neue Position anwenden
      19. End If
      20. End Sub
      21. Private Sub MetroFormxd_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp 'Wenn Maustaste losgelassen wird
      22. schieben = False 'Dann speichern, dass das Fenster nicht verschoben wird
      23. End Sub

      Schritt 8:
      Dies ist vorerst der letzte Schritt.
      Das Schließen der Form.
      Dass machen wir wie in Schritt 7 ("MetroFormxd_MouseDown"), nur mit anderen Koordinaten.
      Den Code fügen wir auch in den gleichen Sub wie in Schritt 7 ("MetroFormxd_MouseDown").
      Spoiler anzeigen

      VB.NET-Quellcode

      1. If MousePosition.X > (MyBase.Width - 70) And MousePosition.X < MyBase.Width Then 'Wenn zwischen Anfang und Ende von "Schließen" in X-Richtung
      2. If MousePosition.Y > MyBase.Location.Y And MousePosition.Y < MyBase.Location.Y + 23 Then 'Wenn zwischen Anfang und Ende von Leiste in Y-Richtung
      3. Application.Exit() 'Dann Application schließen (Wenn noch andere Fenster offen von gleichem Projekt werden die auch geschlossen)
      4. End If
      5. End If


      Zum Schluss nochmal der ganze Code an einem Stück.
      Und denkt bitte dran. Von Copy&Paste lernt ihr rein gar nichts. Spätestens beim nächsten mal habt ihr es wieder vergessen und sucht den Link.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports System.Windows.Forms
      2. Imports System.Drawing.Drawing2D
      3. Imports System.Drawing
      4. Public Class MetroFormxd
      5. Inherits Form
      6. Dim schieben As Boolean = False
      7. Dim temp_mouse_X As Integer
      8. Dim temp_mouse_Y As Integer
      9. Dim temp_windo_X As Integer
      10. Dim temp_windo_Y As Integer
      11. Public Sub New()
      12. MyBase.New()
      13. MyBase.SetStyle(ControlStyles.UserPaint, True)
      14. MyBase.SetStyle(ControlStyles.DoubleBuffer, True)
      15. MyBase.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
      16. End Sub
      17. Private Sub MetroFormxd_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
      18. If MousePosition.X > MyBase.Location.X And MousePosition.X < MyBase.Location.X + (MyBase.Width - 70) Then
      19. If MousePosition.Y > MyBase.Location.Y And MousePosition.Y < MyBase.Location.Y + 23 Then
      20. temp_mouse_X = MousePosition.X
      21. temp_mouse_Y = MousePosition.Y
      22. temp_windo_X = MyBase.Location.X
      23. temp_windo_Y = MyBase.Location.Y
      24. schieben = True
      25. End If
      26. End If
      27. If MousePosition.X > (MyBase.Width - 70) And MousePosition.X < MyBase.Width Then
      28. If MousePosition.Y > MyBase.Location.Y And MousePosition.Y < MyBase.Location.Y + 23 Then
      29. Application.Exit()
      30. End If
      31. End If
      32. End Sub
      33. Private Sub MetroFormxd_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
      34. If schieben = True Then
      35. Dim tx As Integer = MousePosition.X - temp_mouse_X
      36. Dim ty As Integer = MousePosition.Y - temp_mouse_Y
      37. Dim sx As Integer = temp_windo_X + tx
      38. Dim sy As Integer = temp_windo_Y + ty
      39. MyBase.Location = New Point(sx, sy)
      40. End If
      41. End Sub
      42. Private Sub MetroFormxd_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
      43. schieben = False
      44. End Sub
      45. Private Sub Grafik(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
      46. e.Graphics.SmoothingMode = SmoothingMode.HighQuality
      47. e.Graphics.FillRectangle(Brushes.White, 0, 0, MyBase.Width - 1, MyBase.Height - 1)
      48. e.Graphics.DrawRectangle(Pens.DarkGray, 0, 0, MyBase.Width - 1, MyBase.Height - 1)
      49. e.Graphics.DrawRectangle(Pens.DarkGray, 0, 0, MyBase.Width - 1, 23)
      50. e.Graphics.DrawIcon(MyBase.Icon, New Rectangle(1, 1, 23, 23))
      51. e.Graphics.DrawString(MyBase.Text, New Font("Arial", 12), Brushes.Black, 24, 3)
      52. e.Graphics.DrawString("Schließen", New Font("Arial", 10), Brushes.Black, MyBase.Width - 70, 4)
      53. End Sub
      54. End Class


      Ich hoffe och konnte wenigstens einigen helfen xD
      Kleine Anmerkung zu Schritt 6, Zeile 6:
      Edit: ...und Schritt 7, Zeile 2... (70 als Konstante is nicht gut)

      VB.NET-Quellcode

      1. e.Graphics.DrawString("Schließen", New Font("Arial", 10), Brushes.Black, MyBase.Width - 70, 4) 'Zeichnet das "Schließen", kann auch Bild sein


      Ich schlage stattdessen folgende Zeilen vor:
      Durch die MeasureString-Funktion bekommt man die Abmessungen des Textes in der gewünschten Schriftart zurück.
      Dadurch kann jeder Text gut rechtsbündig ausgerichtet werden.
      Außerdem hat man in crect dann die Abmessungen, falls man diese Worte - "Schließen" - auch mal mit einer entsprechenden Funktion versehen will.

      VB.NET-Quellcode

      1. Dim ctext As String = "Schließen"
      2. Dim cfont As New Font("Arial", 10)
      3. Dim crect As SizeF = e.Graphics.MeasureString(ctext, cfont)
      4. Dim cbreite As Single = crect.Width
      5. e.Graphics.DrawString(ctext, cfont, Brushes.Black, MyBase.Width - cbreite, 4)


      PS: gut geschrieben, nett erklärt...

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „der_Kurt“ ()

      Und wie schreibt man jetzt den Code?
      Also wie zeichnet man z.b einen Button mit Events?
      Dazu müsste man das Viereck doch deklarieren oder?

      Nachtrag:
      Damit die Form nach resizen neuzeichnet einfach bei dem Event "ResizeEnd" Me.Invalidate einfügen.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „TheMatI“ ()

      @der Kurt: OK, dass wusste ich nicht. Werde es bei gelegenheit ändern. :)

      @TheMatI: Für ein eigees Control brauchst du folgendes:
      Die Imports
      Den "Public Sub New"
      Den Sub "Graphik"

      Alles andere ist nur für die Form.
      Jetzt zeichnest du das Viereck/Rechteck für den Button im "Graphik" Sub mit e.Graphics.FillRectangle(...).
      Ich bin mir nicht sicher, aber ich glaube dass es automatisch nach dem ReSize neu gezeichnet wird. (bin mir nicht sicher)
      Wenn nicht einfach ein Sub mit "Handles Mybase.ReSize"

      Darin schreibst du dann MyBase.Invalidate, obwohl bei mir auch Me.Refresh funktioniert hat. KA was davon besser ist.
      Wenns einer weiß bitte sagen xD