Pinsel
und Flächen
Bevor Flächen gezeichnet werden können, muss auch hier zuerst das entsprechende
'Werkzeug' ausgewählt werden. Flächen werden mit so genannten Pinsel (Brush) ausgefüllt
und mit den in der vorherigen Lektionen eingeführten Stiften umrandet.
 |
Wollen Sie Flächen ohne Umrandung zeichnen, so wählen Sie als Stift den
Stifttyp NULL_PEN aus. |
Und auch hier sind wieder am einfachsten die Pinsel zu verwenden, die WINDOWS
von Haus aus zur Verfügung stellt. Diese Pinsel müssen ebenfalls nicht explizit
erstellt werden sondern können durch die vorhin erwähnte Methode SelectStockObject(...)
für die nachfolgende Zeichenoperation ausgewählt werden. Der Parameter gibt jetzt
den auszuwählenden Pinsel an und kann eine der Konstanten BLACK_BRUSH,
DKGRAY_BRUSH, GRAY_BRUSH,
LTGRAY_BRUSH, HOLLOW_BRUSH,
NULL_BRUSH oder WHITE_BRUSH sein.
Die Pinsel HOLLOW_BRUSH und NULL_BRUSH füllen keine Flächen aus. Der nachfolgende
Auszug aus einem Listing wählt zuerst einen schwarzen Pinsel und dann einen hellgrauen
für nachfolgenden Zeichenoperationen aus:
void CMyView::OnDraw (CDC *pDC)
{
pDC->SelectStockObject (BLACK_BRUSH);
.... // Hier werden
Flächen mit schwarzer Farbe ausgefuellt
pDC->SelectStockObject (LTGRAY_BRUSH);
.... // und hier
mit hellgrauer Farbe
} |
Und damit auch wieder etwas Farbe ins Spiel kommt, stehen Ihnen ebenfalls anwenderdefinierte
Pinsel zur Verfügung. Soll ein anwenderdefinierter Pinsel erstellt werden, so kann
dies wiederum auf zwei Arten erfolgen. Im ersten Fall wird ein MFC-Objekt vom Typ
CBrush ohne Parameter erstellt und anschließend eine der Methoden CreateSolidBrush(...),
CreateHatchBrush(...) oder CreatePatternBrush(...) aufgerufen. Die
Methode CreateSolidBrush(...) erzeugt einen einfarbigen, nicht gemusterten
Pinsel mit einer anzugebenden Farbe. CreateHatchBrush(...) erzeugt dagegen
einen Pinsel mit einem vom System vorgegebenen Muster. Das Muster sowie die Farben
werden über Parameter der Methode eingestellt. Für das Muster kann eine der Konstanten
HS_BDIAGONAL, HS_CROSS, HS_DIAGCROSS, HS_FDIAGONAL, HS_HORIZONTAL oder HS_VERTICAL
angegeben werden. Wird einer dieser gemusterten Pinsel verwendet, so wird der Hintergrund
des Musters immer mit der aktuellen Hintergrundfarbe ausgefüllt (siehe auch
Methode SetBkMode(...) und SetBkColor(...) in der vorherigen Lektion).
Eine Sonderstellung nimmt die Methode CreatePatternBrush(...) ein. Sie
erzeugt einen Pinsel über ein CBitmap-Objekt. Diese Methode wird immer
dann verwendet, wenn das Muster des Pinsels frei einstellbar sein soll. Die Größe
der als Brush zu verwendenden Bitmap ist unter WINDOWS98 und WINDOWS NT/2000 nicht
begrenzt. Für WINDOWS95 sollte die Bitmap aber auf 8x8 Pixel begrenzt werden.
|
Brush-Methode
|
Brushdarstellung
|
|

|
Alternativ kann ein Pinsel, genauso wie ein Stift, auch beim Aufruf seines Konstruktor
bereits initialisiert werden.
Auch Pinsel werden nach ihrer Erstellung nicht automatisch für die nachfolgenden
Zeichenoperationen verwendet. Sie müssen genauso wie Stifte mit der Methode
SelectObject(...) explizit auswählt werden.
Sehen wir uns jetzt die Funktionen zum Zeichnen von Flächen an. Beginnen wir
mit den Funktionen, die sich mit Rechtecken befassen. Die einfachste CDC-Methode
zum Zeichnen eines Rechtecks ist die Methode Rectangle(...). Sie zeichnet
ein Rechteck dessen Umrandung mit dem aktuellen Stift gezeichnet wird und das mit
dem aktuellen Pinsel ausgefüllt wird. Die Koordinatenangaben für das Rechteck erfolgen
wiederum in logischen Einheiten.
 |
Die Koordinate des rechten, unteren Punktes gehört nicht mehr zum Rechteck!
Dies gilt auch für alle nachfolgenden Rechteck-Funktionen. Außerdem muss die
Breite und Höhe bei allen Rechteck-Methode unter WINDOWS95/98 kleiner 32,767
Einheiten betragen da dort ein 16-Bit Koordinatensystem verwendet wird.. WINDOWS
NT/2000 hingegen verwendet ein 32-Bit Koordinatensystem, so dass dort die Grenze
bei 2.147E+09 liegt. |
Die nächste Methode zum Zeichnen eines Rechtecks ist die Methode FrameRect(...).
Sie zeichnet nur einen Rahmen mit dem als Parameter übergebenen Pinsel. Die Breite
des Rahmens ist immer 1 logische Einheit. Das Innere des Rechtecks wird nicht ausgefüllt.
 |
Beachten Sie bitte bei dieser und der nachfolgenden Methode, dass folgende
Bedingungen eingehalten werden: left<right und top<bottom. Werden diese Bedingungen
nicht erfüllt, so wird das Rechteck nicht gezeichnet! |
Die CDC-Methode FillRect(...) zeichnet ein ausgefülltes Rechteck,
das mit einem anzugebenden Pinsel ausgefüllt wird. Eine Umrandung des Rechtecks
erfolgt nicht.
Die letzte CDC-Methode zum Zeichnen eines Rechtecks ist die Methode
RoundRect(...). Sie zeichnet ein Rechteck mit abgerundeten Ecken. Das Rechteck
wird mit dem aktuellen Pinsel ausgefüllt und die Umrahmung wird mit dem aktuellen
Stift gezeichnet. Der letzte Parameter der Methode spezifiziert die Ellipse,
die für die Rundungen an den Ecken verwendet wird (siehe nachfolgendes Bild).

Eine Sonderstellung bei den Rechteck-Methoden nimmt die CDC-Methode
InvertRect(...) ein. Sie zeichnet kein Rechteck sondern invertiert alle
Pixel die sich innerhalb des angegebenen Rechtecks befinden. Diese Invertierung
ist eine boolsche NOT-Operation auf die innerhalb des Rechtecks liegenden Pixel.
So erzeugt die Methode aus weißen Pixel (RGB(0xFF,0xFF,0xFF)) schwarze Pixel (RGB(0x00,0x00,0x00)).
Das nachfolgende Bild veranschaulicht dies nochmals: Die Ellipse wurde mit einem
grünen, schraffierten Pinsel (RGB(0x00,0xFF,0x00)) gezeichnet. Der Bereich der Ellipse,
der sich innerhalb des zu invertierenden Rechtecks befindet, erhält als Ergebnis
der Invertierung die Farbe lila (RGB(0xFF,0x00,0xFF)), d.h. alle RGB-Anteile der
ursprünglichen Farbe erscheinen invertiert.

 |
Eine zweimalige Invertierung des gleichen Bereichs stellt wieder den Urzustand
des Bereichs her! |
Außer Rechteck-Funktionen stellt das GDI, und damit auch die MFC-Klasse CDC,
noch Funktionen zum Zeichnen von runden Flächen zur Verfügung. Um eine Ellipse zu
zeichnen wird die CDC-Methode Ellipse(...) eingesetzt. Die übergebenen
Koordinatenwerte, wieder in logischen Einheiten, spezifizieren das die Ellipse umschließende
Rechteck. Die Ellipse wird ebenfalls mit dem aktuellen Pinsel ausgefüllt und die
Umrandung mit dem aktuellen Stift gezeichnet.
 |
WINDOWS kennt keine Funktion um einen Kreis zu zeichnen. Ein Kreis wird
mit der Ellipsen-Funktion gezeichnet, wobei Breite gleich Höhe zu setzen ist.
Soll nur die Umrandung gezeichnet werden, d.h. ein nicht ausgefüllter Kreis,
so ist über die Methode SelectStockObject(...) entweder der Pinsel
NULL_BRUSH oder HOLLOW_BRUSH einzustellen. |
Die CDC-Methode Pie(...) zeichnet einen Ellipsenausschnitt,
d.h. ein 'Kuchenstück'. Dazu wird das die Ellipse umschließende Rechteck sowie der
Start- und Endpunkt des Kreissegments spezifiziert. Diese beide Punkte müssen
nicht unmittelbar auf der Ellipse liegen. Die Standard-Zeichenrichtung ist auch
hier gegen dem Uhrzeigersinn. Soll die Zeichenrichtung geändert werden, so ist hierfür
die Methode SetArcDirection(...) aufzurufen.

Eine ähnliche Funktion besitzt die Methode Chord(...). Sie zeichnet
ein Ellipsensegment. Ein Ellipsensegment verbindet den Start- und Endpunkt auf der
Ellipse durch eine gerade Linie. Diese Methode besitzt die gleichen Parameter wie
die Methode Pie(...).

Die letzte Gruppe der Flächenfunktionen behandelt Polygone. Polygone sind ausgefüllte
Linienzüge. Um Polygone darzustellen werden die CDC-Methoden Polygon(...)
bzw. PolyPolygon(...) eingesetzt. Ihre Parameter entsprechen denen der
Methode Polyline(...) bzw. PolyPolyline(...). Polygon(...)
zeichnet einen ausgefüllten Linienzug mit den in einem CPoint-Feld abgelegten
Stützpunkten. Der Linienzug wird automatisch vom letzten zum ersten Stützpunkt geschlossen.
Das Polygon wird mit dem aktuellen Pinsel ausgefüllt und der Linienzug des Polygons
wird mit dem aktuellen Stift gezeichnet. PolyPolygon(...) kann mit einem
Aufruf mehrere solcher Polygone zeichnen.

Im Zusammenhang mit Polygonen muss noch die CDC-Methode SetPolyFillMode(...)
erwähnt werden. Über den Parameter der Methode kann der Modus eingestellt werden,
der zum Ausfüllen des Polygons verwendet wird. Hierfür sind die beiden Werte WINDING
und ALTERNATE zulässig. Wie sich der Füllmodus auswirkt kann dem nachfolgenden Bild
entnommen werden. Hier wurde als Polygon ein einfacher Stern verwendet.

Und damit beenden wir die Theorie. Jetzt sind Sie wieder gefragt!
 |
Erweitern Sie das in der letzten Lektion begonnene Beispiel
jetzt. Anstelle einer Polyline ist nun ein Polygon zu zeichnen. Das Polygon
soll mit einem Pinsel ausgefüllt werden der ein diagonales Muster besitzt. Der
Linienzug des Polygons ist weiterhin in rot zu zeichnen während das Füllmuster
des Polygons mit grünen Streifen auf weißem Hintergrund gezeichnet werden soll.
 |
Wenn Sie genug geschwitzt haben kann ich Ihnen auch meine Lösung anzeigen. |
Lösung zur Darstellung des Polygons
void CGDIFuncView::OnDraw(CDC*
pDC)
{
CGDIFuncDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten
hinzufügen
// Stift fuer das Koordinatensystem
CPen CAxisPen(PS_DASH,1,RGB(0,0,255));
// Stift fuer die Kurve
CPen CLinePen;
CLinePen.CreatePen(PS_SOLID,1,RGB(255,0,0));
// Gemusterter
Pinsel zum Ausfuellen des Polygons
CBrush
CPFillBrush(HS_BDIAGONAL,RGB(0,255,0));
....
// Messkurve zeichnen
pDC->SelectObject(&CLinePen);
// Fuellfarbe des
Polygons setzen
pDC->SelectObject(&CPFillBrush);
pDC->SetBkColor(RGB(255,255,255));
// Polygon zeichnen
pDC->Polygon(m_pPts,m_nNoOfPts);
} |
Zuerst muss wieder der für das Polygon zu verwendende Pinsel erstellt
werden. Als Pinselstil wird für das diagonale Muster der Stil HS_BDIALGONAL
verwendet. Ebenso hätten Sie hier das Muster HS_FDIAGONAL einsetzen können.
Die Farbe des Muster wird beim Erstellen des Pinsels gleich auf grün gesetzt.
Dann wird vor dem Zeichnen des Polygons der neu erzeugte Pinsel ausgewählt
und als Hintergrundfarbe für den Pinsel die Farbe weiß eingestellt. Danach
kann das Polygon gezeichnet werden.
Ende der Lösung
|
Übersetzen und starten Sie das Programm. Wenn Sie ganz genau hinsehen
können Sie sehen, dass der Polygonzug mit dem entsprechenden Pinsel ausgefüllt
wurde.
|
Doch damit wollen wir es noch nicht bewenden lassen. Unser Fenster soll nun auch
noch einen hellgrauen Hintergrund erhalten. Im ersten Ansatz könnten wir in der
OnDraw(...) Methode diesen Hintergrund zeichnen. Doch wenn Sie sich ein
klein wenig in den WINDOWS-Nachrichten umsehen werden Sie dort eine Nachricht mit
der ID WM_ERASEBKGND finden. Diese Nachricht wird immer dann an ein Fenster gesendet,
wenn dessen Hintergrund neu gezeichnet werden muss. Bauen wir jetzt den Nachrichtenbearbeiter
für diese Nachricht in das Programm ein.
 |
Fügen Sie über den Klassen-Assistenten den Nachrichtenbearbeiter
für die WM_ERASEBKGND Nachricht zur Ansichtsklasse hinzu. Sie finden diese Nachricht
unter dem Punkt Behandlungsroutine für Windows Nachrichten hinzufügen.....
Modifizieren Sie die eingefügte Methode OnEraseBkgnd(...) wie folgt:
BOOL CGDIFuncView::OnEraseBkgnd(CDC*
pDC)
{
// TODO: Code für die Behandlungsroutine für Nachrichten hier
einfügen ...
// Groesse der Client-Area
des Fensters holen
CRect CClientRect;
GetClientRect(&CClientRect);
// Rechteck um eins in jeder
Richtung erhoehen da die
// rechte untere Kante nicht mitgezeichnet wird!
CClientRect.bottom++;
CClientRect.right++;
// Rechteck nun ausfuellen
pDC->FillRect(&CClientRect,&m_CBkBrush);
return TRUE;
} |
Als nächstes fügen Sie der Klasse noch die Membervariable m_CBkBrush
für den Pinsel zum Ausfüllen des Fensterhintergrundes hinzu. Erstellen Sie in
der OnInitialUpdate(...) Methode den Pinsel wie folgt:
void CGDIFuncView::OnInitialUpdate()
{
....
for (int iLoop=1; iLoop<m_nNoOfPts; iLoop++)
{
....
}
// Pinsel fuer Fensterhintergrund
erstellen
m_CBkBrush.CreateSolidBrush(RGB(240,240,240));
} |
Übersetzen und starten Sie das Programm nun wieder. Der Hintergrund des Fensters
sollte jetzt in einem hellem grau erscheinen.
|
Damit beenden wir die Übersicht über die Flächenfunktionen und wenden uns in
der nächsten Lektion der Beschreibung der verschiedenen Mapping-Modes zu. Mit Hilfe
der Mapping-Modes werden wir dann unsere Messkurve fensterfüllend darstellen können.
|