GDI Grundlagen Problem

  • VB.NET

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    GDI Grundlagen Problem

    Hallo Community,
    Ich versuche mir nun seit kurzem (heute:D) gdi anzueignen und stehe vor einem naja, Grundlagen Problem.
    Ich habe versucht mir dir Aufgage zu stellen eine animierte Linie zu erstellen stehe aber vor einem logischen Problem, denn die ich nenne sie mal
    "Ausgangszahlen" für meine Animation werden zwar erhöht mit jedem Programmdurchlauf, allerdings wird die Linie nicht neugezeichnet, ich hoffe ihr könnt mir helfen, denn ich
    glaub ich stehe logisch dort grad aufem Schlauch (Für das Application.DoEvents() dürft ihr mich gerne schlagen.... :pinch: )

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    4. End Sub
    5. Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    6. Dim aa As Integer
    7. aa = 100
    8. Dim bb As Integer
    9. bb = 200
    10. Dim Punkt1 As New Point(CInt(aa), CInt(aa))
    11. Dim Punkt2 As New Point(CInt(bb), CInt(bb))
    12. With e.Graphics
    13. While True
    14. .DrawLine(Pens.Black, Punkt1, Punkt2)
    15. aa = aa + 1
    16. bb = bb + 1
    17. MsgBox("Gezeichnet! " & "Wert Punkt1 : " & aa & " Punkt2: " & bb, MsgBoxStyle.Information)
    18. Application.DoEvents()
    19. End While
    20. End With
    21. End Sub
    22. End Class

    Mit freundlichen Grüßen
    paulkoch95
    Ps: ich erbitte möglichst nur den logischen Ansatz, ich möchts schliesslich lernen und keine sourcecode kopieren^^
    "yippieh! it compiles - ship it!"
    wenn dann musst du statt aa=aa+1:

    VB.NET-Quellcode

    1. Punkt1 = new point(Punkt1.x+1,Punkt1.x+1)

    schreiben.
    Aber du solltest im Paint event nur die Zeichenrei erledigen und mit nem Timer zB. oder in der FormLoad Sub mit deiner While-Schleife eine Variable rauf zählen.
    So machts eigentlich keinen Sinn, wie skyscater bereits sagte, denn du solltest im Paint-Event nur zeichnen - und alles andere wie Variablenhochzählung mit nem Timer machen.
    Ne Variable vom Typen Point sollte man wohl eher so hochzählen: Point1 = New Point(Point1.X + 1, Point1.Y + 1)

    @kinsi: nicht umbedingt, für sowas ist ein Timer ganz in Ordnung.
    Dein Problem ist eher die Endlosschleife im Paint-Event ;) Wie sollte dein Programm jemals eine fertige Zeichnung ausgeben, wenn es in einer Endlosschleife festhängt?

    MfG
    Jup, danke, mit einem Timer funktionierts, aber gibt es nicht auch eine bessere performantere Methode?
    btw, bisheriger funzender Quellcode:

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Public aa As Integer = 100
    4. Public bb As Integer = 200
    5. Public Punkt1 As New Point(CInt(aa), CInt(aa))
    6. Public Punkt2 As New Point(CInt(bb), CInt(bb))
    7. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    8. End Sub
    9. Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    10. Dim aa As Integer
    11. aa = 100
    12. Dim bb As Integer
    13. bb = 200
    14. With e.Graphics
    15. .DrawLine(Pens.Black, Punkt1, Punkt2)
    16. End With
    17. End Sub
    18. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    19. Me.Invalidate()
    20. Punkt1 = New Point(Punkt1.X + 1, Punkt2.X + 1)
    21. Punkt2 = New Point(Punkt2.X + 1, Punkt1.X + 1)
    22. End Sub
    23. End Class
    "yippieh! it compiles - ship it!"
    mega! xD

    Ohne Genau Vorstellung, was du da genau machen willst (ich meine "eine Linie animiert darstellen" ist recht dürftig) will ich nichtmal ne antwort darauf geben xD

    Ein Timer ist auf jeden Fall tausend prozent besser als deine schleife da. Also Timer erstellen, der die variablen hochzählt und .invalidate (zum neuzeichnen) aufruft. Damit würde sich die Linie bewegen - sogar mit relativ konstanter Geschwindigkeit wenn man es mit einer bloßen While-Schleife vergleicht die auf einem schnellerem Prozessor öfters durchlaufen wird...

    Und nochwas zu deinem Code:

    Dim aa As Integer
    aa = 100
    ..wird zu: Dim aa As Integer = 100
    ist leserlicher und spart platz

    das Cint(..) kannst du dir sparen - es handelt sich ja bereits um einen integer. Schalte option strict on, dann siehst du wo du wirklich umwandeln musst^^ ps: nicht cstr oder so nutzten, es gibt .tostring


    edit: Warum brauchst du was performanteres? Wenn du tausen frames pro sekunde rendern willst wird der PC das schon iwie schaffen - dein auge nicht. Dein Problem ist offenbar, dass sich die Linie nicht "schnell" genug bewegt. da musst du dann größere Schritte machen.
    Tipp: berechnungen auslagern und evtl mit kommazahlen rechnen. Erst die Ergebnisse in integer converten. So werden langsame bewegungen möglich. Wie gesagt, ohne zu wissen was du da genau machst kann man dir keine musterlösung geben
    @FreakJNS4
    wie dir aufgefallen sein sollte ist option strict on on:D Deshalb ist da ja das cint, vorher wars da nicht:D
    Mit animierter linie meinte ich nichts weiter als eine Linie die sich schräg über dir Form bewegt und genau das klappt jetzt..
    mfg paulkoch95
    "yippieh! it compiles - ship it!"
    Zum Konzept:

    VB.NET-Quellcode

    1. Dim YourVar As Integer = bla
    2. Dim YourOtherVar As Integer = blup
    3. Dim WithEvents GameTimer As New Timer With {.Interval = 30, .Enabled = True} 'Ein Intervall von 30ms gibt ca. 33 Frames pro Sekunde
    4. Private Sub GameTick() Handles GameTimer.Tick
    5. DoSomething(YourVar)
    6. DoSomethingElse(YourOtherVar)
    7. Me.Invalidate()
    8. End Sub
    9. Private Sub PaintSomeStuff(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
    10. e.Graphics.DrawSomeStuff(YourVar, YourOtherVar)
    11. End Sub


    Das ist das Grundkonzept.

    @kinsi: Bitte erkläre mir wie Du ein geregeltes, gleichmäßiges Neuzeichnen der Form ohne Timer machst? Mit einem Thread, der in einer Endlosschleife läuft und immer wieder Me.Invoke(Sub() GameTick()) aufruft? Genau das macht ein Timer auch.

    @paulkoch95: wieder:

    Bei Dir würde das obrige Konzept angewandt so aussehen:

    VB.NET-Quellcode

    1. Dim Pos1 As Single = 100
    2. Dim Pos2 As Single = 200
    3. Dim WithEvents GameTimer As New Timer With {.Interval = 30, .Enabled = True}
    4. Private Sub GameTick() Handles GameTimer.Tick
    5. Pos1 += 0.5 'oder so
    6. Me.Invalidate()
    7. End Sub
    8. Private Sub PaintSomeStuff(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
    9. e.Graphics.DrawLine(Pens.Black, Pos1, Pos1, Pos2, Pos2)
    10. End Sub


    Noch was zu den Variablen, die an die Draw* Methoden übergeben werden:

    Integer funktioniert immer (bzw. Rectangle, Size, etc.).

    Wenn es genauer her gehen muss kannst Du Single verwenden (bzw. RectangleF, SizeF, etc.).

    Wenn es noch genauer hergehen muss, oder aus anderen Gründen zu viele Konvertierungen von z.B. Double nach Single vorkommen, dann kannst Du Double nehmen.
    Dafür gibt's dann keine Structures wie Rectangle oder Size.
    Die musst Du separat erstellen. Und wenn Du wie in dem Beispiel eine Variable direkt übergibst muss die zu Single konvertiert werden (Integer wäre wieder ungenau).

    VB.NET-Quellcode

    1. Dim Pos1 As Double = 100
    2. Dim Pos2 As Double = 200
    3. Dim WithEvents GameTimer As New Timer With {.Interval = 30, .Enabled = True}
    4. Private Sub GameTick() Handles GameTimer.Tick
    5. Pos1 += 0.5 'oder so
    6. Me.Invalidate()
    7. End Sub
    8. Private Sub PaintSomeStuff(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
    9. 'So:
    10. e.Graphics.DrawLine(Pens.Black, CSng(Pos1), CSng(Pos1), CSng(Pos2), CSng(Pos2))
    11. 'Oder So:
    12. Dim Pos1Sng As Single = CSng(Pos1) 'Bei aufwendigen Konvertierungen lohnt sich das enorm, weil nur einmal konvertiert werden muss.
    13. Dim Pos2Sng As Single = CSng(Pos2)
    14. e.Graphics.DrawLine(Pens.Black, Pos1Sng, Pos1Sng, Pos2Sng, Pos2Sng)
    15. End Sub


    Noch ein Tipp:
    e.Graphics.SmoothingMode gibt an, ob und wie gezeichnetes geglättet wird.
    Zeichne mal mit
    e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.NearestNeighbour
    und einmal mit
    ... .AntiAlias
    Was nötig ist / schöner ist musst Du wissen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

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

    @niko
    danke für die hilfreich und umfassende antwort, sachen wie das anti aliasing habe ich mir schon angeguckt nur halt noch net gebraucht....:=D
    schönen abend an alle
    mfg
    paulkoch95
    "yippieh! it compiles - ship it!"
    Sieh Dir mal außerdem die Überladungen von Me.Invalidate() an, da kannst Du Rechtecke und Regionen (Überlagerungen von Rechtecken) übergeben, und nur dort wird neu gezeichnet.
    Das erhöht die Performance sehr.
    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!