Zeichnen auf Form ohne Flimmern

benurb

Mitglied
Hi,

Bin gerade dabei ein Programm zu schreiben, das bei jeder Mausbewegung eine Grafik auf dem Form verändert (einen Kompass, wobei sich die Nadel bewegt und der Kreis statisch bleiben soll).

Quellcode:
Code:
Public Class Form1

    Dim imageOffsetTop As Integer = 20
    Dim imageOffsetLeft As Integer = 50
    Dim rectangleRadius As Integer = 100
    Dim angle = 0
    Dim gegenkathete As Integer = 0
    Dim ankathete As Integer = 0
    Dim cX As Integer = imageOffsetLeft + rectangleRadius
    Dim cY As Integer = imageOffsetTop + rectangleRadius

    Dim lastMousePoint As Point = New Point(0, 0)
    Dim lastMouseCounter As Integer = 0

    Dim g As Graphics

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call
        Me.SetStyle(ControlStyles.DoubleBuffer Or ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint, True)
        Me.UpdateStyles()
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        g = Me.CreateGraphics()
    End Sub

    Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        lastMouseCounter += 1
        If lastMouseCounter Mod 2 <> 0 Then
            Return
        End If

        txtMouseX.Text = e.X
        txtMouseY.Text = e.Y

        If (lastMousePoint.X < e.X And cY > e.Y) Or (lastMousePoint.X > e.X And cY < e.Y) Then
            angle += 1
        Else
            angle -= 1
        End If

        Me.Refresh()
        lastMousePoint = New Point(e.X, e.Y)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        angle += 1

        Console.WriteLine("Winkel: " & angle & " Gk: " & gegenkathete & " Ak:" & ankathete)
    End Sub

    Private Sub PicBoxNadel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PicBoxNadel.Paint

        Dim p As Pen

        p = New Pen(System.Drawing.Color.Black, 2)

        gegenkathete = Math.Sin(angle * (Math.PI / 180)) * rectangleRadius
        ankathete = Math.Cos(angle * (Math.PI / 180)) * rectangleRadius
        g.DrawLine(p, cX - ankathete, cY - gegenkathete, cX - ankathete + 20, cY - gegenkathete + 20)
    End Sub

    Private Sub PicBoxKreis_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PicBoxKreis.Paint
        Dim p As Pen
        Dim r As Rectangle

        p = New Pen(System.Drawing.Color.Black, 2)
        r = New Rectangle(imageOffsetLeft, imageOffsetTop, rectangleRadius * 2, rectangleRadius * 2)
        g.DrawEllipse(p, r)
    End Sub
End Class

MyPanel.vb
Code:
Class MyPanel
    Inherits System.Windows.Forms.Panel
    Public Sub New()
        MyBase.New()
        'The reason for this class:
        'The following protected property needed to be set to reduce flicker
        Me.DoubleBuffered = True
        Me.SetStyle(ControlStyles.DoubleBuffer Or ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint, True)
        Me.UpdateStyles()
    End Sub

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        MyBase.Dispose(disposing)
    End Sub
End Class

Nun flimmert das ganze aber wie die Pest :D
Die Frage ist jetzt wie man entweder das Flimmern wegbekommt (Double Buffering funktioniert nicht) oder nur PicBoxNadel aktualisiert. Wenn man das nämlich über PicBoxNadel.Refresh() macht zieht sich eine schöne Linie um den Kreis, weil ja das Form an sich nicht aktualisiert wird (die alten Zeichnungen werden also wohl nicht entfernt). Wäre nett wenn mir jemand helfen könnte. Ich komm einfach auf keinen grünen Zweig.

Danke im voraus
Benni
 
erstmal würde ich PicBoxNadel.Refresh aufrufen bei Me.Refresh wird ja das komplette Formular neu gezeichnet.
Oder eventuell sogar besser PicBoxNadel.Invalidate, dann teilst du nur mit das sich das Control neu zeichnen soll und erzwingst es nicht.

Und den Kreis würde ich eventuell gleich direkt in nem Bitmap halten und nicht immer neu zeichnen lassen.
 
Dieses Problem hatte ich auch schon öfters.
Es reicht aber nicht aus, die Eigenschaft "DoubleBuffered" des Forms auf true zu setzen, wenn du nicht nur auf das Form direkt zeichnest, sondern auch in verschiedene Controls.
Folgende Lösung löst dieses Problem (dieser Code muss in jedem Control stehen (z.B. im Konstruktor), das DoubleBuffered sein soll):
Visual Basic:
Me.SetStyle(ControlStyles.DoubleBuffer, true);
Me.UpdateStyles();

MfG
Fabsch
 
Zuletzt bearbeitet:
Hallo benurb,

warum erzeugst du ein globales Graphics-Objekt? Das bekommst du doch über die PaintEventArgs.

Gruß
MCoder
 
naja ich kenn mich damit nicht so richtig aus. wie würde ich das denn ohne globales grafikelement machen?

Fabsch: Das habe ich bereits in der MyPanel.vb Datei gemacht.
 
Zuletzt bearbeitet:
Das Graphics-Object wird mit dem Parameter "e" übergeben.
Visual Basic:
Private Sub PicBoxNadel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PicBoxNadel.Paint

    e.Graphics.DrawLine( ... )

End Sub

Ansonsten zeichnest du bei den Paint-Events der Controls "PicBoxNadel" und "PicBoxKreis" nämlich nicht auf das Control, sondern auf die Form, was wahrscheinlich die Flackerei verursacht.

Gruß
MCoder
 
Zuletzt bearbeitet:
Danke MCoder. So hats nun im Endeffekt ohne Flimmern funktioniert. Hatte mich schon gewundert, dass ich das Panel positionieren kann wie ich will und die gezeichnete Grafik trotzdem an derselben Position bleibt :D
 

Neue Beiträge

Zurück