Benutzer mit den meisten Antworten
Grafiken mit VB2010 ?

Frage
-
Ich werd noch wahnsinnig weil ich im Web nichts vernünftiges zu Grafiken in VB2010 finde. Mein Problem ist, dass eine auf die Form gezeichnete Grafik beim Me.Refresh() gelöscht wird bzw. auch wenn aus versch. SUBs auf die Form gezeichnet wird. Wie kann ich sowas wie AutoRedraw() bei VB6 unter VB2010 erreichen?
Nicht funktionierender Beispielcode einer analogen Uhr, wo ich versucht habe die Grafik zu speichern:
(Es ist nur eine normale Form samt einem Timer erforderlich).
---
Public Class Form1
Public x0, y0, r, rs, rm, rh As Integer ' Mittenkoordinaten, Radien
Public g As Graphics
Public m_Face As Bitmap
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
DrawFace()
Timer1.Interval = 200
Timer1.Enabled = True
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim s, m, h, x1, y1 As Integer ' Zeitwerte, Zeigerkoordinaten
If m_Face Is Nothing Then Exit Sub
' Ziffernblatt
e.Graphics.DrawImage(m_Face, 0, 0)
s = Int(Math.PI / 30 * Now.Second) ' Winkel s
m = Int(Math.PI / 30 * Now.Minute) ' Winkel m
h = Int(Math.PI / 6 * Now.Hour) ' Winkel h
' Textlabel mit Uhrzeit
' LabelTime.Text = Now.ToString
' Pens generieren
Dim hour As New Pen(Color.Blue)
Dim minute As New Pen(Color.Red)
Dim second As New Pen(Color.Black)
hour.Width = 8
minute.Width = 4
second.Width = 1
' alte Zeiger löschen
Dim pinsel As New SolidBrush(Me.BackColor)
g.FillEllipse(pinsel, x0 - rs, y0 - rs, rs * 2, rs * 2)
' Zeiger zeichnen
x1 = Int(x0 + rh * Math.Sin(h) + 0.5)
y1 = Int(y0 - rh * Math.Cos(h) + 0.5)
g.DrawLine(hour, x0, y0, x1, y1)
x1 = Int(x0 + rm * Math.Sin(m) + 0.5)
y1 = Int(y0 - rm * Math.Cos(m) + 0.5)
g.DrawLine(minute, x0, y0, x1, y1)
x1 = Int(x0 + rs * Math.Sin(s) + 0.5)
y1 = Int(y0 - rs * Math.Cos(s) + 0.5)
g.DrawLine(second, x0, y0, x1, y1)
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Invalidate()
End Sub
Private Sub DrawFace()
' Ziffernblatt zeichnen
m_Face = New Bitmap(Me.ClientRectangle.Width, Me.ClientRectangle.Height)
Dim g As Graphics = Graphics.FromImage(m_Face)
Dim stifth As New Pen(Color.Black)
Dim i As Integer
x0 = Int(Me.ClientRectangle.Width / 2)
y0 = Int(Me.ClientRectangle.Height / 2)
r = IIf(x0 < y0, x0 * 0.9, y0 * 0.9) ' radius
rs = r * 0.9
rm = r * 0.8
rh = r * 0.6
stifth.Width = 5
'g = Me.CreateGraphics
For i = 0 To 360 Step 6 ' Minuten
g.DrawPie(Pens.Black, x0 - r, y0 - r, r * 2, r * 2, i, 360)
Next
For i = 0 To 360 Step 30 ' Stunden
g.DrawPie(stifth, x0 - r, y0 - r, r * 2, r * 2, i, 360)
Next
Dim pinsel As New SolidBrush(Me.BackColor)
g.FillEllipse(pinsel, x0 - rs, y0 - rs, rs * 2, rs * 2)
' Ziffernblatt anzeigen
Me.BackgroundImage = m_Face
End Sub
End Class
Antworten
-
Hallo,
Du solltest Dich zunächst auseinandersetzen mit Grafik und Zeichnen in Windows Forms
Und eine Grundregel dabei beherzigen:
Alle Grafikobjekte (Pen, Brushes etc.) sollten direkt nach der Verwendung freigegeben werden.Will man wie hier (einen Teil) des Hintergrunds wiederholt zeichnen, so kann man dazu die
doppelte Pufferung benutzen, beschrieben unter: Verwenden der doppelten PufferungAbseits davon solltest Du Dir angewöhnen mit Option Strict On zu arbeiten, dass vermeidet einige Fehler.
Ich habe Deinen Code (auf die Schnelle) mal entsprechend umgebaut.
Ergänzt ist ein Resize, damit die Uhr sich anpasst, wenn die Formulargröße sich ändert.Option Explicit On Option Infer On Option Strict On Public Class UhrForm Private m_Face As BufferedGraphics Private WithEvents Timer1 As New Timer() Public Sub New() ' Neuzeichnen bei Größenänderung und alles im Paint Ereignis Me.SetStyle(ControlStyles.ResizeRedraw Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint, True) ' Mindestgröße Me.MinimumSize = New Size(120, 120) InitializeComponent() End Sub Private Sub Form_Resize(ByVal sender As Object, ByVal e As EventArgs) _ Handles MyBase.Resize ' Hintergrundgröße geändert Me.DrawFace() End Sub Private Sub Form_Load(ByVal sender As Object, ByVal e As EventArgs) _ Handles MyBase.Load Me.DrawFace() Timer1.Interval = 500 Timer1.Enabled = True End Sub Private Sub Form_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles MyBase.Paint Dim now = DateTime.Now Dim second = Math.PI / 30.0 * now.Second Dim minute = Math.PI / 30.0 * now.Minute Dim hour = Math.PI / 6.0 * now.Hour ' Console.WriteLine("Paint {0} - {1} {2} {3}", now, hour, minute, second) Dim centerX = CInt(Me.ClientRectangle.Width / 2) Dim centerY = CInt(Me.ClientRectangle.Height / 2) Dim radius = CInt(Math.Min(centerX, centerY) * 0.9) Dim radiusHour = CInt(radius * 0.6) Dim radiusMinute = CInt(radius * 0.8) Dim radiusSecond = CInt(radius * 0.9) ' alte Zeiger löschen If m_Face IsNot Nothing Then m_Face.Render(e.Graphics) End If 'Using brush As New SolidBrush(Me.BackColor) ' e.Graphics.FillEllipse(Brush, centerX - radiusSecond, centerY - radiusSecond, radiusSecond * 2, radiusSecond * 2) 'End Using ' Zeiger zeichnen Dim x1 = CInt(centerX + radiusHour * Math.Sin(hour) + 0.5) Dim y1 = CInt(centerY - radiusHour * Math.Cos(hour) + 0.5) Using hourPen = New Pen(Color.Blue, 8) e.Graphics.DrawLine(hourPen, centerX, centerY, x1, y1) End Using x1 = CInt(centerX + radiusMinute * Math.Sin(minute) + 0.5) y1 = CInt(centerY - radiusMinute * Math.Cos(minute) + 0.5) Using minutePen As New Pen(Color.Red, 4) e.Graphics.DrawLine(minutePen, centerX, centerY, x1, y1) End Using x1 = CInt(centerX + radiusSecond * Math.Sin(second) + 0.5) y1 = CInt(centerY - radiusSecond * Math.Cos(second) + 0.5) Using secondPen As New Pen(Color.Black, 1) e.Graphics.DrawLine(secondPen, centerX, centerY, x1, y1) End Using End Sub Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick Me.Invalidate() End Sub Private Sub DrawFace() ' Re-create the graphics buffer for a new window size. BufferedGraphicsManager.Current.MaximumBuffer = Me.Size If m_Face IsNot Nothing Then m_Face.Dispose() m_Face = Nothing End If m_Face = BufferedGraphicsManager.Current.Allocate(Me.CreateGraphics(), Me.ClientRectangle) Dim centerX = CInt(Me.ClientRectangle.Width / 2) Dim centerY = CInt(Me.ClientRectangle.Height / 2) Dim radius = CInt(Math.Min(centerX, centerY) * 0.9) Dim radiusSecond = CInt(radius * 0.9) ' Hintergrund Using brush = New SolidBrush(Me.BackColor) m_Face.Graphics.FillRectangle(brush, 0, 0, Size.Width, Size.Height) End Using If radius > 0 Then ' Minuten For i = 0 To 360 Step 6 m_Face.Graphics.DrawPie(Pens.Black, centerX - radius, centerY - radius, radius * 2, radius * 2, i, 360) Next ' Stunden Using Pen As New Pen(Color.Black, 5) For i = 0 To 360 Step 30 m_Face.Graphics.DrawPie(Pen, centerX - radius, centerY - radius, radius * 2, radius * 2, i, 360) Next End Using ' Sekunden Using brush As New SolidBrush(Me.BackColor) m_Face.Graphics.FillEllipse(brush, centerX - radiusSecond, centerY - radiusSecond, radiusSecond * 2, radiusSecond * 2) End Using End If End Sub End Class
Auch ist findet mehr Fliesskomma-Arithmetik statt - sonst lahmt der Sekundenzeiger ;-)Gruß Elmar
- Als Antwort vorgeschlagen Robert BreitenhoferModerator Freitag, 10. Dezember 2010 11:12
- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 21. Dezember 2010 17:50