Programmieren mit Swift - Für macOS und iOS
Programmieren mit Swift - Für macOS und iOS
Zeichnen mit NSView, Teil 1

In Cocoa-Anwendung wird selten direkt auf das Programmfenster gezeichnet, sondern meistens in ein spezielles Steuerelement vom Typ NSView. Sie finden so ein Objekt ebenfalls in der Palette der Steuerelemente im Interface Builder. Allerdings wird ein NSView nicht von der Klasse MyController gesteuert, er benötigt zur Verwaltung eine eigene Klasse, die von NSView abgeleitet ist und die das Zeichnen regelt.

Auch diese Anwendung beginnt ihre Existenz als gewöhnliches Cocoa-Projekt, von dem Sie inzwischen bestimmt schon eine ganze Reihe erstellt haben. Eine MyController-Klasse benötigen Sie zu Anfang noch nicht. Fügen Sie aber trotzdem eine weitere Klasse zum Projekt hinzu. Wählen Sie aber jetzt nicht NSObjekt als Superklasse, sondern NSView. Nennen Sie diese Klasse MyView.
stacks_image_272631AB-3D41-4D05-A591-DE761F6975E4
Schon nach dem Erstellen enthält die Klasse zwei Methoden, die Sie in der MyView.m finden.
- (id)initWithFrame:(NSRect)frame
und
- (void)drawRect:(NSRect)dirtyRect
Während initWithFrame die Initialisierungs-Methode dieser Klasse ist, ist drawRect die Methode, in der tatsächlich gezeichnet wird. Als Parameter erhält diese Methode ein Rechteck, dirtyRect, welches neu gezeichnet werden muss. Das kann manchmal nützlich sein, am einfachsten ist es aber, immer den gesamten NSView neu zu zeichnen. Die Methode drawRect wird immer automatisch aufgerufen, wenn der View neu gezeichnet werden muss, zum Beispiel, wenn der View skaliert wurde. Das System merkt dies und handelt dementsprechend. Wie Sie einen NSView manuell aktualisieren können, werden Sie aber im Laufe dieser Lektion auch noch erfahren. drawRect sollten Sie nie manuell aufrufen.

Die erste Aufgabe in dieser Lektion soll sein, dem kompletten NSView einen grünen Hintergrund zu verpassen. Dazu holt man sich zuerst ein Rechteckt, das der Größe des View entspricht. Das ist einfach zu lösen, indem man bounds an das Objekt sendet. Erinnern Sie sich, dass self eine von NSView abgeleitete Klasse ist.
Anschließend wird die Farbe gesetzt und ein NSBezierPath in der Größe des Rechtecks gezeichnet.
- (void)drawRect:(NSRect)dirtyRect {
    NSRect bounds = [
self bounds];
    [[NSColor greenColor] set];
    [NSBezierPath fillRect:bounds];
}
Öffnen Sie nun den Interface Builder und ziehen Sie ein NSView (Custom View) auf das Programmfenster.
stacks_image_97DEDDBB-E969-4F21-A223-44118578B9EC
Platzieren Sie den NSView auf dem Programmfenster und verändern Sie die Eigenschaften des Objektes so, dass es sich an allen Seite des Fensters andockt und mit dem Fenster skaliert.
stacks_image_6DA81A8B-55F0-4ABA-AB1C-B2F40BDFDC80
Ändern Sie nun noch die Klassenidentität dieses NSView auf die von Ihnen erstellte Klasse MyView.
stacks_image_EDA81DFF-5D0E-411B-896C-53F35D4A6141
Speichern Sie alle Änderungen. Wenn Sie jetzt Ihre Anwendung starten, wird eine Instanz von MyView erzeugt und die drawRect-Methode sorgt dafür, dass der zugewiesene View komplett grün gefüllt wird.
stacks_image_901A3BFB-F840-471E-8910-EDBA7BDBA0D8
Ein wenig komplizierter wird es, wenn man zwei Rechtecke zeichnen möchte, die jeweils nur die Hälfe des View ausfüllen. Alles, was Sie tun müssen, ist die Größe und Position dieses Rechtecks zu berechnen. Aber das sollte Ihnen nicht sehr schwer fallen.
- (void)drawRect:(NSRect)dirtyRect {

    NSRect bounds = [
self bounds];

    NSRect leftRect = NSMakeRect(bounds.origin.x, bounds.origin.y,
     bounds.size.width /2, bounds.size.height);
    [[NSColor redColor] set];
    [NSBezierPath fillRect:leftRect];

    NSRect rightRect = NSMakeRect(bounds.origin.x + bounds.size.width /2 ,
     bounds.origin.y,bounds.size.width /2, bounds.size.height);
    [[NSColor blueColor] set];
    [NSBezierPath fillRect:rightRect];
}
Auch wenn Sie dieses Fenster skalieren, bleibt das Verhältnis des Rechtecks gleich. Denn immer, wenn Sie skalieren, wird automatisch die drawRect-Methode aufgerufen und ein neuer Wert für bounds ermittelt.
stacks_image_A1C76261-A4B2-4346-8AAC-DBD73203742A
Sehr schön kann man hier erkennen, dass trotz objektorientierter Programmierung, die Methoden selbst noch sequenziell abgearbeitet werden. Setzt man die Farbe für diese View, werden alle nachfolgenden Zeichenvorgänge in dieser Farbe vorgenommen, bis Sie eine neue Farbe bestimmen. Ein explizites Setzen der Farbe für jedes zu zeichnende Objekt ist nicht nötig. Auch werden die Objekte in der Reihenfolge, wie sie im Code stehen, gezeichnet. Wie bei einer Leinwand können sich dann auch Objekte überlagern.
- (void)drawRect:(NSRect)dirtyRect {

    NSRect bounds = [
self bounds];

    NSRect leftRect = NSMakeRect(bounds.origin.x, bounds.origin.y,
     bounds.size.width /2, bounds.size.height);
    [[NSColor redColor] set];
    [NSBezierPath fillRect:leftRect];

    NSRect rightRect = NSMakeRect(bounds.origin.x + bounds.size.width /2 ,
     bounds.origin.y,bounds.size.width /2, bounds.size.height);
    [[NSColor blueColor] set];
    [NSBezierPath fillRect:rightRect];

    NSRect orangeRect = NSMakeRect(bounds.origin.x + 20, bounds.origin.y + 20,
     bounds.size.width - 40, bounds.size.height -40);
    [[NSColor orangeColor] set];
    [NSBezierPath fillRect:orangeRect];
}
stacks_image_BB75856A-E4EA-4D1A-8957-C6A350C63F0A