15.2 Die Klasse Graphics
Um ein Bild zeichnen zu können, brauchen Sie als Erstes eine Zeichenfläche. Der Leinwand oder dem Papier entspricht in .NET ein Objekt vom Typ Graphics. Es hat Methoden zum Zeichnen, Messen, Transformieren und Beschneiden. Die dafür notwendigen Informationen, zum Beispiel die Auflösung des Bildschirms, bilden den sogenannten Grafikkontext. Weil die Kombination von Stiften oder Pinseln mit dem Grafikkontext das Ergebnis einer Zeichenoperation beeinflusst, ist der Grafikkontext sehr wichtig. In der Realität verhält sich ja zum Beispiel Aquarellpapier anders als eine Schiefertafel. Bei durchscheinenden Farben sind bereits gezeichnete Flächen von Bedeutung. Daher gilt: Ohne Graphics-Objekt gibt es auch keine Zeichnung.
Die Zeichenoperationen auf dem Graphics-Objekt gliedern sich in zwei Gruppen:
- Methoden mit dem Präfix Draw erzeugen Strichzeichnungen. Sie können damit Rechtecke zeichnen, aber auch Linien, Kreise, Ellipsen, Kreis- und Ellipsenabschnitte, Polygone, Bezierkurven, Icons und Bilder sowie Texte. Typische Vertreter dieser Gruppe sind DrawRectangle, DrawLine und DrawEllipse.
- Methoden mit dem Präfix Fill erzeugen gefüllte Flächen geometrischer Figuren, zum Beispiel FillEllipse und FillRectangle.
Über die Zeichenoperationen hinaus beinhaltet Graphics auch viele Eigenschaften, die Informationen in Zusammenhang mit dem Grafikkontext bereitstellen.
15.2.1 Ein Graphics-Objekt besorgen
Um in ein Steuerelement zeichnen zu können, brauchen Sie eine Referenz auf ein Graphics-Objekt. Das Besondere an Graphics ist, dass die Klasse keinen öffentlichen Konstruktor hat und deshalb nicht instanziiert werden kann. An die Referenz kommen Sie auf drei Wegen:
- Dem Ereignishandler des Paint-Ereignisses einer Komponente wird ein Objekt vom Typ PaintEventArgs übergeben. Die Eigenschaft Graphics dieses Objekts liefert das Graphics-Objekt, das auf dem jeweiligen Control basiert.
- Die Fabrikmethode CreateGraphics eines Steuerelements erzeugt ein Graphics-Objekt.
- Der Rückgabewert der statischen Methode FromHwnd der Klasse Graphics ist ein Graphics-Objekt.
Paint-Ereignis
Das Paint-Ereignis wird ausgelöst, wenn zumindest Teile eines Steuerelements neu gezeichnet werden müssen. Das ist auch der Fall, wenn das Steuerelement zum ersten Mal sichtbar wird oder wenn es durch andere Fenster verdeckt war. Deshalb werden Zeichenanweisungen vorzugsweise in Paint codiert. Paint wird aber auch dann ausgelöst, wenn sich die Größe des Formulars ändert. Standardmäßig werden dabei nur die Bereiche neu gezeichnet, die bei einer Vergrößerung hinzukommen. Grafiken, die von der Größe der Komponente abhängig sind, passen sich der Größenänderung nicht automatisch an, was zu sehr hässlichen Effekten führt. Wir werden darauf gleich noch einmal eingehen.
Sehen wir uns den Ereignishandler von Paint einer Form an:
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) ... End Sub
Der zweite Parameter ist ein PaintEventArgs-Objekt, das uns mit
- ClipRectangle
- Graphics
ereignisspezifische Daten zur Verfügung stellt. Graphics liefert die Referenz auf den Grafikkontext der Komponente, und ClipRectangle gibt das neu zu zeichnende Rechteck in seiner Breite und Höhe an. Der Rückgabewert ist vom Typ Rectangle.
Public ReadOnly Property ClipRectangle As Rectangle |
Damit sind Sie in der Lage, die Zeichenoperationen auf die Bereiche zu beschränken, die ein Neuzeichnen erforden.
Paint-Ereignis im Code auslösen
Manchmal ist es erforderlich, das Neuzeichnen einer Komponente zu erzwingen. Dazu ist das programmgesteuerte Auslösen von Paint erforderlich, zum Beispiel durch die Methode Invalidate. Mit
pictureBox1.Invalidate()
wird das Paint-Ereignis eines Steuerelements namens pictureBox1 ausgelöst und der gesamte Bereich neu gezeichnet.
Bei aufwändigen Grafiken kann das zu lange dauern. Deshalb hat Invalidate Überladungen mit der Angabe des Bereichs, der neu gezeichnet werden muss. Eine Überladung erwartet beispielsweise die Beschreibung durch die Angabe eines Rectangle-Objekts:
pictureBox1.Invalidate(New Rectangle(100, 100, _
pictureBox1.ClientSize.Width – 100, pictureBox1.ClientSize.Height – 100)
CreateGraphics aufrufen
Manchmal ist es notwendig, außerhalb des Paint-Ereignisses in eine Komponente zu zeichnen. Dann muss man sich die Graphics-Referenz des entsprechenden Elements mit der parameterlosen Methode CreateGraphics besorgen. Möchten Sie, dass das Klicken auf einen Button bewirkt, ein Rechteck in die Form zu zeichnen, kann der Code wie folgt aussehen:
Private Sub button1_Click(sender As Object, e As EventArgs)
Dim graph As Graphics = Me.CreateGraphics()
graph.DrawRectangle(New Pen(Brushes.Blue, 10), 20, 20, 100, 100)
End Sub
Die Methode DrawRectangle des Graphics-Objekts beschreibt hier ein Quadrat, das in einer Strichstärke von 10 Pixeln gezeichnet wird. Der Ursprungspunkt des Quadrats (die Ecke links oben) hat je 20 Pixel Abstand vom Rand des Arbeitsbereichs der Form. Die Seitenlänge des Quadrats beträgt 100 Pixel.
Graphics-Referenz mit FromHwnd
Eine Alternative zu CreateGraphics bietet die klassengebundene Methode FromHwnd der Klasse Graphics. Die Methode erwartet als Argument einen Handle auf die Komponente, in die gezeichnet werden soll. Diesen stellt die Eigenschaft Handle bereit, die in der Klasse Control definiert ist und von allen Steuerelementen geerbt wird.
Angenommen, in einer Form befindet sich eine PictureBox namens pictureBox1 und wir wollen auf das Anklicken einer Schaltfläche hin in dieses Steuerelement eine Diagonale zeichnen, so können wir den Ereignishandler von Click wie folgt implementieren:
Private Sub button1_Click(sender As Object, e As EventArgs)
Dim gr As Graphics = Graphics.FromHwnd(pictureBox1.Handle)
gr.DrawLine(New Pen(Brushes.Black), 0, 0, 100, 100)
End Sub
15.2.2 Neuzeichnen mit ResizeRedraw und Invalidate
Wird eine Grafik teilweise verdeckt, beispielsweise durch eine andere Form, und anschließend wieder sichtbar, wird nicht die gesamte Grafik neu gezeichnet, sondern nur der Teil, der verdeckt war. Dasselbe passiert auch, wenn eine Form vergrößert wird. Sind die grafischen Routinen abhängig von der Größe des Fensters, tritt ein Effekt auf, wie Sie ihn in Abbildung 15.1 sehen können.
Abbildung 15.1 Vergrößern ohne Neuzeichnen
Den Abbildungen liegt der folgende Code im Paint-Ereignis der Form zugrunde. Beachten Sie, dass die Größe der Ellipsen mit den Abmessungen des Clientbereichs der Form skaliert.
Private Sub Ellipsen_Paint(sender As Object, e As PaintEventArgs) Dim gr As Graphics = e.Graphics Dim w As Integer = Me.ClientSize.Width, h = Me.ClientSize.Height For i As Integer = 0 To 4 gr.DrawEllipse(New Pen(Brushes.Black), i * w \ 10, i * h \ 10, _ w – 2 * i * w \ 10, h – 2 * i * h \ 10) Next End Sub
Wird das Fenster zur Laufzeit vergrößert, wird Paint zwar mehrfach ausgelöst, aber es werden immer nur die neu hinzugekommenen Bereiche neu gezeichnet. Das Resultat sehen Sie im rechten Fenster der Abbildung – es sieht dilettantisch aus.
Wenn Sie die Eigenschaft ResizeRedraw der Form auf den Wert True setzen, wird bei jeder Größenänderung der gesamte Bereich der Form neu gezeichnet. Die Eigenschaft wird nicht im Eigenschaftsfenster angezeigt. Der Konstruktor oder das Load-Ereignis der Form sind geeignet, den Wert festzulegen:
Private Sub Ellipsen_Load(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.Load
Me.ResizeRedraw = True
End Sub
ResizeRedraw ist Protected definiert, und damit ist der Zugriff nur aus der Klasse Control selbst heraus möglich oder aus einer Klasse, die davon abgeleitet ist. Bei der benutzerdefinierten Form ist das der Fall, weil diese von der Basisklasse Form abgeleitet ist, die ihrerseits die Klasse Control beerbt.
15.2.3 Zerstören grafischer Objekte (Dispose)
Wenn eine Klasse die Schnittstelle IDisposable implementiert, ruft der Garbage Collector (GC) während des Bereinigungsprozesses im Destruktor automatisch die Dispose-Methode des Objekts auf. Wann der GC dies tut, ist nicht vorhersehbar. Das kann sich nachteilig auswirken, wenn die Speicherressourcen knapp werden: Das System verlangsamt sich.
Insbesondere Anwendungen, die eine sehr große Anzahl grafischer Objekte erzeugen, sind davon betroffen, denn grafische Objekte verbrauchen meist sehr viele Speicherressourcen. Der GC wird aktiv, wenn sich die Ressourcen verknappen. Durch den GC verlangsamt sich dann das System in einem Ausmaß, das nicht akzeptabel ist. Ein kleines Beispiel soll das verdeutlichen.
Private Sub button1_Click(sender As Object, e As EventArgs)
Dim starttime As DateTime = DateTime.Now
Dim bmp As Bitmap
For i As Integer = 0 To 999
bmp = new Bitmap(1000, 1000)
bmp.Dispose()
Next
Dim difftime As TimeSpan = DateTime.Now.Subtract(starttime)
Me.Text = String.Format( _
"{0}.{1} Sekunden", difftime.Seconds, difftime.Milliseconds)
End Sub
In einer Schleife werden 1000 Bitmap-Objekte der Größe 1000 × 1000 Pixel erzeugt. Die Zeit für die Ausführung der Operation wird gemessen und in der Titelleiste der Form angezeigt. Die Zeitspanne, die für das Erzeugen der Bitmaps benötigt wird, schwankt in Abhängigkeit von der Hardware-Ausstattung des Systems. Auf meinem Rechner betrug sie etwa zehn Sekunden – wenn in der Schleife jedes neue Bitmap-Objekt mit Dispose sofort aufgegeben wird. Durch Auskommentieren von Dispose lief die Operation doppelt so lange.
15.2.4 Koordinatensystem
Bevor wir uns mit den Zeichenmethoden der Klasse Graphics beschäftigen, müssen wir das zugrunde liegende GDI+-Koordinatensystem verstehen, auf das sich die Grafikroutinen beziehen. Das Koordinatensystem in einem Graphics-Objekt ist vordefiniert, lässt sich aber nach eigenen Wünschen modifizieren, zum Beispiel durch Umstellung der Maßeinheit oder durch die Festlegung eines anderen Koordinatenursprungs.
Maßeinheiten
Die Standardmaßeinheit ist Pixel. Mit der Eigenschaft PageUnit des Graphics-Objekts können wir diese Einstellung festlegen oder den aktuellen Wert abrufen. Der Eigenschaft können wir die Konstanten aus der GraphicsUnit-Enumeration zuweisen (siehe Tabelle 15.1).
Konstante | Einheit |
Display |
1/100 Zoll |
Document |
1/300 Zoll |
Inch |
Zoll (2,54 cm) |
Millimeter |
Millimeter |
Pixel |
Bildschirmpixel |
Point |
1/72 Zoll |
World |
Abstrakte Einheit des globalen Koordinatensystems: verboten! |
Abbildung 15.2 zeigt für das folgende Codefragment die Auswirkung einer Änderung der Einheit vom Standard GraphicsUnit.Pixel in GraphicsUnit.Point anhand zweier Rechtecke, deren Werte für Abmessung und Position identisch sind. Zur besseren optischen Unterscheidung ist das erste Rechteck mit der Farbe Color.Azure gefüllt, das zweite wird nur durch die schwarzen Randlinien dargestellt.
Private Sub Einheit_Paint(sender As Object, e As PaintEventArgs)
e.Graphics.FillRectangle(New SolidBrush(Color.Azure), 10, 10, 100, 100)
e.Graphics.PageUnit = GraphicsUnit.Point
e.Graphics.DrawRectangle(New Pen(Color.Black), 10, 10, 100, 100)
End Sub
Abbildung 15.2 Einheitenwechsel
Skalierung der Grafikausgabe
Die Eigenschaft PageScale des Graphics-Objekts dient dazu, die grafische Ausgabe um einen bestimmten Faktor zu skalieren. Verwenden Sie die beiden Eigenschaften PageUnit und PageScale parallel, multiplizieren sich die Faktoren. In Abbildung 15.3 können Sie die Auswirkungen von PageScale sehen. Beachten Sie, dass sich auch die Linienbreite entsprechend verändert.
Private Sub Skalierung_Paint(sender As Object, e As PaintEventArgs)
e.Graphics.DrawRectangle(New Pen(Color.Black), 5, 5, 50, 50)
e.Graphics.PageScale = 2
e.Graphics.DrawRectangle(New Pen(Color.Black), 5, 5, 50, 50)
End Sub
Abbildung 15.3 Skalierung
15.2.5 Koordinatenursprung
Standardmäßig liegt der Ursprungspunkt in der linken oberen Ecke des Clientbereichs (0, 0). Die positive Richtung der x-Achse zeigt dabei nach rechts, die positive Richtung der y-Achse nach unten und unterscheidet sich damit von der mathematischen, die nach oben zeigt.
Mit den XxxTransform-Methoden der Graphics-Klasse lässt sich das Koordinatensystem verändern. Mit TranslateTransform wird das Koordinatensystem um die in den beiden Parametern übergebenen Werte verschoben. Mit
graph.TranslateTransform(10, –30)
sind das zehn Einheiten in positiver x-Richtung und 30 Einheiten in negativer Richtung.
Die Methode ScaleTransform skaliert das Koordinatensystem sowohl in x- als auch in y-Richtung. Im Gegensatz zur Methode PageScale werden mit ScaleTransform auch gezeichnete Schriften mitskaliert.
Der an die Methode RotateTransform übergebene Winkel dreht das Koordinatensystem um den angegebenen Betrag. Die Rotationsachse ist der Ursprung. Wollen Sie das Koordinatensystem wieder an seine Ausgangsposition zurückversetzen, können Sie alle Transformationen mit ResetTransform zurücksetzen.
Beispiel: Verschiebung des Koordinatensystems
Wir wollen uns nun die Verschiebung des Koordinatensystems an einem Beispielprogramm ansehen (siehe Abbildung 15.4). In einer PictureBox werden die Achsen des Koordinatensystems in Rot gezeichnet. Über zwei Schieberegler können sowohl die x- als auch die y-Achse innerhalb der Clientfläche beliebig verschoben werden. Ausgehend vom Ursprung des Koordinatensystems wird ein Rechteck mit einem schwarzen Rahmen gezeichnet, dessen Position sich bezüglich des Koordinatensystems nicht ändert. Es wird also in gleichem Maße mitverschoben.
Abbildung 15.4 Das Beispiel »Transformation«
'...\GDI\Koordinaten\Transformation.vb |
Public Class Transformation Private Sub Transformation_Load(sender As Object, e As EventArgs) _ Handles MyBase.Load DeltaY.Maximum = Zeichnung.ClientSize.Width DeltaX.Maximum = Zeichnung.ClientSize.Height DeltaY.TickFrequency = DeltaY.Maximum / 10 DeltaX.TickFrequency = DeltaX.Maximum / 10 End Sub Private Sub Zeichnung_Paint(sender As Object, e As PaintEventArgs) _ Handles Zeichnung.Paint Dim g As Graphics = e.Graphics ' neues Koordinatensystem festlegen g.TranslateTransform(DeltaX.Value, DeltaY.Value) ' x-Koordinate neu zeichnen g.DrawLine(New Pen(Color.Red), -DeltaX.Value, 0, _ Zeichnung.ClientSize.Width – DeltaX.Value, 0) ' y-Koordinate zeichnen g.DrawLine(New Pen(Color.Red), 0, -DeltaY.Value, 0, _ Zeichnung.ClientSize.Height – DeltaY.Value) ' Rechteck zeichnen g.DrawRectangle(New Pen(Color.Black), 0, 0, 100, 100) End Sub Private Sub Ursprung(ByVal sender As Object, ByVal e As EventArgs) _ Handles DeltaX.Scroll, DeltaY.Scroll Zeichnung.Invalidate() End Sub End Class
Die Grafik der PictureBox wird im Ereignis Paint erstellt. Zuerst wird mit
g.TranslateTransform(DeltaX.Value, DeltaY.Value)
das Koordinatensystem an die Position verschoben, die durch die Werte der beiden Schieberegler DeltaX und DeltaY gegeben sind. Alle Zeichenoperationen des Graphics-Objekts verwenden die neue Position des Koordinatensystems. In unserem Beispiel sind das die Aufrufe der Methoden Drawline und DrawRectangle.
Bei jeder Auslösung des Paint-Ereignisses wird die Arbeitsfläche des zugrunde liegenden Steuerelements neu gezeichnet. Grafische Elemente, die vorher in dem Steuerelement zu sehen waren, werden damit gleichzeitig auch verworfen. Das erleichtert uns die Programmierung ganz wesentlich, denn bei einer Verschiebung des Koordinatensystems legen wir keinen Wert mehr darauf, die Grafik außerdem auf der alten Position zu sehen.
Das Scroll-Ereignis des Schiebereglers tritt auf, wenn er durch eine Maus- oder Tastaturaktion bewegt wird. Da unsere Grafikroutinen im Paint-Ereignis der PictureBox implementiert sind, müssen wir nur noch dieses Ereignis auslösen. Genau dies leistet die Invalidate-Methode der PictureBox.
15.2.6 Zeichnen mit der Klasse Graphics
Die Klasse Graphics ist die Basisklasse grafischer Operationen. Sie stellt Methoden bereit, mit denen unterschiedliche geometrische Figuren gezeichnet werden können (siehe Tabelle 15.2). Die meisten Methoden sind vielfach überladen.
Methode | Gezeichnete Figur |
DrawArc |
Ellipsenbogen |
DrawBezier |
Durch vier Point-Strukturen definierte Bézier-Splinekurve |
DrawBeziers |
Bézier-Splinekurvenzug, definiert durch ein Array von Point-Strukturen; der Endpunkt eines Abschnitts ist der Anfang des nächsten. |
DrawClosedCurve |
»Gespannter« geschlossener Splinekurvenzug durch ein Point-Array |
DrawCurve |
»Gespannter« Splinekurvenzug durch ein Array von Point-Strukturen |
DrawEllipse |
Ellipse in einem umschließenden Rechteck |
DrawLine |
Linie zwischen zwei Punkten |
DrawLines |
Linienzug durch die Punkte eines Point-Arrays |
DrawPie |
Ellipsensegment |
DrawPolygon |
Kontur eines Polygons |
DrawRectangle |
Rechteck, definiert durch die Eckpunkte |
DrawRectangles |
Mehrere Rechtecke, gegeben als Rectangle-Array |
DrawString |
Zeichenfolge an einer bestimmten Position |
FillEllipse |
Farbgefüllte Ellipse in einem umschließenden Rechteck |
FillClosedCurve |
Farbgefüllter geschlossener Splinekurvenzug durch ein Point-Array |
FillPie |
Farbgefülltes Ellipsensegment |
FillPolygon |
Farbgefüllte Kontur eines Polygons |
FillRectangle |
Farbgefülltes Rechteck, definiert durch die Eckpunkte |
FillRectangles |
Mehrere farblich ausgefüllte Rechtecke, gegeben als Rectangle-Array |
15.2.7 Eine Linie
Mit der vierfach überladenen Methode DrawLine zeichnen Sie eine Linie. Als Erstes haben alle Überladungen ein Argument vom Typ Pen, mit dem die Art der zu zeichnenden Linie beschrieben wird. Es wird mindestens die Farbe spezifiziert. Die Angaben der Linienbreite, der Art der Linienenden und -verbindungen und Strichelungen sind optional.
Eine Linie ist durch ihren Anfangs- und Endpunkt definiert. Sie können die Koordinaten der Punkte einzeln als Integer oder Single übergeben oder als geordnete Point-Struktur.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
e.Graphics.DrawLine(New Pen(Brushes.Red, 6), 12, 20, 120, 200)
End Sub
15.2.8 Mehrere Linien
DrawLines zeichnet einen Linienzug. Die Methode erwartet ebenfalls die Referenz auf ein Pen–Objekt sowie zusätzlich ein Array von Point-Objekten. Die Anzahl der Array-Elemente (= Punkte) kann ungerade sein, da der Endpunkt der einen Linie zum Anfangspunkt der nächsten Linie wird. Das Ergebnis ist eine Kette von miteinander verbundenen Linien, wobei das geometrische Gebilde nicht automatisch geschlossen wird.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
Dim points() As PointF = New PointF() {New Point(0, 0), _
New Point(25, 35), New Point(120, 50), New Point(25, 130)}
e.Graphics.DrawLines(New Pen(Color.Black, 2), points)
End Sub
In der Abbildung 15.5 sehen Sie das Ergebnis der Zeichenoperation.
Abbildung 15.5 Linienzug mit DrawLines
15.2.9 Rechtecke
Die Parameterlisten der DrawRectangle-Methoden ähneln denen der DrawLine-Methode. Der erste Parameter erwartet ein Pen-Objekt, den folgenden Parametern werden zwei Punkte übergeben, die die Koordinaten der linken oberen und rechten unteren Ecke angeben. Alternativ können Sie auch eine Rectangle-Struktur übergeben.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
e.Graphics.DrawRectangle(New Pen(Brushes.Blue), 0, 0, 100, 60)
End Sub
Benötigen Sie mehrere Rechtecke, die sich weder in ihrer Farbe noch der Linienart unterscheiden, bietet sich die Methode DrawRectangles an, die ein Array der Struktur Rectangle erwartet. Alle im Array enthaltenen Rechtecke werden in derselben Farbe und Strichstärke gezeichnet.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
Dim rectArr() As Rectangle = New Rectangle() {New Rectangle(0,0,20,40), _
New Rectangle(8,15,45,70), New Rectangle(15,20,80,120)}
e.Graphics.DrawRectangles(New Pen(Brushes.Black), rectArr)
End Sub
Der Hintergrund der mit DrawRectangle und DrawRectangles gezeichneten Rechtecke wird vom Container übernommen. Wollen Sie farblich ausgefüllte Rechtecke zeichnen, müssen Sie auf die Methoden FillRectangle bzw. FillRectangles zurückgreifen. Diesen wird im ersten Parameter kein Pen-Objekt übergeben, sondern ein Brush-Objekt. Da die Klasse Brush abstrakt ist und nicht unmittelbar verwendet werden kann, wird im Code die Referenz auf eine von Brush abgeleitete Klasse übergeben. Damit ist es auch beispielsweise möglich, anstelle einer Farbfüllung eine beliebige Schraffur zu wählen.
15.2.10 Polygone
Die Methode DrawPolygon ähnelt DrawLines und kann sie oft im Programmcode ersetzen. Der Unterschied zwischen den beiden Methoden ist, dass DrawPolygon eine zusätzliche Linie zeichnet, die den letzten mit dem ersten Punkt verbindet und so die Figur schließt.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
Dim pArr() As Point = New Point() _
{New Point(2, 7), New Point(25, 12), New Point(67, 100)}
e.Graphics.DrawPolygon(New Pen(Brushes.Black, 2), pArr)
End Sub
15.2.11 Ellipsen und Teile davon
Gezeichnet wird eine Ellipse innerhalb eines umschließenden Rechtecks, daher gleichen sich auch die Parameterlisten von DrawRectangle und DrawEllipse. Im folgenden Codefragment wird eine Ellipse in die Form gezeichnet, deren umschließendes Rechteck seine linke obere Ecke im Ursprungspunkt des Clientbereichs der Form hat. Die Breite beträgt 200 Pixel, die Höhe 100 Pixel.
Private void Form1_Paint(sender As Object, e As PaintEventArgs)
e.Graphics.DrawEllipse(New Pen(Brushes.Blue, 3), 0, 0, 200, 100)
End Sub
Einen Kreis- bzw. Ellipsenbogen zeichnen Sie mit DrawArc. Auch hier wird das umschließende Rechteck der Ellipse übergeben. Der vorletzte Parameter gibt den Startwinkel zwischen der x–Achse und dem Anfangspunkt des Bogens an, der letzte Parameter den Winkel des zu zeichnenden Bogens. Die Winkel werden in Grad und im Uhrzeigersinn angegeben.
15.2.12 Kurvenzüge
Die Methoden DrawCurve und DrawClosedCurve zeichnen Kurven (Cardinal-Splinekurven), die durch in einem Point-Array definierte Punkte führen. DrawClosedCurve schließt den Kurvenzug. Beide Methoden sind mehrfach überladen. Mehrere Varianten erwarten einen Parameter vom Typ Single, der die »Spannung« der Kurve angibt. Der Wert 0 bedeutet unendliche Spannung an den Punkten und erzeugt einen eckigen Polygonzug. Maximal »weiche« Kurven ergibt der Wert 1. Höhere Werte »stauchen« die Kurve. Standard ist 0.5.
Abbildung 15.6 zeigt die beiden Kurven, die mit dem folgenden Programmcode gezeichnet werden. Die im Point-Array definierten Punkte sind durch einen kleinen Kreis optisch hervorgehoben.
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
Dim pt() As Point = New Point() {New Point(0, 4), New Point(50, 150), _
New Point(100, 70), New Point(150, 155), New Point(200, 145), _
New Point(250, 160), New Point(300, 20)}
e.Graphics.DrawCurve(New Pen(Brushes.Red, 3), pt)
e.Graphics.DrawCurve(New Pen(Brushes.Black), pt, 1)
For Each p As Point In pt
e.Graphics.DrawEllipse(New Pen(Brushes.Black, 2), p.X-2, p.Y-3, 6, 6)
Next
End Sub
Abbildung 15.6 Kurven mit DrawCurve
15.2.13 Bézierkurven
Mit DrawBezier verbinden Sie zwei Punkte durch eine glatte Splinekurve. Die Steigung der Kurve an den Endpunkten wird durch je eine Tangente definiert, die von den Endpunkten und je einem zusätzlich gegebenen Punkt gebildet werden. Die Kurve liegt vollständig innerhalb des von den Kontrollpunkten gebildeten Polygons. Der Zeichenmethode werden der Startpunkt, der Tangentenpunkt am Start, der Tangentenpunkt am Ende und der Endpunkt übergeben.
e.Graphics.DrawBezier(New Pen(Brushes.Black), start,tangStart,tangEnde,ende)
Abbildung 15.7 zeigt zusätzlich zu dieser Bezierkurve eine dicke Linie zwischen Start- und Endpunkt. Die Bézierkurve wird durch die beiden ober- und unterhalb liegenden Stützpunkte auf den gewünschten Verlauf »gezogen«. Die Tangenten sind gepunktet dargestellt.
Abbildung 15.7 Bezierkurve
Der Abbildung liegt der folgende Programmcode zugrunde:
Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
Dim start As New Point(10, 100), tangStart As New Point(30, 30)
Dim tangEnde As New Point(150, 150), ende As New Point(300, 100)
Dim dick As New Pen(Brushes.Black, 2), dünn As New Pen(Brushes.Black, 1)
' Gerade zwischen Start- und Endpunkt
e.Graphics.DrawLine(dick, start, ende)
' Bezierkurve
e.Graphics.DrawBezier(dünn, start, tangStart, tangEnde, ende)
' Tangenten
dick.DashStyle = Drawing2D.DashStyle.Dot
e.Graphics.DrawLine(dick, start, tangStart)
e.Graphics.DrawLine(dick, tangEnde, ende)
' Punkte markieren
e.Graphics.DrawEllipse(dünn, start.X – 2, start.Y – 3, 6, 6)
e.Graphics.DrawEllipse(dünn, tangStart.X – 2, tangStart.Y – 3, 6, 6)
e.Graphics.DrawEllipse(dünn, tangEnde.X – 2, tangEnde.Y – 3, 6, 6)
e.Graphics.DrawEllipse(dünn, ende.X – 2, ende.Y – 3, 6, 6)
End Sub
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.