18.11.2011

Xcode 4

Cocoa-Tutorial mit NSTextFields und NSButtons

In dem folgenden Tutorial wird am Beispiel eines Vokabeltrainers erklärt, wie man NSTextFields, NSButtons und NSColorWells in Objective-C und Cocoa verwenden kann.

Bei der Beispielanwendung werden die Vokabeln in einer plist als key-value-Paare verwaltet. Vereinfachend sind immer nur ein deutsches und ein englisches Wort gespeichert.

Die Applikation besteht aus zwei NSTextFields (Text Fields), zwei NSTextFields (Label), einem NSButton (Button) und einem NSColorWell (Color Well).

Das NSColorWell zeigt nach dem Click auf den OK-Button an, ob die Antwort richtig war. Bei einer richtigen Antwort wird es grün und bei eine falschen Antwort wird es rot.

Die Vokabel werden mit der Methode random() zufällig ausgewählt..

Xcode Projekt erstellen

Als erstes wird eine neues Projekt angelegt (⌘+⇧+N). In dem Fenster wird als Template Cocoa Application gewählt.

Mit Next gelangt man zum nächsten Dialog, in dem als Product Name VokabelTrainer angegeben wird.

Dieser Dialog wird wiederum mit Next bestätigt. Im abschließenden Dialog kann ein Order gewählt werden im dem das Xcode-Projekt abgelegt werden soll und ob ein lokales Git-Repository benötigt wird.

Mit dem create-Button wird das Projekt erstellt. Das neue Projekt sollte dann folgendermaßen aussehen:

VokabelTrainerAppDelegate.h

Als erstes werden die notwendigen Variablen und Methoden in der Header-Datei angelegt:

#import <Cocoa/Cocoa.h>

@interface SimpleVokabelTrainerAppDelegate : NSObject <NSApplicationDelegate> {
@private
    NSTextField *englishTextField;
    NSTextField *germanTextField;
    NSColorWell *signalColor;

    NSMutableDictionary* aDictionary;
}

-(IBAction) doClickOk:(id)sender;
-(void) nextEnglischWord ;

@property (assign) IBOutlet NSTextField *englishTextField;
@property (assign) IBOutlet NSTextField *germanTextField;
@property (assign) IBOutlet NSColorWell *signalColor;
@end

In den beiden NSTextFields werden die deutschen und englischen Vokabeln angezeigt. Die NSColorWell zeigt an, ob es sich um eine richtige oder falsche Antwort handelt. Das NSMutableDictionary speichert die geladenen Vokabeln.

Die Methode doClickOk:(id)sender; reagiert auf einen Click mit den OK-Button. Bei der Methode nextEnglishWord: handelt es sich um eine Methode, die zufällig eine neue Vokabel auswählt und im NSTextField englishTextField anzeigt.

VokabelTrainerAppDelegate.m

Im nächsten Schritt wird die Datei VokabelTrainerAppDelegate.m implementiert. Die generierte Datei sieht initial folgendermaßen aus:

//
//  VokabelTrainerAppDelegate.m
//  VokabelTrainer
//
//  Created by Jörn Hameister on 18.11.11.
//  Copyright 2011 http://www.hameister.de . All rights reserved.
//

#import "VokabelTrainerAppDelegate.h"

@implementation VokabelTrainerAppDelegate


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
}

@end

Als erstes ergänzt man die synthesize-Anweisungen direkt unter der Zeile @implementation VokabelTrainerAppDelegate, damit die getter und setter generiert werden:

@synthesize englishTextField;
@synthesize germanTextField;
@synthesize signalColor;

Danach wird die Hilfsfunktion nextEnglischWord: hinzugefügt, die zufällig eine englische Vokabel bestimmt und sie im NSTextField einträgt:

- (void) nextEnglischWord {
    //Ein zufaelliges englisches Wort auswaehlen und anzeigen
    NSString *key = [[aDictionary allKeys] objectAtIndex:(random() % [aDictionary count])];
    [englishTextField setStringValue:key];
}

Als nächstes wird in der Methode applicationDidFinishedLaunching:(NSNotification*)aNotification: die Vokabel-Datei geladen und in dem NSMutableDictionary aDictionary abgelegt (Weitere Erklärungen zum Laden von plist-Dateien findet man hier.). Dann wird das NSTextField für die englische Vokabel angepaßt, so daß es nicht editierbar und nicht aktiviert ist. Das NSTextField für die deutsche Vokabel wird programmatisch selektiert, so daß der Benutzer sofort die richtige Antwort eintippen kann, wenn die Applikation gestartet ist. Am Ende der Methode wird die erste englische Vokabel bestimmt und eingetragen.

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    //Laden der plist-Datei
    NSString* plistPath = [[NSBundle mainBundle] pathForResource:@"Vokabeln" ofType:@"plist"];
    aDictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];

    [englishTextField setEditable:FALSE];
    [englishTextField setEnabled:FALSE];

    //Das Textfeld selektieren, damit man sofort mit der Eingabe beginnen kann.
    [[germanTextField window] makeFirstResponder:germanTextField];

    //Erstes englisches Wort anzeigen
    [self nextEnglischWord];
}

Was jetzt noch fehlt ist die Methode doClickOk:(id)sender;, die aufgerufen wird, wenn der OK-Button benutzt wird. Diese Methode liest die Antwort aus germanTextField aus und vergleicht sie mit der richtigen Antwort aus dem Dictionary aDictionary.

Bei der richtigen Antwort wird eine neue englische Vokabel bestimmt und angezeigt und die NSColorWell wird auf grün gesetzt. Falls die Antwort falsch ist, wird die NSColorWell auf rot gesetzt. Abschließen wird das eingetippte Wort aus dem germanTextField gelöscht.

-(IBAction) doClickOK:(id)sender {
    if ([[germanTextField stringValue] isEqualToString:[aDictionary objectForKey:[englishTextField stringValue]]]) {
        //Eine neue Vokabel anzeigen
        [self nextEnglischWord];

        //Gruenes ImageWell bei richtigen Antwort
        [signalColor setColor:[NSColor greenColor]];
    }
    else {
        //Rotes ImageWell bei falscher Antwort
        [signalColor setColor:[NSColor redColor]];
    }
    //Reset TextField
    [germanTextField setStringValue:@""];
}

plist-Datei

Wie schon erwähnt, sollen die Vokabeln in einer plist-Datei abgelegt werden. Um eine neue plist-Datei zu erstellen, selektiert man den Folder VokabelTrainer und wählt im Kontextmenü New File... aus.

In dem Datei-Dialog wird erst Resource und dann Property List ausgewählt.

Nach der Bestätigung mit Next öffnet sich ein Dialog in dem der Name der plist-Datei angegeben wird.

Nach dem Speichern ist die Datei auf der linken Seite in Xcode zu sehen und es können neue key-Value-Paare eingetragen werden.

In dem Beispiel wurden über das Kontextmenü und Add Row zwei Werte hinzugefügt.

Die Cocoa-GUI

Abschließend muß nur noch die GUI erstellt und die Komponenten verbunden werden. Dazu wird die Datei MainMenu.xib selektiert. Daraufhin wird auf der rechten Seite der Interface-Builder (IB) angezeigt.

In der ObjectLibrary werden nun die zwei NSTextFields (Text Field), die zwei NSTextFields (Label), der NSButton (Push Button) und die NSColorWell (Color Well) ausgewählt und per Drag&Drop in das NSWindow gezogen.

In der ObjectLibrary kann durch Tippen der Anfangsbuchstaben die angezeigte Komponentenmenge reduziert werden. Im folgenden Bild wird nach NSTe gesucht, woraufhin das Label und das Text Field angezeigt werden.

Nachdem alle Komponenten in das NSWindow gezogen und die Größen angepaßt wurden, sollte das Ergebnis so aussehen:

Was jetzt noch fehlt, sind die Verbindungen zum Controller. Als erstes werden die Textfelder verbunden. Dazu selektiert man die Vokabel Trainer App Delegate (Controller) mit der Mouse und zieht den Cursor per ctrl-Drag auf das NSTextField für die englische Vokabel. Dort wählt man englischTextField aus. Auf die gleiche Weise verfährt man mit dem NSTextField für die deutsche Vokabel.

Beim ImageWell geht man genauso vor. Den Controller selektieren, den Cursor auf das Image Well ziehen und im Fenster das Outlet signalColor auswählen.

Beim OK-Button geht man genau anders herum vor. Es wird der Button selektiert und per ctrl-Drag der Cursor auf den Controller gezogen. In dem dann erscheinenden Menü, wird die Methode doClickOK: ausgewählt.

Nach dem Abspeichern läßt sich die Applikation kompilieren und starten.

Nun kann die Applikation nach belieben erweitert werden. Beispielsweise wären folgende Erweiterungen denkbar:

  • Statistiken, die Informationen über richtige und falsche Antworten anzeigen.
  • Mehrere Bedeutungen der Worte hinterlegen.
  • Umschalten zwischen zwischen der Abfrage von englischen und deutschen Worten.
  • ...