GDI Zeichenfehler anzeigen

  • VB.NET
  • .NET (FX) 4.0

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

    GDI Zeichenfehler anzeigen

    Hallo Community!

    Ich bastel derzeit an einer kleinen Spielerei:
    Einer Animation des Formhintergrunds. Das Ganze funktioniert eigentlich schon ziemlich gut:


    Trotzdem kommt es früher oder später zu einem Fehler, bei dem die Form mit einem roten X übermalt wird (klassischer GDI Fehler)
    Ich denke es liegt daran, dass der Speicher verbraucht wurde, jedoch weiß ich es nicht sicher.

    Wie kann ich mir hier eine Fehlermeldung anzeigen lassen?

    Danke im Vorraus!
    Bilder
    • 122.png

      24,37 kB, 586×426, 257 mal angesehen
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    kannst einerseits nen try catch darum machen und nen breakpoint setzen, auf die Art debugg ich GDI+ immer.
    Ansonsten solltest das denke ich auch aktivieren können:
    msdn.microsoft.com/en-us/library/x85tt0dd.aspx
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    Gather schrieb:

    Wie kann ich mir hier eine Fehlermeldung anzeigen lassen?
    Die sollte eigentlich im Ausgabefenster erscheinen.
    Also dieses löschen, solange noch kein Fehler da ist und dann dort suchen und finden.
    Ansonsten ggf. ein Logging einbauen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Mit folgendem Code wird das Ganze gezeichnet:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Sub DrawGalaxy(g As Graphics, points As BoundPoint(), Optional connectionDistance As Integer = 50, Optional lineAlpha As Integer = 50)
    2. g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    3. If points.Count >= 1 Then
    4. Try
    5. For Each p In points
    6. Using b As New SolidBrush(p.Color)
    7. g.FillEllipse(b, New Rectangle(p.Location.X - CInt(p.Width / 2), p.Location.Y - CInt(p.Width / 2), p.Width, p.Width))
    8. End Using
    9. For Each possiblePoint In points
    10. If possiblePoint IsNot p Then
    11. Dim d As Double = MeasurePointDistance(p.Location, possiblePoint.Location)
    12. If d < connectionDistance Then
    13. Using lgb As New LinearGradientBrush(p.Location, possiblePoint.Location, Color.FromArgb(lineAlpha, p.Color), Color.FromArgb(lineAlpha, possiblePoint.Color))
    14. Using Pen As New Pen(lgb)
    15. g.DrawLine(Pen, p.Location, possiblePoint.Location)
    16. End Using
    17. End Using
    18. End If
    19. End If
    20. Next
    21. Next
    22. Catch ex As Exception
    23. MsgBox(ex.Message)
    24. End Try
    25. End If
    26. End Sub
    27. End Class


    Hab das Try Catch eingebaut, aber es fängt nichts ab. Der Fehler tritt auch nur sporadisch auf, weswegen ich mir langsam ziemlich sicher bin, dass es ein OutOfMemory-Fehler ist..
    Edit:// Hättet ihr Anregungen wie ich einem OutOfMemory Fehelr hier wegbekommen könnte?
    Edit 2:// TryCatch fängt jetzt doch eine OutOfMemory Exception ab. Und mit dem Funktioniert das Ganze auch ziemlich gut, jedoch kann dies nicht der richtige Weg sein.
    Bilder
    • update.PNG

      92,2 kB, 572×419, 250 mal angesehen
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Gather“ ()

    Gather schrieb:

    dass es ein OutOfMemory-Fehler ist.
    Mach Dir dochj mal nen ordentlichen Test-Case, so dass praktisch immer ne Exception kommt.
    Du kannst ja im Output-Fenster den verfügbaren Speicher ausgeben, um das zu verifizieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Blackn0va: Danke! Kleine Spielerei für die MetroSuite :P
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Glaub ich nicht, das ist ja eigentlich nur Pythagoras. Ich würd einfach mal ne Graphics von einer Bitmap erstellen und deine Funktion in ner Schleife ein paar tausend mal aufrufen und gucken was der RAM macht. Erstmal sehe ich allerdings Nichts was ne OutOfMemoryException auslösen würde.

    VB.NET-Quellcode

    1. Math.Round(Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + Math.Pow((p2.Y - p1.Y), 2)), 1)

    Würd zum Messen der Distanz verwendet. @Gonger96 werde ich ausprobieren und später Rückmeldung geben!
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Gather schrieb:

    VB.NET-Quellcode

    1. Math.Round(Math.Sqrt(Math.Pow((p2.X - p1.X), 2) + Math.Pow((p2.Y - p1.Y), 2)), 1)
    ist performancemäßig absolut suboptimal.
    Pack die Differenz in je eine Variable und rechne die Quadrate zu Fuß aus:

    VB.NET-Quellcode

    1. Dim dx = p2.X - p1.X
    2. Dim dy = p2.Y - p1.Y
    3. Dim length = Math.Sqrt(dx * sx + dy * dy)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich habe versucht das ganze bei mir mal nachzustellen, dabei lass ich das ganze mit 15 - 50 BoundPoints alle 500 ms. Zeichnen. Leider kann ich die OutOfMemory Exception nicht reproduzieren, die Diagnosesitzung läuft seit 30 min und der Ram liegt relativ konstant bei 28 MB.
    Stimmt schon, bin drauf gekommen dass der OutOfMemory fehler beim bewegen dieser Punkte entlang ihrer Linie kommt.
    Wie gesagt, grundsätzlich funktioniert es wenn man alles mit nem TryCatch abfängt.
    Aber wie folgt bewege ich die Punkte:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ''' <summary>
    2. ''' Bewegt eine Sammlung von Punkten in Richtung ihrer Ziele.
    3. ''' </summary>
    4. ''' <param name="points">Die zu bewegende Sammlung von Punkten.</param>
    5. ''' <param name="canvas">Die "Leinwand" vom Typ Rectangle, auf welcher die Punkte dargestellt werden sollen.</param>
    6. ''' <param name="DistanceToMove">Die Distanz um welche jeder einzelne Punkt bewegt werden soll.</param>
    7. Public Sub MovePoints(points As BoundPoint(), canvas As Rectangle, DistanceToMove As Long)
    8. For Each p In points
    9. p.MovedBy = CInt(p.MovedBy + DistanceToMove)
    10. If p.ParentLine.Count > 1 Then
    11. Dim dx As Single, dy As Single, sLen As Single
    12. dx = p.ParentLine(1).X - p.ParentLine(0).X
    13. dy = p.ParentLine(1).Y - p.ParentLine(0).Y
    14. sLen = CSng(Math.Sqrt(dx * dx + dy * dy))
    15. p.Location = New Point(CInt((dx * p.MovedBy) / sLen + p.ParentLine(0).X), CInt((dy * p.MovedBy) / sLen + p.ParentLine(0).Y))
    16. If canvas.Contains(p.Location) Then
    17. If p.InCanvas = False Then p.InCanvas = True
    18. Else
    19. If p.InCanvas Then
    20. p.MovedBy = 0
    21. p.InCanvas = False
    22. End If
    23. End If
    24. End If
    25. Next
    26. End Sub


    Wie kann dies einen OutOfMemoryFehler hervorrufen? Alles, genauso wie beim Zeichnen wird doch disposed.

    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Gather“ ()

    Gather schrieb:

    VB.NET-Quellcode

    1. If p.InCanvas = False Then p.InCanvas = True
    machst Du ggf. gleich

    VB.NET-Quellcode

    1. p.InCanvas = True
    Ist der Else-Zweig so gewollt?
    Kommt da das p.InCanvas vom letzten Step?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hmm, ich bin kein Fachmann für sowas aber mir kommt Zeile 17 verdächtig vor. Du erzeugst jedes mal einen neuen Punkt. Wenn dieser nicht zuverlässig von der Garbage Collection entsorgt wird, würde das langsam aber sicher zu einem OutOfMemeory Error führen. Um das zu überprüfen, wären nur geringe Änderungen notwendig.
    Zwischen Zeile 7 und 8 dies einfügen:

    Quellcode

    1. Dim my_Point as New Point(1,1)

    Alternativ wäre es auch möglich, die Deklaration und Initialisierung von my_Point außerhalb von MovePoints vorzunehmen.


    Je nach dem, wie oft MovePoints aufgerufen wird, wäre dann in Zeile 28 noch zu ergänzen:

    Quellcode

    1. my_Point = Nothing


    Zeile 17 dann durch mehrere Zeilen ersetzen:

    Quellcode

    1. my_Point.X = 'Berechnung
    2. my_Point.Y = 'andere Berechnung
    3. p.Location = my_Point

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

    Ein Punkt sind nur 8 Bytes, das ist nicht viel. Ich sehe immer noch nix auffälliges. Kannst du vielleicht mal ein Demo Projekt hochladen? Da können dann auch ruhig ein paar tausend Punkte sein, sodass die Exception auf jeden Fall kommt.
    Point ist ne struct und somit, solang man den nicht in ein Array packt somit stack allocated, wird also nicht vom GC aufgeräumt...
    Also das setzen auf Nothing bringt nichts, da das mit default(Point) gleichzusetzen sein dürfte, was genauso nen Wert ist, nur halt derselbe wie new Point(0,0)^^

    Mach doch einfach eine Diagnosesitzung, dann sollte schon zu sehen sein, was da den Speicher auffüllt, du kannst ja auch ca.Anzahl mancher Objekte abschätzen und wenn es dann einiges mehr ist kannst es vlt. sogar abschätzen, ohne bis zum absturz zu warten
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Da kommt mir aber ne Idee, die anderweitig hilfreich war.
    @Gather Mach da mal an einer sinnvollen Stelle ein GC.Collect() rein.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany: Gute Idee, jedoch was wäre hier eine passende Stelle?
    @jvbsl: Ich muss gestehen dass ich das noch nei gemacht habe, aber ich habs mal probiert.
    Hab ne Analyse und Diagnose gestartet, zu sehen ist, dass die Speichernutzung beim LinearGradientBrush am größten ist:


    Ich hoffe das war das richtige.
    Bilder
    • prob2.PNG

      31,43 kB, 824×555, 200 mal angesehen
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Gather schrieb:

    eine passende Stelle
    Zumindest nach der äußeren Schleife.
    Die Pens hatte ich auch schon in Verdacht. Muss es ein LinearGradientBrush sein?
    Andere kannst Du vorab berechnen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!