OwnerDrawing: Zeichen-Objekte bewegen...

    • VB.NET

    Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von VincentTB.

      OwnerDrawing: Zeichen-Objekte bewegen...

      Hallo...

      Ich mach aus Lust, ein Tutorial, das den Aufbau einer Steuerung beinhaltet...

      Das Bewegen von GDI+ Objekten, zB eines Rectangles, kann durch variierenden Koordinaten erreicht werden...

      Das heißt, dass 2 Variablen benötigt werden, und durch Eingabe von zB der Pfeiltaste-Links, beeinflusst wird...

      zB:


      VB.NET-Quellcode

      1. Dim PosX As Integer = 120
      2. Dim PosY As Integer = 120


      Nun wurde bezweckt, dass PosX;PosY Variablen sind...

      Ausserdem wird noch eine Deklaration benötigt, und zwar, die des Rectangles:

      VB.NET-Quellcode

      1. Dim Player As Rectangle


      Nun kommen wir zur Steuerung:

      VB.NET-Quellcode

      1. Private Sub Form1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
      2. Select Case e.KeyCode
      3. Case Keys.Left
      4. PosX -= 5
      5. Me.Invalidate() ' Das Me.Invalidate() bezweckt, dass der Clientbereich ungültig ist, und neu gezeichnet
      6. Case Keys.Right 'werden soll, das das Paint_Ereignis der Anwendung tut
      7. PosX += 5
      8. Me.Invalidate()
      9. Case Keys.Up
      10. PosY -= 5
      11. Me.Invalidate()
      12. Case Keys.Down
      13. PosY += 5
      14. Me.Invalidate()
      15. End Select
      16. End Sub


      Hier wird nun beschrieben, dass , während des Klickens auf Pfeiltaste-Links, 5 Pixel nach links gesprungen wird... Also vom Ganzen -5 beim erneuten Drücken, abgezogen...

      Das Paint_Ereigniss kann so aussehen:

      VB.NET-Quellcode

      1. Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      2. Player = New Rectangle(PosX, PosY, Width:=25, Height:=25) 'Die Positionen X;Y sind variable...
      3. e.Graphics.FillRectangle(Brushes.Aqua, Player)
      4. End Sub


      Es wird definiert, das Player, das Rectangle, an verschiedenen Positionen gezeichnet werden soll...

      Das Ganze sieht dann so aus:

      VB.NET-Quellcode

      1. Public Class Form1
      2. 'Deklaration der Positionsangaben...
      3. Dim PosX As Integer
      4. Dim PosY As Integer
      5. 'Deklaration des Rectangles
      6. Dim Player As Rectangle
      7. Private Sub Form1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
      8. Select Case e.KeyCode
      9. Case Keys.Left
      10. PosX -= 5
      11. Me.Invalidate() ' Das Me.Invalidate() bezweckt, dass der Clientbereich ungültig ist, und neu gezeichnet
      12. Case Keys.Right 'werden soll, das das Paint_Ereignis der Anwendung tut
      13. PosX += 5
      14. Me.Invalidate()
      15. Case Keys.Up
      16. PosY -= 5
      17. Me.Invalidate()
      18. Case Keys.Down
      19. PosY += 5
      20. Me.Invalidate()
      21. End Select
      22. End Sub
      23. Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      24. Player = New Rectangle(PosX, PosY, Width:=25, Height:=25) 'Die Positionen X;Y sind variable...
      25. e.Graphics.FillRectangle(Brushes.Aqua, Player)
      26. End Sub
      27. End Class



      Kritik oder Feedback,und Ähnliches sind erwünscht...

      Mfg.eniking1998

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

      paar wesentliche Verbesserungen:

      VB.NET-Quellcode

      1. Public Class frmMoveRectangle
      2. Private _Player As New Rectangle(0, 0, 25, 25)
      3. Private Sub Form1_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
      4. If e.KeyCode < Keys.Left OrElse e.KeyCode > Keys.Down Then Return 'nur Pfeiltasten berücksichtigen
      5. Me.Invalidate(_Player) 'bisherige Player-Rect neuzeichnen (löschen)
      6. Select Case e.KeyCode
      7. Case Keys.Left
      8. _Player.X -= 5
      9. Case Keys.Right
      10. _Player.X += 5
      11. Case Keys.Up
      12. _Player.Y -= 5
      13. Case Keys.Down
      14. _Player.Y += 5
      15. End Select
      16. Me.Invalidate(_Player) 'an neuer Position neuzeichnen
      17. e.Handled = True
      18. End Sub
      19. Private Sub Form_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      20. e.Graphics.FillRectangle(Brushes.Aqua, _Player)
      21. End Sub
      22. End Class
      • extra-Positions-Variablen sind nicht erforderlich
      • nur das zu zeichnende Rechteck invalidieren - nicht immer das ganze Form
      • Code redundanzfrei organisieren
      • e.Handled setzen, wenn das Event behandelt wurde
      Warum nicht gleich so:

      VB.NET-Quellcode

      1. Public Class frmMoveRectangle
      2. Private _Player As New Rectangle(0, 0, 25, 25)
      3. Private _Bounds As New Rectangle(0, 0, 250, 250) 'Das Rectangle, in dem sich der _Player bewegen darf
      4. Private _Controls As New Dictionary(Of Keys, Action) From {{Keys.Left, Sub() If _Player.X > _Bounds.X Then _Player.X -= 5}, _
      5. {Keys.Right, Sub() If _Player.X < _Bounds.X + _Bounds.Width - _Player.Width Then _Player.X += 5}, _
      6. {Keys.Up, Sub() If _Player.Y > _Bounds.Y Then _Player.Y -= 5}, _
      7. {Keys.Down, Sub() If _Player.Y < _Bounds.Y + _Bounds.Height - _Player.Height Then _Player.Y += 5}}
      8. Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
      9. If e.KeyCode < Keys.Left OrElse e.KeyCode > Keys.Down Then Return 'nur Pfeiltasten berücksichtigen
      10. If _Controls.ContainsKey(e.KeyCode) Then 'Wenn die Taste im Dictionary vorhanden ist
      11. Me.Invalidate(_Player) 'bisherige Player-Rect neuzeichnen (löschen)
      12. Me.Invoke(_Controls(e.KeyCode)) 'Den der Taste zugehörigen Code ausführen
      13. Me.Invalidate(_Player) 'an neuer Position neuzeichnen
      14. e.Handled = True
      15. End If
      16. MyBase.OnKeyDown(e)
      17. End Sub
      18. Protected Overrides Sub OnPaint(e As PaintEventArgs)
      19. e.Graphics.FillRectangle(Brushes.Aqua, _Player)
      20. MyBase.OnPaint(e)
      21. End Sub
      22. End Class
      • Behandlung der Tasten in ein Dictionary ausgelagert
      • Code wird direkt im OnPaint bzw. OnKeyDown ausgeführt
      • Rectangle eingefügt, welches bestimmt, wohin sich die Figur bewegen kann
      Warum?
      1. Warum Invoke? Du führst keinen Threadwechsel durch->langsam
      2. Warum Dictionary? Sieht übersichtlich aus(vorallem so formatiert) und ist langsamer. Vorallem für solch kurzen Code?
      3. Warum nicht über die Events arbeiten?
      Ich wollte auch mal ne total überflüssige Signatur:
      ---Leer---
      Tut mir Leid wenn ich das so sage, aber so eine Steuerung nervt extrem ! Die Figur bewegt sich bei gedrückter Taste(n) einfach total un-dynamisch.
      Sowas würde ich nie nutzen.
      Hier finde ich ist es richtig gut gemacht. ( [Beta] YaGE - Yet another Game Engine ) Einfach mal Beispiel laden.
      Ist sogar open Source-Code.
      github.com/timmi31061/YaGE/tree/master/YaGE/YaGE
      Hallo, ich hab kurz was gebastelt, und lad es jetzt hier hoch...
      Das Gebastelte bezweckt das Zeichnen eines "Scrollbars"...
      Im Prinzip funktioniert es.

      Sinn und Zweck der Sache ist, einen Einblick in die Funktionsweise zu liefern.

      Hier der Code,
      (Version 0.1)
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Option Strict On
      2. Public Class Form1
      3. Dim Recs_(5) As Rectangle
      4. Dim Clicked_ As Boolean
      5. Dim PosX As Integer
      6. Dim PosY As Integer
      7. Dim PosCursorY As Integer
      8. Dim PosY_ As Integer = 350
      9. Dim Buffer_ As Integer
      10. Dim MouseIsMoving As Boolean
      11. Dim Mouse_ As Integer
      12. Dim BufferXYCoordinates As Integer
      13. Dim Did_ As Boolean
      14. Dim IsLoopRunning As Boolean = True
      15. '-
      16. Private Sub Loop_()
      17. Do While IsLoopRunning = True
      18. Application.DoEvents()
      19. If Mouse_ = 1 Then
      20. MouseIsMoving = False
      21. Else
      22. Mouse_ += 1
      23. End If
      24. If MouseIsMoving = False Then
      25. '-
      26. Buffer_ = Recs_(0).Location.Y
      27. End If
      28. If Not BufferXYCoordinates = System.Windows.Forms.Cursor.Position.X Then
      29. Did_ = False
      30. Else
      31. End If
      32. Loop
      33. End Sub
      34. Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
      35. If Recs_(0).IntersectsWith(Recs_(1)) Then
      36. Clicked_ = True
      37. End If
      38. If Did_ = True Then
      39. MouseIsMoving = True
      40. Else
      41. Mouse_ = 0
      42. Did_ = True
      43. BufferXYCoordinates = e.Location.X
      44. End If
      45. If Recs_(0).IntersectsWith(Recs_(3)) Then
      46. PosCursorY = e.Location.Y
      47. If Recs_(2).Location.Y > e.Location.Y Then
      48. PosY_ += 11
      49. Else
      50. PosY_ -= 11
      51. End If
      52. Else
      53. End If
      54. PosX = e.Location.X
      55. PosY = e.Location.Y
      56. Me.Invalidate()
      57. End Sub
      58. Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
      59. If Did_ = True Then
      60. MouseIsMoving = True
      61. Else
      62. Mouse_ = 0
      63. Did_ = True
      64. BufferXYCoordinates = e.Location.X
      65. End If
      66. If Clicked_ = True Then
      67. PosCursorY = e.Location.Y
      68. If Buffer_ > e.Location.Y Then
      69. PosY_ += 1
      70. Else
      71. PosY_ -= 1
      72. End If
      73. Else
      74. End If
      75. PosX = e.Location.X
      76. PosY = e.Location.Y
      77. Me.Invalidate()
      78. End Sub
      79. Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
      80. Clicked_ = False
      81. End Sub
      82. Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      83. DoubleBuffered = True
      84. Recs_(0) = New Rectangle(x:=PosX, y:=PosY, Width:=0, Height:=0)
      85. e.Graphics.FillRectangle(Brushes.Black, Recs_(0))
      86. Recs_(2) = New Rectangle(x:=200, y:=PosY_, Width:=20, Height:=20)
      87. e.Graphics.FillRectangle(Brushes.Black, Recs_(2))
      88. Recs_(3) = New Rectangle(x:=300, y:=0, Width:=20, Height:=2000)
      89. e.Graphics.FillRectangle(SystemBrushes.ScrollBar, Recs_(3))
      90. Recs_(1) = New Rectangle(x:=300, y:=PosCursorY, Width:=20, Height:=80)
      91. If Recs_(1).IntersectsWith(Recs_(0)) Then
      92. e.Graphics.FillRectangle(Brushes.Red, Recs_(1))
      93. Else
      94. e.Graphics.FillRectangle(Brushes.Blue, Recs_(1))
      95. End If
      96. End Sub
      97. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      98. Me.Show()
      99. Loop_()
      100. End Sub
      101. Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
      102. IsLoopRunning = False
      103. End Sub
      104. End Class

      Uneingeschränkt.
      Unendlich frei durchgehbar,eniking1998
      Mfg.eniking1998

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

      enIking1998 schrieb:

      VB.NET-Quellcode

      1. Application.DoEvents()

      Ist dir nicht so langsam mal klar, DASS HIER VB6 CODE NICHTS ZU SUCHEN HAT? Es gibt Multithreading! Auch in einer Vorversion sollte man zumindest etwas schönen VB.Net Code veröffentlichen und nicht so einen Ranz. Außerdem wären ein paar Kommentare schön. Bitte berichtigen. Außerdem musst du DoubleBuffered nur einmal setzten und nicht bei jedem Paint-Event. Das Me.Show() im Form-Load ist unnötig...

      Edit by ErfinderDesRades: Bitte bleibt höflich!
      Der TE hat dir, @VincentTB:, nichts getan, und Unzulänglichkeiten im Code, seien sie noch so gräuselig, sind in respektvollem Ton anzusprechen.
      Mfg
      Vincent

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