Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
1 Einführung
2 Grundlagen der Sprachsyntax
3 Klassendesign
4 Weitere Datentypen
5 Multithreading
6 Collections und LINQ
7 Eingabe und Ausgabe
8 Anwendungen: Struktur und Installation
9 Code erstellen und debuggen
10 Einige Basisklassen
11 Windows-Anwendungen erstellen
12 Die wichtigsten Steuerelemente
13 Tastatur- und Mausereignisse
14 MDI-Anwendungen
15 Grafiken mit GDI+
16 Drucken
17 Entwickeln von Steuerelementen
18 Programmiertechniken
19 WPF – Grundlagen
20 Layoutcontainer
21 WPF-Steuerelemente
22 Konzepte von WPF
23 Datenbankverbindung mit ADO.NET
24 Datenbankabfragen mit ADO.NET
25 DataAdapter
26 Offline mit DataSet
27 Datenbanken aktualisieren
28 Stark typisierte DataSets
A Anhang: Einige Übersichten
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual Basic 2008 von Andreas Kuehnel, Stephan Leibbrandt
Das umfassende Handbuch
Buch: Visual Basic 2008

Visual Basic 2008
3., aktualisierte und erweiterte Auflage, geb., mit DVD
1.323 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1171-0
Pfeil 15 Grafiken mit GDI+
Pfeil 15.1 Namensräume von GDI+
Pfeil 15.2 Die Klasse Graphics
Pfeil 15.2.1 Ein Graphics-Objekt besorgen
Pfeil 15.2.2 Neuzeichnen mit ResizeRedraw und Invalidate
Pfeil 15.2.3 Zerstören grafischer Objekte (Dispose)
Pfeil 15.2.4 Koordinatensystem
Pfeil 15.2.5 Koordinatenursprung
Pfeil 15.2.6 Zeichnen mit der Klasse Graphics
Pfeil 15.2.7 Eine Linie
Pfeil 15.2.8 Mehrere Linien
Pfeil 15.2.9 Rechtecke
Pfeil 15.2.10 Polygone
Pfeil 15.2.11 Ellipsen und Teile davon
Pfeil 15.2.12 Kurvenzüge
Pfeil 15.2.13 Bézierkurven
Pfeil 15.3 Stifte und Farben
Pfeil 15.3.1 Linienstile mit Pen
Pfeil 15.3.2 Farben mit Color
Pfeil 15.4 Schriftdarstellung
Pfeil 15.4.1 Schriftart (Font und FontFamily)
Pfeil 15.4.2 Schriftstil mit FontStyle
Pfeil 15.4.3 Ausgabe einer Zeichenfolge
Pfeil 15.4.4 Abmessungen mit MeasureString
Pfeil 15.4.5 Textlayout mit StringFormat
Pfeil 15.5 Bilddateien
Pfeil 15.5.1 Bilder und Grafiken in .NET
Pfeil 15.5.2 Bitmap-Dateiformate
Pfeil 15.5.3 Bilder vom Typ Image
Pfeil 15.5.4 Bitmaps


Rheinwerk Computing - Zum Seitenanfang

15.5 Bilddateien Zur nächsten ÜberschriftZur vorigen Überschrift

Grafiken, Bilder und Zeichnungen werden mithilfe verschiedener Technologien dargestellt, bearbeitet und letztendlich auch gespeichert. Prinzipiell werden dabei zwei Kategorien zur Bearbeitung grafischer Elemente unterschieden:

  • Rastergrafiken
  • Vektorgrafiken

Rastergrafiken

Oft werden Bilder oder Fotos als Rastergrafik im Bitmap-Format hinterlegt. Ein solches Bild ist eine Aneinanderreihung einzelner Bildpunkte, die durch je eine Farbe beschrieben werden. Weil eine Rastergrafik sehr simpel aufgebaut wird, ist auch ihre Erzeugung bzw. Nachbearbeitung sehr einfach. Allerdings erkauft man sich diesen Vorteil zu einem hohen Preis:

  • Kurven sind immer stufig, weil sie sich aus einzelnen Rechtecken zusammensetzen.
  • Eine Rastergrafik benötigt sehr viel Speicherplatz. Zur Abmilderung wurden zahlreiche Komprimierungsverfahren entwickelt, um die Datenmenge zu reduzieren. GIF für Liniengrafiken und JPEG für Fotos sind die bekanntesten Beispiele.
  • Bei einer Skalierung (Größenänderung) kommt es zu sehr unschönen optischen Effekten. Beispielsweise werden bei einer Verkleinerung einfach Spalten oder Zeilen weggelassen.

Vektorgrafiken

Bei einer Vektorgrafik werden Linien, Kurven und Texte durch wenige Koordinaten beschrieben. Verschiedene Funktionen beschreiben, wie aus Koordinaten Grafiken werden. Jede Koordinate wird durch einen Vektor beschrieben. Ihn können Sie sich als Linie vorstellen, die durch einen Anfangspunkt, eine Richtung und eine Länge beschrieben ist. Gibt es für ein Bild-element keine passende Funktion, wird es aus Einzelteilen zusammengesetzt, für die jeweils eine Funktion existiert. Die funktionale Beschreibung hat einige Vorteile.

  • Eine Vektorgrafik kann sehr kompakt gespeichert werden. Ein Bild der Größe 300 × 500 mit einer Diagonalen benötigt als Rastergrafik 150.000 Bildpunkte, als Vektorgrafik genügen der Anfangs- und der Endpunkt ((0,0),(300,500)).
  • Da Grafiken durch Koordinaten beschrieben werden, kann eine Vektorgrafik beliebig skaliert werden. Das Programm rechnet die Koordinaten um und zeichnet die Grafik neu.
  • In einigen Programmen (Beispiel CAD) ist das Bearbeiten einer Vektorgrafik einfacher, denn das Programm kennt die einzelnen Elemente und hat direkten Zugriff darauf. Mit der Maus lassen sich die einzelnen Bildelemente sehr einfach greifen und bearbeiten.

Das hört sich ausgesprochen vorteilhaft an, und es stellt sich die Frage, warum Vektorgrafiken die Rastergrafiken nicht ablösen konnten. Der Grund ist, dass in vielen Bildern die einzelnen Bildelemente unkorreliert sind, zum Beispiel die Pixel eines Fotos. Es gibt keine Funktion, die mehrere Elemente beschreiben kann. So müsste jedes Pixel durch einen eigenen Vektor beschrieben werden, was sehr viel Speicherplatz braucht. Daraus folgt:

  • Zeichenprogramme, die hauptsächlich auf Linien und Kurven basieren, speichern die Daten des Bildes als Vektordatei, die oft binäre Daten enthält.
  • Malprogramme und Bilder werden im Bitmap-Format gespeichert.

Rheinwerk Computing - Zum Seitenanfang

15.5.1 Bilder und Grafiken in .NET Zur nächsten ÜberschriftZur vorigen Überschrift

Rastergrafiken werden als Bitmaps gespeichert, Vektorgrafiken als Metadateien. Die Klassenbibliothek stellt die Klassen Image, Bitmap, Icon und Metafile bereit, deren Klassenhierarchie in Abbildung 15.10 gezeigt ist.

Die Klasse Image ist die abstrakte Basisklasse für die beiden Typen Bitmap und Metafile und stellt diesen Funktionen zur Bildbearbeitung zur Verfügung. Ein wenig aus dem Rahmen fällt die Klasse Icon. Grundsätzlich ist auch ein Icon-Objekt eine Bitmap, es wird aber in einem Windows-eigenen Dateiformat gespeichert und hat nur wenig Bearbeitungsmethoden.

Abbildung 15.10 Hierarchie der Bildklassen

Der Bitmap-Klasse kommt eine deutlich höhere Bedeutung zu als den Klassen Icon und Metafile. Im Weiteren beschränke ich mich auf die Bitmap-Klasse.


Rheinwerk Computing - Zum Seitenanfang

15.5.2 Bitmap-Dateiformate Zur nächsten ÜberschriftZur vorigen Überschrift

Eine Bitmap ist die Ansammlung von Pixeln in einem Array. Höhe und Breite werden in Pixeln angegeben. Die Anzahl der darstellbaren Farben wird Farbtiefe genannt. Sie wird als Anzahl der Bits gegeben, die jedem Pixel einer Bitmap gleichermaßen zur Verfügung steht. Der Bereich reicht von 1 bis 32 Bits, die Anzahl der darstellbaren Farben ergibt sich zu:

Farbenanzahl = 2Bits pro Pixel

Für RGB-Farben wird für den Rot-, Grün- und Blauanteil (die sogenannten Primärfarben) jeweils ein Byte bereitgestellt, das insgesamt 256 Farbabstufungen umfasst. Die ARGB-Farbskala hat noch ein viertes Byte, mit dem die Transparenz ebenfalls zwischen 0 (durchsichtig) und 255 (undurchsichtig) eingestellt wird.

Es haben sich einige feste Bitmap-Formate etabliert. Werden die Farben eines Pixels durch acht Bit beschrieben, ergeben sich 256 Farbabstufungen. Meistens wird dieses Format zur Darstellung von Graustufen-Bitmaps benutzt. Stehen jedem Pixel drei Byte mit je acht Bit zur Farbdarstellung zur Verfügung, erhöht sich die Farbanzahl sofort deutlich auf 224 = 16.777.216. Wir kennen diese Farbskala unter dem Namen True Color.

Der Nachteil herkömmlicher Bitmaps ist die Größe der Datei. Eine Bitmap mit den Abmessungen 300 × 300 Pixel und einer Farbtiefe von 24 Bit beansprucht bereits etwas über 260 KByte. Als die Rechner noch nicht so üppig mit Hauptspeicher ausgerüstet waren wie heutzutage, waren das schon Größenordnungen, die kaum noch akzeptabel waren. Heutzutage mangelt es den Maschinen zwar nicht mehr an RAM, allerdings gibt es ein anderes Nadelöhr hinsichtlich des Speichervolumens: das Web. Eine Internetseite, die mehrere Bitmaps beinhaltet, kann ein unzumutbares Ladeverhalten zeigen.

Die Tabelle 15.6 beschreibt kurz verschiedene Dateiformate für Bitmaps.


Tabelle 15.6 Dateiformate für Bitmaps

Dateiformat Beschreibung

BMP

BMP ist das Standardformat von Windows für Bitmap-Dateien. Die Farbtiefe ist auf 24 Bit beschränkt, und es wird unkomprimiert gespeichert.

GIF

Das Graphics Interchange Format hat maximal 256 Farben, aber ein effizientes Komprimierungsverfahren. Es eignet sich für Bilder mit transparenten Bereichen sowie für im Internet oft anzutreffende Animationen.

JPEG

JPEG (Joint Photographic Experts Group) ist ein international standardisiertes Komprimierungsverfahren, das für Fotos entwickelt wurde. Das Format ist auch als JFIF (JPEG File Interchange Format) bekannt geworden.

PNG

PNG (Portable Network Graphics) ist ein 1995 als Konkurrenz zu GIF entwickelter und von den meisten Browsern neben GIF und JPEG unterstützter Bildstandard. PNG bietet hohe Kompressionsraten, Halbtransparenz und Echtfarben.

TIFF

TIFF (Tagged Image File Format) dient dem Austausch von Dateien zwischen Programmen und Plattformen. TIFF ist ein flexibles Bitmap-Format, das von fast allen Mal- und Bildbearbeitungsprogrammen unterstützt wird.



Rheinwerk Computing - Zum Seitenanfang

15.5.3 Bilder vom Typ Image Zur nächsten ÜberschriftZur vorigen Überschrift

Ein Bild laden

Image ist die abstrakte Basisklasse der beiden abgeleiteten Klassen Bitmap und Metafile. Daher gibt es keinen Konstruktor in der Klasse Image, um daraus ein Objekt zu erzeugen.

AlleDateienAnzeigen.tifMehrere klassengebundene Methoden in Image liefern die Referenz auf ein Bild. Die am häufigsten benutzte Methode erstellt ein Image aus einer Datei, deren Zugriffspfad als Zeichenkette übergeben wird. Wir wollen sie im folgenden Beispielprogramm benutzen und eine JPEG-Datei in einer Form anzeigen, die dem Projekt so, wie in Abbildung 15.11 zu sehen ist, hinzugefügt wird. Gegebenenfalls müssen Sie mit der Symbolleistenschaltfläche im Projektmappen-Explorer alle Dateien anzeigen lassen.

Abbildung 15.11 Bilddatei zum Projekt hinzufügen

Im Eigenschaftsfenster sorgen wir dafür, dass die Datei mit im Ausgabeverzeichnis landet (siehe Abbildung 15.12).

Abbildung 15.12 Bilddatei zum Programm hinzufügen

Der Programmcode ist kurz:


'...\GDI\Bilddateien\Laden.vb

Public Class Laden 
  Private Sub Laden_Paint(sender As Object, ByVal e As PaintEventArgs) _ 
  Handles MyBase.Paint 
    Try 
      Dim strFile As String = IO.Path.Combine("Bilder", "Egypt.jpg") 
      Dim img As Image = Image.FromFile(strFile) 
      e.Graphics.DrawImage(img, 10, 20) 
    Catch ex As Exception 
      MessageBox.Show("Ladefehler: " & ex.Message, "Fehler") 
    End Try 
  End Sub 
End Class

Eine Referenz auf das Bild gibt uns die an die Klasse Image gebundene Methode FromFile, der wir den Pfad zur Bilddatei übergeben. Durch den Einschluss der Bilddatei in das Projektausgabeverzeichnis können wir die Angabe relativ zur ausführbaren Datei machen. Die Anzeige übernimmt die Methode DrawImage des Graphics-Objekts der Form. Hier wird das unveränderte Bild mit seiner linken oberen Ecke an der Stelle (10,20) gezeichnet. Wird das Bild nicht gefunden, zum Beispiel weil nur die ausführbare Datei vorliegt, wird im Catch-Zweig eine Fehlermeldung produziert.

Bildanzeige mit DrawImage

DrawImage bietet 30 verschiedene Arten, ein Bild zu zeichnen. Bilder können gestreckt, gestaucht oder gedreht angezeigt werden. In der folgenden Syntaxübersicht sind optionale Teile kursiv gesetzt.


Public Sub DrawImage(bild As Image, <Ort>) 
Public Sub DrawImage(bild As Image, <Bereich>) 
Public Sub DrawImage(bild As Image, <Raute>) 
Public Sub DrawImage(<bild>, <Ziel>, <Quelle>, <Attr>, <Check>, <Daten>)

<Ort>    : linke obere Ecke als Point/PointF oder 2 Integer/Single 
<Bereich>: Ort und Größe als Rectangle/RectangleF oder 4 Integer/Single 
<Raute>  : Einpassung in Parallelogramm, gegeben als Point()/PointF() 
<Ziel>   : Ort, Bereich oder Scherung 
<Quelle> : Bildausschnitt (Zahlenart wie Ziel) und Einheit als GraphicsUnit 
           4 Punkte->Rectangle, Rechteck->2 Punkte/Rechteck/Parallelogramm 
<Attr>   : ImageAttributes (wie Quelle außer 2 Punkte/Rechteck) 
<Check>  : Callback Prüffunktion vom Typ DrawImageAbort (Ladekontrolle) 
<Daten>  : Daten für Callback als Integer

Zwei weitere Beispiele sollen die Flexibilität der Zeichenmethode DrawImage demonstrieren. Für das erste brauchen Sie nur die Zeile des Methodenaufrufs von DrawImage im Beispiel oben gegen die folgende Anweisung auszutauschen:

e.Graphics.DrawImage(img, New Rectangle(0, 0, 250, 150))

Der zweite Methodenparameter ist ein Rectangle-Objekt, das die Lage und die Abmessungen des Bereichs beschreibt, in dem das Bild angezeigt werden soll. Die daraus resultierende Bildausgabe sehen Sie in Abbildung 15.13 – das Bild wird in seiner Breite gestreckt.

Abbildung 15.13 Ausgabe eines gestreckten Bildes

Tauschen wir noch einmal den DrawImage-Aufruf gegen einen anderen aus, und übergeben wir ein Point-Array. Dieser Übergabe liegt die folgende überladene Methode zugrunde:


Public Sub DrawImage(image As Image, destPoints As Point())

In diesem Point-Array sind drei Punkte definiert: Der erste gibt die obere linke Ecke des Bildes an, der zweite die obere rechte Ecke und der dritte die untere linke Ecke. Der vierte Punkt wird automatisch so ermittelt, dass das Ergebnis ein Parallelogramm bildet, wie in Abbildung 15.14 zu sehen.

e.Graphics.DrawImage(img, New Point() _ 
  {New Point(80, 0), New Point(300, 80), New Point(30, 100)})

Abbildung 15.14 Ausgabe eines gedrehten und gestreckten Bildes

Zeichnen auf Bildern

Bilder sind bezüglich nachfolgender Zeichenoperationen nichts Besonderes. Im folgenden Beispiel zeichnen wir mit DrawImage ein Bild und schreiben mit DrawString an der Stelle (5,5) einen gelben Text darauf (siehe Abbildung 15.15). Um den Code kurz zu halten, hat er keinen Try-Block.


'...\GDI\Bilddateien\Beschriftung.vb

Public Class Beschriftung 
  Private Sub Beschriftung_Paint(sender As Object, e As PaintEventArgs) _ 
  Handles MyBase.Paint 
    Dim strFile As String = IO.Path.Combine("Bilder", "Egypt.jpg") 
    Dim img As Image = Image.FromFile(strFile) 
    e.Graphics.DrawImage(img, New Rectangle(0, 0, 257, 172)) 
    Dim strText As String = "Ägyptischer Restaurateur" 
    Dim ft As New Font("Arial", 12, FontStyle.Bold Or FontStyle.Underline) 
    e.Graphics.DrawString(strText, ft, Brushes.Yellow, New Point(5, 5)) 
  End Sub 
End Class

Abbildung 15.15 Bildausgabe mit Beschriftung

Eigenschaften der Klasse Image

Als abstrakte Basisklasse stellt Image den beiden abgeleiteten Klassen Metafile und Bitmap die in Tabelle 15.7 gezeigten Eigenschaften zur Verfügung, die Informationen über das Image-Objekt liefern.


Tabelle 15.7 Eigenschaften von »Image«

Eigenschaft Beschreibung

Flags

Details wie Skalierbarkeit und Farbraum

R

FrameDimensionsList

IDs im Bild enthaltener Frames und Auflösungen

R

Height

Höhe des Bildes in Pixel

R

HorizontalResolution

Horizontale Auflösung des Bildes in DPI (Dots per Inch)

R

Palette

Farbpalette des Bildes (ARGB Farben)

PhysicalDimension

Größe des Bildes als SizeF-Objekt. Einheiten: Bitmaps in Pixel, Metafiles in 1/100 mm

R

PixelFormat

Gibt an, wie ein Pixelwert auf eine Farbe abgebildet wird.

R

PropertyIdList

IDs der Metainformationen

R

PropertyItems

Metainformationen zum Bild

R

RawFormat

Bildformat des Bildes als ImageFormat

R

Size

Bildgröße in Pixel

R

Tag

Benutzerdefinierte Zusatzdaten

VerticalResolution

Vertikale Auflösung des Bildes in DPI (Dots per Inch)

R

Width

Breite des Bildes in Pixel

R



Rheinwerk Computing - Zum Seitenanfang

15.5.4 Bitmaps topZur vorigen Überschrift

Die abstrakte Klasse Image ist im Gegensatz zur beerbenden Klasse Bitmap nicht instanziierbar. Die Konstruktoren zerfallen in zwei Gruppen. Entweder übernehmen Sie ein Bild, das als Datenfeld, Image, Stream oder Dateipfad gegeben ist. Sie können es skalieren oder Farben korrigieren. Die zweite Gruppe erstellt eine leere Bitmap mit optionaler Auflösung (gegeben als Graphics) oder optionaler Farbcodierung (gegeben als PixelFormat). Am einfachsten lässt sich eine Bitmap mit dem Konstruktor erzeugen, der die Breite und Höhe in Pixel angibt:

Dim bmp As New Bitmap(300, 400)

Die erzeugte Bitmap ist 300 Pixel breit und 400 Pixel hoch. Es handelt sich um eine ARGB-Bitmap (A = Alpha-Kanal, R = Rot, G = Grün, B = Blau), deren Werte mit 0 initialisiert werden. Da der A-Kanal zur Darstellung der Transparenz den Startwert 0 hat, bedeutet das, dass eine Bitmap (zunächst) durchsichtig ist.

»Malen« mit SetPixel

Die Methode SetPixel ändert den Zustand eines einzelnen Pixels in der Bitmap:

bmp.SetPixel(10, 10, Color.Blue)

Die ersten beiden Parameter geben die Koordinaten eines Pixels an, das mit der Farbe gezeichnet wird, die im dritten Parameter genannt ist. Mit der DrawImage-Methode des Graphics-Objekts kann die Bitmap auf einem beliebigen Steuerelement angezeigt werden, da Control die Methode OnPaint bereitstellt. Das folgende Beispiel zeichnet einen zweidimensionalen Farbverlauf.

Private Sub SetPixel_Paint(sender As Object, ByVal e As PaintEventArgs) 
  Dim bmp As New Bitmap(255, 255) 
  For i As Integer = 0 To 254 
    For j As Integer = 0 To 254 
      bmp.SetPixel(j, i, Color.FromArgb(i, 0, j)) 
  Next j, i 
  e.Graphics.DrawImage(bmp, 0, 0) 
End Sub

Die Bitmap hat eine Höhe und Breite von jeweils 255 Pixeln. In zwei For-Schleifen wird für jedes Pixel in der Bitmap eine neue Farbe festgelegt. Die äußere Schleife durchläuft dabei jede Pixelzeile, die innere jede Pixelspalte. Die Farbe des Rot- und Blauanteils wird aus dem jeweiligen Zählerstand mit der statischen FromArgb-Methode der Color-Klasse ermittelt.

Die Farbe eines Pixels liefert das Pendant der SetPixel-Methode: GetPixel. Sie müssen wieder die Koordinaten des Pixels angeben und erhalten die Farbe als Color-Struktur.

Speichern von Bitmaps

Ebenso einfach wie das Laden ist das Speichern einer Datei. Die Klasse Image bietet dazu die überladene Methode Save an, die von der abgeleiteten Klasse Bitmap geerbt wird. Die einparametrige Version, die nur die Angabe des Speicherpfades als Zeichenfolge entgegennimmt, erzeugt ein PNG-Format. Allerdings sollten Sie beim Speichern immer das Bildformat angeben, zum Beispiel mit folgender Überladung:


Public Sub Save(filename As String, format As ImageFormat)

Anstatt an eine Datei können Sie die Bitmap auch an ein Stream-Objekt übergeben. Ein Objekt für den Formatparameter vom Typ System.Drawing.Imaging.ImageFormat liefern die zehn in Tabelle 15.8 aufgelisteten klassengebundenen Eigenschaften dieser Klasse. Alle sind schreibgeschützt.


Tabelle 15.8 Statische Eigenschaften der Klasse »ImageFormat«

Eigenschaft Beschreibung

Bmp

Bitmap-Bildformat (BMP)

Emf

Windows-Bildformat Erweiterte Metadatei (Enhanced Meta File – EMF)

Exif

Exif-Format (Exchangeable Image File)

Gif

GIF-Bildformat (Graphics Interchange Format)

Icon

Bildformat für Windows-Symbole

Jpeg

JPEG-Format (Joint Photographic Experts Group)

MemoryBmp

Bitmap-Bildformat im Speicher

Png

PNG-Bildformat (W3C Portable Network Graphics)

Tiff

TIFF-Bildformat (Tagged Image File Format)

Wmf

WMF-Bildformat (Windows Metafile)


Zum Speichern geben Sie den Pfad zur Datei an. Die Dateierweiterung sollte mit der Angabe des Bildformats übereinstimmen.

bmp.Save("C:\MyBitmap.jpg", ImageFormat.Jpeg)

Die Bitmap wird vor dem Speichern in das angegebene Format konvertiert. Wenn Sie die Bitmap beispielsweise als GIF-Datei speichern, verringert sich die Anzahl der Farben auf 256, was zu einem Verlust der Darstellungsqualität führen kann.

Ein einfaches Malprogramm

Im folgenden Beispielprogramm kann mit der Maus eine Grafik auf die Clientfläche der Form gezeichnet werden (siehe Abbildung 15.16). Dazu wird die linke Maustaste gedrückt und gleichzeitig gezogen. Die folgende Abbildung zeigt eine damit erstellte Zeichnung.

Abbildung 15.16 Einfaches Malprogramm

Zeichnungen auf dem Bildschirm sind sehr flüchtig. Kaum wird ein Fenster(bereich) verdeckt, sind sie weg. Kommt das Fenster wieder zum Vorschein, muss die Zeichnung wieder restauriert werden. Unter allen gängigen grafischen Oberflächen wird dazu der sichtbar werdende Bereich neu gezeichnet. Eine besonders einfache Wiederherstellung ist möglich, wenn die Pixelinformation des Fensterbereichs zuvor gespeichert wurde. Anstatt bei jeder Änderung den Bildschirmbereich des Fensters abzuspeichern, gehen wir hier den umgekehrten Weg. Wir zeichnen auf eine Bitmap, die wir bei Änderungen und der Wiederherstellung zur Anzeige bringen.

Das folgende Codefragment zeigt den Initialisierungsteil des Beispiels. Die wesentlichen Teile sind die Erzeugung einer Bitmap zur Speicherung und die Erzeugung eines Graphics-Objekts, das auf die Bitmap zeichnen kann. Die Dialoge werden später zum Laden und Speichern verwendet.


'...\GDI\Bilddateien\Malen.vb

Public Class Malen 
  Private grafik As Bitmap, blatt As Graphics 
  Private dö As New OpenFileDialog(), ds As New SaveFileDialog() 
  Private Sub Laden(sender As Object, e As EventArgs) Handles MyBase.Load 
    grafik = New Bitmap(ClientSize.Width, ClientSize.Height) 
    blatt = Graphics.FromImage(grafik) 
    Dim exe As String = Application.ExecutablePath 
    dö.InitialDirectory = IO.Directory.GetParent(exe).FullName 
    ds.InitialDirectory = IO.Directory.GetParent(exe).FullName 
    ds.DefaultExt = "bmp" : ds.AddExtension = True 
  End Sub 
  ... 
End Class

Die eigentliche Zeichnerei besteht aus zwei Teilen. Durch einen Mausklick wird ein Linienzug begonnen. Im Ereignishandler wird der Linienbeginn gespeichert. Bei jeder Mausbewegung bei gedrückter Maustaste wird der Linienzug um ein Stück verlängert. Dazu wird zwischen dem bisherigen Ende des Linienzugs, der in start gespeichert ist, und der in ende gespeicherten Mausposition mit DrawLine eine Linie in das Graphics-Objekt blatt gezeichnet, das die Linie an die darunterliegende Bitmap grafik weiterreicht (noch erscheint die Linie nicht auf dem Bildschirm). Die linke Maustaste zeichnet in Gelb, die rechte löscht, indem sie in der Hintergrundfarbe Schwarz zeichnet. Das neu gezeichnete Element des Linienzugs liegt innerhalb des in quelle gespeicherten Rechtecks und wird mit DrawImage auf das Graphics-Objekt g des Formulars gezeichnet und erscheint damit auf dem Bildschirm. Da das Ereignis MouseMove nicht primär zum Zeichnen gedacht ist, stellt es keinen Grafikkontext zur Verfügung. Wir beschaffen ihn uns mit der Methode CreateGraphics(). Es reicht, den Bereich von quelle zu zeichnen, da nur er neu ist. Alternativ zu DrawImage können Sie Inavidate(quelle) aufrufen (CreateGraphics() ist dann überflüssig). Schließlich wird die aktuelle Mausposition durch start=ende zum neuen Ende des Linienzugs. Der Using-Block gibt automatisch Ressourcen des durch CreateGraphics() erzeugten Objekts durch den impliziten Aufruf von Dispose() frei.


'...\GDI\Bilddateien\Malen.vb

Public Class Malen 
  ... 
  Private start As Point 
  Private Sub Anfang(sender As Object, ByVal e As MouseEventArgs) _ 
  Handles MyBase.MouseDown 
    start = New Point(e.X, e.Y) 
  End Sub

  Private Sub Zeichnen(sender As Object, e As MouseEventArgs) _ 
  Handles MyBase.MouseMove 
    If e.Button = Windows.Forms.MouseButtons.None Then Return 'schneller 
    Dim ende As New Point(e.X, e.Y) 
    Using g As Graphics = Me.CreateGraphics() 
      Dim w As Integer 
      If e.Button = MouseButtons.Left Then 
        w = 2 : blatt.DrawLine(New Pen(Brushes.Yellow, 2), start, ende) 
      ElseIf e.Button = MouseButtons.Right Then 
        w = 8 : blatt.DrawLine(New Pen(Brushes.Black, 8), start, ende) 
      End If 
      Dim quelle As New Rectangle( _ 
          Math.Min(start.X, ende.X) – w\2, Math.Min(start.Y, ende.Y) – w\2, _ 
          Math.Abs(start.X – ende.X) + w, Math.Abs(start.Y – ende.Y) + w) 
      g.DrawImage(grafik, quelle.Left, quelle.Top, quelle, GraphicsUnit.Pixel) 
      start = ende 
    End Using 
  End Sub 
  ... 
End Class

Die Wiederherstellung eines verdeckten Bereichs im Ereignishandler von Paint ist schon fast trivial. Der wieder sichtbare Bereich wird aus der Bitmap grafik restauriert.


'...\GDI\Bilddateien\Malen.vb

Public Class Malen 
  ... 
  Private Sub Auffrischen(sender As Object, ByVal e As PaintEventArgs) _ 
  Handles MyBase.Paint 
    Dim r As Rectangle = e.ClipRectangle 
    e.Graphics.DrawImage(grafik, r.Left, r.Top, r, GraphicsUnit.Pixel) 
  End Sub 
  ... 
End Class

Zur Abrundung hat das Beispiel noch drei Menüpunkte zum Neustart des Zeichnens, zum Öffnen einer auf Platte gespeicherten Bitmap und zum Speichern von Zeichnungen. Analog zum Konstruktor werden für eine neue Zeichnung die Zeichenfläche und das zugehörige Graphics-Objekt erstellt. Der Aufruf von Invalidate() erzwingt ein Neuzeichnen. Eine zu öffnende Bitmapdatei wird mit OpenFileDialog.ShowDialog() ermittelt und in ein Bitmap-Objekt geladen. Die einfachste Konstruktorüberladung von Bitmap

Public Sub New(filename As String)

ist leider ungeeignet, da sie die Bitmap zwar lädt, aber gleichzeitig geöffnet lässt. Dadurch ist sie gesperrt und kann nicht mehr unter dem gleichen Namen im selben Verzeichnis gespeichert werden. Der Umweg über einen expliziten Stream umgeht das Problem. Die Anpassung der Auflösung ist zum Beispiel beim Öffnen von JPEG-Dateien nötig. Die Auswahl einer Datei durch einen Doppelklick im Öffnen-Dialog erzeugt implizit ein MouseMove-Ereignis im Formular, wenn sich die Mausposition innerhalb des Formulars befindet (auch wenn dieses durch den Dialog verdeckt war). Um dann keine Linie zu zeichnen, wird der Beginn des Linienzugs auf die aktuelle Mausposition gesetzt. Im Ereignishandler von MouseMove führt dies zu einem Liniensegment der Länge null. Die Speicherung ist deutlich einfacher. SaveFileDialog.ShowDialog() ermittelt den Dateinamen, und den Rest übernimmt die Methode Bitmap.Save().


'...\GDI\Bilddateien\Malen.vb

Public Class Malen 
  ... 
  Private Sub Löschen(sender As Object, e As EventArgs) Handles Neu.Click 
    grafik = New Bitmap(ClientSize.Width, ClientSize.Height) 
    blatt = Graphics.FromImage(grafik) 
    Me.Invalidate() 
  End Sub

  Private Sub Bild(sender As Object, e As EventArgs) Handles Öffnen.Click 
    If dö.ShowDialog() = DialogResult.OK Then 
      Dim st As New IO.FileStream(dö.FileName, IO.FileMode.Open) 
      grafik = New Bitmap(st) 
      st.Close() 
      grafik.SetResolution(blatt.DpiX, blatt.DpiY) 
      blatt = Graphics.FromImage(grafik) 
      start = Control.MousePosition 
      Me.Invalidate() 
    End If 
  End Sub

  Private Sub Sichern(sender As Object, e As EventArgs) _ 
  Handles Speichern.Click 
    If ds.ShowDialog() = DialogResult.OK Then _ 
      grafik.Save(ds.FileName, Imaging.ImageFormat.Bmp) 
  End Sub 
End Class

Das Beispiel ist bewusst einfach gehalten und kann Ihnen als Startpunkt eigener Entwicklungen dienen.



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.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual Basic 2008
Visual Basic 2008
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Visual Basic 2012






 Visual Basic 2012


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern