Mehrere Grafiken in einer Picturebox (ohne zu überschreiben/löschen)?

  • VB.NET

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Mehrere Grafiken in einer Picturebox (ohne zu überschreiben/löschen)?

    Hallo,

    ich habe folgendes Problem. Also ich möchte einen Temperaturverlauf in einer Grafik darstellen, dann einen Eingabe Wert ändern - nochmal rechnen lassen und den neuen Temperatur Verlauf dann zusätzlich zum alten Temperaturverlauf darstellen.
    Also x-Achse ist dann die Position, Y-Achse die Temperatur.

    Habe das auch mit CreateGraphics() und DrawGraph() gelöst, und solange man die PictureBox nicht mit PictureBox.Clear() lehrt werden die Kurven auch übereinander gelegt.
    Das Problem dabei ist aber, sobalt ich ein anderes Fenster darüberlege werden die Kurven wegradiert. Und das sollte auf keinen Fall passieren.

    Jetzt versuche ich das ganze als .Bitmap zu programmieren, zwar habe ich dann erstmal nur die einzelnen Punkte mit SetPixel(), aber es wird nichts wegradiert.
    Nun zum eigentlichen Problem: Auf diese weisse wird immer das ganze Bild in der Picturebox überschrieben, also man sieht immer nur die aktuelle Kurve. Wie könnte man es denn lösen, das die Alte Kurve auch noch zu sehen ist?
    Das ganze wird "wegradiert", weil das die Picturebox neugezeichnet werden muss, wenn du das Fenster wegziehst. Es gibt zwei Möglichkeiten für dich das "Wegradieren" zu verhindern :
    • Nicht in die Picturebox direkt, sondern auf ein Bitmap zu zeichnen und dieses dann als Bild für die Picturebox zu nehmen.
    • Im Draw-Event der Picturebox alles zeichnen.
    Bei dem Bitmap war das Problem, das dann die alte Kurve überschrieben wird.
    Wahrscheinlich weil dann das Bild über die ganze Picturebox geht.....aber müsste der Hintergrund dann nicht dranzparent sein, wenn ich nur die paar Pixel auf dem Bild gesetzt habe?

    Draw-Event sagt mir jetzt so genau noch nichts, muss ich mich mal schlau machen.
    Danke für die Info erstmal :)
    Ok schau das Paint-Event wird immer dann aufgerufen wenn neu gezeichnet werden muss z.B. wenn sich die Größe verändert oder wenn du es mit meinepicturebox.Invalidate() aufrufst. Dort drinnen hast du dann über e.Graphics schon ein fertiges Graphics-objekt. Mit diesem zeichnest du dann auf die Picturebox. Die nötigen Werte die du zum Zeichnen brauchst kannst du auch global deklarieren und irgendwo in einer sub ändern.

    z.B. wenn du eine linie verlängern willst. Irgendwo (z.B. bei einem Button-click-event) diesen code verwenden: xPos = xPos + 10 und danach noch meinepicbox.Invalidate(). Dabei ist natürlich xPos global deklariert und im Paintevent wird dann auf diese zugegriffen und ausgelesen.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim AllePunkte As PointF()
    3. Dim AllePunkte2 As PointF()
    4. Dim Alle_Kurven()
    5. Dim P1X_Array(50)
    6. Dim P1Y_Array(50)
    7. Dim P2X_Array(50)
    8. Dim P2Y_Array(50)
    9. Dim P3X_Array(50)
    10. Dim P3Y_Array(50)
    11. Dim Stift As Pen = New Pen(Brushes.AliceBlue)
    12. Private Kurvenchar As New PictureBox()
    13. Dim Durchlauf = 0
    14. Public Sub Kurvenchar_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
    15. Kurvenchar.Invalidate() 'Altes wird ungültig und es wird neu gezeichnet
    16. ' Die Grafik die auf die Picturebox gesetzt wird (Lokale Variable)
    17. Dim Kurven As Graphics = MyPicture.CreateGraphics
    18. For i As Integer = 0 To Durchlauf Step +1 'So oft wie die Funktion schon aufgerufen wurde werden Kurven gezeichnet
    19. 'Pro Durchlauf eine Puntechar
    20. AllePunkte = {New Point(0, P1Y_Array(i)), New Point(50, P2Y_Array(i)), New Point(100, P3Y_Array(i))}
    21. Select Case i 'Jede Kurve bekommt eine andere Farbe
    22. Case 0
    23. Stift = Pens.AliceBlue
    24. Case 1
    25. Stift = Pens.Red
    26. Case 2
    27. Stift = Pens.Green
    28. Case 3
    29. Stift = Pens.Blue
    30. Case 4
    31. Stift = Pens.Purple
    32. End Select
    33. Kurven.DrawCurve(Stift, AllePunkte) 'Kurve Zeichnen
    34. Next
    35. End Sub 'pictureBox1_Paint
    36. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    37. Durchlauf = Durchlauf + 1
    38. 'X und Y Werte festlegen
    39. P1X_Array(Durchlauf) = 0
    40. P2X_Array(Durchlauf) = 50
    41. P3X_Array(Durchlauf) = 100
    42. P1Y_Array(Durchlauf) = 50 + Durchlauf * 10
    43. P2Y_Array(Durchlauf) = 60 + Durchlauf * 10
    44. P3Y_Array(Durchlauf) = 30 + Durchlauf * 10
    45. ' ...Zeichne von der Kurvenchar Funktion ....... +Adresse wo der Paint Event steht?
    46. AddHandler Kurvenchar.Paint, AddressOf Me.Kurvenchar_Paint
    47. ' Setzt die Grafiken aus der Sub Kurvenchars ?
    48. Me.Controls.Add(Kurvenchar)
    49. End Sub
    50. End Class


    Habe das jetzt so gelöst, und es Funktioniert so wie ich es mir vorgestellt habe. *freu* Hätte nun aber doch noch ne frage zu den letzten veiden Zeilen, was machen die überhaupt? Würde auch gerne genau verstehen was ich da programmiere ;)
    Hab mal mit Fragezeichen Kommentare daran gechrieben was ich vermute was dort passiert...
    Ich nehme an es flackert weil du quasie eine Endlosschleife dadrin hast O.o die Invalidate()-Methode veranlasst ein Neuzeichnen des Controls, da du diese Methode im Paint-Event aufrufst, wird natürlich sofort nochmals das Pain-Event gefeuert usw.

    Zudem würde ich zu begin des Zeichnen SuspentLayout() machen damit die PB nicht jedes Zeichnen sofort übernimmt und erst am Ende mit ResumeLayout() wieder freigeben. Dadruch wird das Zeichnen deutlich beschleunigt.
    Hmm, ok...aber ohne das Invalidate() bekomme ich halt das Problem, das die Zeichnung teilweise verschwindet wenn man mit einem anderen Fenster darüber geht.
    Es müsste also irgendwie erkannt werden wann die Zeichnung nicht mehr komplett ist...
    Ich denk, du mußt nochma neu konzepteln. Das hier:
    Dim AllePunkte As PointF()
    Dim AllePunkte2 As PointF()
    Dim Alle_Kurven()
    Dim P1X_Array(50)
    Dim P1Y_Array(50)
    Dim P2X_Array(50)
    Dim P2Y_Array(50)
    Dim P3X_Array(50)
    Dim P3Y_Array(50)
    scheint mir niedergeschriebene Konfusion.
    du solltest deine Grafiken nicht mehr als Grafiken denken, sondern als Daten.

    Wenn du mehrere Linien malen möchtest, und jede Linie besteht aus mehreren (zu verbindenden) Stützpunkten, dann brauchst du also eine List(Of List(Of Point)) - logisch?

    Aber sowas wird schnell komplizierter. Etwa möchtest du verschiedene Farben für die Linien?

    Dann brauchst du ein spezielles Linie-Objekt, wo eine List(Of Point) drin ist, und ein Pen, mit dem die Linie gezogen werden soll.

    Jedenfalls - diese Daten musstedir in einer Klassenvariable merken, und ausserdem muss da ja auch zugefügt oder sogar gelöscht werden können - was ist mit abspeichern?

    Jo, und ein einem Paint-Event zeichnest du einfach alle Daten. Vlt denkst du, dann zeichnest du ja andauernd und viel zu viel, aber das Paint-Event wird sehr listig geworfen, meist liegt auf den mitgelieferten Graphics auch ein Clip, sodaß nur in einem sehr kleinen Bereich wirklich gezeichnet wird, und die anneren Zeichen-aufrufe rauschen nur so durch.

    Ja, also bring deine App erstmal so weit, dass du so eine List(Of Line) hast, also eine Line-Klasse basteln, und ein User-Instrumentarium, wie er da Linien zufügen kann.
    Sorry, aber ich komme da absolut nicht weiter....

    also das hab ich jetzt gemacht:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim List1_a As List(Of Point)
    3. Dim List1_b As List(Of Point)
    4. Dim list2 As List(Of List(Of Point))
    5. Dim y1 = 10
    6. Dim y2 = 30
    7. Dim y3 = 50
    8. Dim x1_1 = 10
    9. Dim x2_1 = 20
    10. Dim x3_1 = 15
    11. Dim x1_2 = 10
    12. Dim x2_2 = 15
    13. Dim x3_2 = 10
    14. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    15. List1_a.Add(New Point(x1_1, y1))
    16. List1_a.Add(New Point(x2_1, y2))
    17. List1_a.Add(New Point(x2_1, y2))
    18. List1_b.Add(New Point(x1_2, y1))
    19. List1_b.Add(New Point(x2_2, y2))
    20. List1_b.Add(New Point(x2_2, y2))
    21. list2.Add(List1_a)
    22. list2.Add(List1_b)
    23. End Sub
    24. End Class


    und was dann?
    ich glaub, das wird noch nix.
    Da fehlen allerlei Grundlagen.
    Typisierung: du kennst vmtl. deine verwendeten Datentypen nicht. Machma Option Strict On!, und bring Klarheit in die Sache.

    Dann scheint dir nochnicht klar, wozu Auflistungen gut sind - nämlich, dass man nicht hunderte von Variablen braucht, sondern stattdessen nurnoch eine, wo man die Werte reinpackt.

    Hab jetzt deine Daten systematisiert - aber damit hast du nur eine _Lines-Auflistung, aber noch immer kein User-Instrumentarium, da hinzuzufügen/löschen/editieren.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _Lines As New List(Of List(Of Point))
    3. Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
    4. Dim aLine As New List(Of Point)
    5. aLine.Add(New Point(10, 10))
    6. aLine.Add(New Point(20, 30))
    7. aLine.Add(New Point(20, 30))
    8. _Lines.Add(aLine)
    9. aLine.Add(New Point(10, 10))
    10. aLine.Add(New Point(15, 30))
    11. aLine.Add(New Point(15, 30))
    12. _Lines.Add(aLine)
    13. End Sub
    14. Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
    15. For Each line In _Lines
    16. e.Graphics.DrawLines(Pens.Red, line.ToArray)
    17. Next
    18. End Sub
    19. End Class

    Wie du auch sehen kannst - der 3. Punkt jeder Line ist identisch mit ihrem 2.Punkt - das erscheint im Bild natürlich wie eine Linie aus nur 2 Punkten.

    VB.NET-Quellcode

    1. Dim aLine As New List(Of Point)
    2. aLine.Add(New Point(10, 10))
    3. aLine.Add(New Point(20, 30))
    4. aLine.Add(New Point(20, 30))
    5. _Lines.Add(aLine)
    6. aLine.Add(New Point(10, 10))
    7. aLine.Add(New Point(15, 30))
    8. aLine.Add(New Point(15, 30))
    9. _Lines.Add(aLine)

    Da wird aber jetzt in jede Liste immer alle Werte Eingetragen. Also wenn ich für meine erste Kurve Punkt 1-3 hab und für die 2. 4-6
    stehen in _Lines(0) Punkt 1-6, und und Lines(1) nochmal das gleiche. Das ist doch falsch, oder?
    So verbinden sich die Kurven untereinander.

    Sorry, das ich nerve, aber ich muss das halt bis morgen am lauen haben :(
    Da wird aber jetzt in jede Liste immer alle Werte Eingetragen.
    Oh - Fehler! Ich fügte dieselbe "aLine" zweimal zu - dassis natürlich mist - es muss jeweils eine neu erstellte "aLine" sein:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _Lines As New List(Of List(Of Point))
    3. Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
    4. Dim aLine As New List(Of Point)
    5. aLine.Add(New Point(10, 10))
    6. aLine.Add(New Point(30, 30))
    7. aLine.Add(New Point(50, 30))
    8. _Lines.Add(aLine)
    9. aLine = New List(Of Point)'neu erstellen
    10. aLine.Add(New Point(10, 10))
    11. aLine.Add(New Point(100, 30))
    12. aLine.Add(New Point(55, 30))
    13. aLine.Add(New Point(15, 90))
    14. _Lines.Add(aLine)
    15. End Sub
    16. Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
    17. e.Graphics.DrawLines(Pens.Red, _Lines(0).ToArray)
    18. e.Graphics.DrawLines(Pens.Green, _Lines(1).ToArray)
    19. End Sub
    20. End Class
    Jetzt verwende ich auch 2 Farben, um zu verdeutlichen, dasses 2 "Grafiken" sind.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()