• Apfeltalk ändert einen Teil seiner Allgemeinen Geschäftsbedingungen (AGB), das Löschen von Useraccounts betreffend.
    Näheres könnt Ihr hier nachlesen: AGB-Änderung
  • Viele hassen ihn, manche schwören auf ihn, wir aber möchten unbedingt sehen, welche Bilder Ihr vor Eurem geistigen Auge bzw. vor der Linse Eures iPhone oder iPad sehen könnt, wenn Ihr dieses Wort hört oder lest. Macht mit und beteiligt Euch an unserem Frühjahrsputz ---> Klick

[Cocoa] Brauche Hilfe beim Event Handling

.mitro

Allington Pepping
Registriert
14.09.04
Beiträge
193
Liebe Leute,

ich programmiere schon seit langer Zeit und möchte mich jetzt endlich ein Bisserl in Cocoa vertiefen.

Auch wenn Cocoa auf mich einen sehr komfortablen Eindruck macht, fällt mir der Einstieg überraschender Weise relativ schwer (Stichwort InterfaceBuilder, Outlets, Actions und so weiter) - war bei objektorientierter Programmierung bisher den Zugang von Delphi, C++ Builder etc. gewohnt.

Konkrete Anfänger-Frage:

Ich erstelle in XCode eine neue Cocoa-Applikation, öffne die MainMenu.nib im InterfaceBuilder und hab ein leeres Fenster vor mir.

Wie bringe ich nun diese Applikation dazu, auf Tastenanschläge oder Mausclicks zu antworten (sagen wir mit einem NSAlert oder so) - also kein Steuerelement, sondern das Fenster an sich?

Den Currency Converter aus der Dokumentation hab ich programmiert, die Abläufe sind mir auch halbwegs klar und auch, dass ich das keyDown überschreiben muss. Nur wo? Aus dem "Handbuch" über Event Handlung werde ich nicht wirklich schlau, kann aber so schwer nicht sein.

Also: Hat jemand etwas Zeit, um mir eine kurze Step-by-step Anleitung zu geben, wie das hier funktioniert (mit allen Schritten in InterfaceBuilder und dann im Source Code)? Ich bin auch für einen Link sehr dankbar, der mir das erklärt (habe bisher nichts gefunden, was so einfache Dinge behandelt). Allerdings hab ich wieder einmal das Gefühl, den Wald vor lauter Bäumen nicht zu sehen, schließlich kann es ja nicht kompliziert sein, Clicks und Tastenanschläge abzufangen.

Schon mal vielen Dank und liebe Grüße

.mitro
 

Wikinator

Adams Parmäne
Registriert
21.08.04
Beiträge
1.297
du musst NSWindow subclassen:
in XCode eine neue Klasse erstellen, meinetwegen "myWindow.m", dort keyDown: implementieren, diese klasse dann in die Klassen-Hierarchie des IB ziehen und im Info-Dialog von dem Fenster unter "Custom Class" myWindow auswählen.
 

.mitro

Allington Pepping
Registriert
14.09.04
Beiträge
193
Vielen Dank, alles klar.

Nur zum Verständnis der Zusammenhänge: Wie würde das Ganze ausschauen, wenn ich zum Beispiel ein mouseMoved von einem NSTextField abfangen möchte?

Nochmals danke und liebe Grüße

.mitro
 

Wikinator

Adams Parmäne
Registriert
21.08.04
Beiträge
1.297
NSTextField subclassen und mouseMoved überschreiben. :-D

Am besten schreibst du dann den eigentlich Code (das was beim Bewegen der Maus/Drücken der Taste passieren soll) nicht direkt in die Subklassen sondern in ihre Delegate, soll heißen:
du definierst in awakeFromNib vom Controller das Delegate des Textfeldes, schreibst den eigentlichen Code in z.B.
Code:
- (void)myMouseHasMoved:(NSEvent *)event
des Controllers und in die Subklasse nur:
Code:
- (void)mouseMoved:(NSEvent *)event {
[INDENT][[self delegate] myMouseHasMoved:event];
[/INDENT]}

du gibst das Event sozusagen an den Controller weiter.
das hat den Vorteil, dass du die Subklasse immer wieder verwenden kannst und nur den Code im Controller anpassen musst.
 

.mitro

Allington Pepping
Registriert
14.09.04
Beiträge
193
Hm, vielleicht ist es schon ein Bissl zu spät für mich :)

Hab ich das richtig verstanden: Wenn ich eine Klasse von NSTextField ableite, kann ich mir im InterfaceBuilder davon die entsprechenden Source Files generieren lassen (xxx.h und xxx.m) - und in der xxx.m könnte ich theoretisch die mouseMoved-Methode überschreiben?

Das Dein Ansatz intelligenter ist, ist mir klar. Nur möchte ich's zuerst mal so richtig behirnen.

BTW: Hast Du irgendeinen Link (oder Buchtipp) mit ein paar Best Practices für Cocoa/Objective-C? Wie Du vielleicht gemerkt hast, bin ich noch verdammt unsicher, vor allem was die Planung eines Projekts angeht bzw. wie man was am Besten löst. In Delphi und Konsorten war's ja durchaus möglich, einfach mal drauf los zu programmieren. Bei XCode hab ich das Gefühl, dass ich ziemlich schnell im Abseits bin, wenn ich mir nicht alles, was ich mache, vorher gründlich überlege und daher wären die prinzipiellen Vorgehensweisen mal sehr interessant.

Danke und liebe Grüße

.mitro
 

Wikinator

Adams Parmäne
Registriert
21.08.04
Beiträge
1.297
ja, entweder erstellst du sie im IB, indem du in der Verzeichnishierarchie die richtige Superklasse aussuchst und im Kontextmenü "Subclass" auswählst, oder du erstellst eine neue Cocoa-Class in Xcode, dort musst du allerdings, bevor du in .m die Methode überschreibst, in .h
Code:
@interface Controller : NSObject
anpassen (die jeweilige Superklasse anstelle von NSObject).

Als Einstieg in Cocoa soll dieses Buch ganz gut sein:
http://www.amazon.de/COCOA-Programm...1/302-2115995-2608854?ie=UTF8&s=books-intl-de

Kann ich selber allerdings nicht beurteilen, da ich es nicht habe.
Gute Hilfen für Cocoa sind:
http://cocoadevcentral.com/ und
http://developer.apple.com/

Sonst kannst du auch nochmal die Suche hier im Forum benutzen, gibt sicher schon Threads dazu.
 

.mitro

Allington Pepping
Registriert
14.09.04
Beiträge
193
Danke nochmal, Du warst eine große Hilfe - für's Erste bin ich mal beschäftigt :)

Noch eine angenehme Nacht

.mitro
 

.mitro

Allington Pepping
Registriert
14.09.04
Beiträge
193
OK, eines noch ;)

Angenommen: Ich habe eine Klasse von NSTextField abgeleitet, die beiden Files erzeugt und angepasst (damit z.B. bei mouseMoved irgendwas passiert), genannt hab ich sie MyTextField.

Wenn ich jetzt zwei Textfelder vom Typ MyTextField in einem Fenster haben möchte, die beide auf das mouseMoved reagieren, allerdings mit unterschiedlichen Aktionen - wie sieht das im Code aus?

Wenn ich den Code für mouseMoved überschreibe, tu ich das ja quasi auf Klassenebene - es kann aber doch nicht so sein, dass ich für jedes Objekt eine eigene Klasse brauche, oder?

Hoffe, ich hab mich halbwegs verständlich ausgedrückt.

LG .mitro
 

Wikinator

Adams Parmäne
Registriert
21.08.04
Beiträge
1.297
hm, ich mache das so: (es kann auch sein, dass es unnötig ist und alle Informationen schon in NSEvent stecken)
in MyTextField.m:
Code:
- (void)mouseMoved:(NSEvent *)event {
[INDENT][[self delegate] mouseMoved:event onTextField:self];[/INDENT]}

dann kannst du im delegate "onTextField:" mit dem IBOutlet vergleichen und die Textfelder so unterscheiden.
 

Peter Maurer

Pommerscher Krummstiel
Registriert
16.03.04
Beiträge
3.077
hm, ich mache das so: (es kann auch sein, dass es unnötig ist und alle Informationen schon in NSEvent stecken)
in MyTextField.m:
Code:
- (void)mouseMoved:(NSEvent *)event {
[INDENT][[self delegate] mouseMoved:event onTextField:self];[/INDENT]}

dann kannst du im delegate "onTextField:" mit dem IBOutlet vergleichen und die Textfelder so unterscheiden.
Noch 'ne Moeglichkeit: Du sagst den Textfeldern, z.B. ueber eine SEL-Instanzvariable, was in diesem Falle geschehen soll. Dann brauchst Du nicht ueber den Delegate zu gehen, um dort u.U. sogar vermittels if-Konstrukten rauszufinden, was Sache ist. Statt dessen kannst Du dann sowas in der Art machen:

Code:
// Initialisierungskram im zustaendigen Controller

[myFirstTextField setMouseMoveTarget: self];
[myFirstTextField setMouseMoveAction: @selector(doSomething:)];

[mySecondTextField setMouseMoveTarget: self];
[mySecondTextField setMouseMoveAction: @selector(doSomethingElse:)];


// Und dann in Deiner NSTextField-Subklasse, der myFirstTextField und mySecondTextField angehoeren

- (void)setMouseMoveTarget: (id)theTarget {
    [theTarget retain]; // muss als mouseMoveTarget spaetestens in -dealloc wieder ein -release bekommen, sonst hallo Speicherleck
    [mouseMoveTarget release];
    mouseMoveTarget = theTarget;
}

- (void)mouseMoveTarget {
    return mouseMoveTarget;
}

- (void)setMouseMoveAction: (SEL)theAction {
    mouseMoveAction = theAction;
}

- (void)mouseMoveAction {
    return mouseMoveAction;
}

- (void)mouseMoved: (NSEvent*)theEvent {
    if ([[self mouseMoveTarget] respondsToSelector: [self mouseMoveAction]]) {
        [[self mouseMoveTarget] performSelector: [self mouseMoveAction] withObject: self];
    }
}

Disclaimer: Alles in der Apfeltalk-Dialogbox geschrieben. Wuerd' mich also nicht wundern, wenn sich ein paar Fehlerchen eingeschlichen haben. Das Prinzip ist aber vielleicht trotzdem zu erkennen.
 

.mitro

Allington Pepping
Registriert
14.09.04
Beiträge
193
Vielen Dank. So 100%ig durchblickt hab ich's noch nicht, aber sobald ich zu Hause bin, werd ich mich vor mein XCode-Projekt setzen und das umsetzen (und damit hoffentlich auch kapieren).

Mittlerweile bin ich der Ansicht, dass ich (hauptsächlich von Delphi her) eine etwas falsche Ansicht der Dinge hab. Im Prinzip ist ja (zum Beispiel) jeder Button, den man in Delphi zeichnet, "vom Typ TButton", also eine Subklasse von TButton. Somit sind ja dort auch nicht alle Buttons von der selben Subklasse abgeleitet und reagieren unterschiedlich auf dasselbe Ereignis, sondern genaugenommen ist jeder Button, der etwas anderes tut, eine eigene Subklasse von TButton. Also analog zur Vorgehensweise, wenn ich von NSTextField 2 Subklassen ableite und in beiden die mouseMoved-Methode überschreibe (wo dann eben was unterschiedliches passiert).

Sollte jemand Erfahrung mit Delphi und XCode haben, wäre es toll, wenn Ihr mir diese Theorie bestätigen/widerlegen könntet.

Mein Problem ist, dass ich zwar jetzt weiß, wie ich zur Lösung meines (fiktiven) Problems komme, allerdings hab ich Angst, mit der Kirche um's Dorf zu fahren - erscheint mir nämlich nach wie vor relativ viel Aufwand für relativ wenig Ergebnis. Wenn ich mir da anschau, mit wieviel weniger Code ich kompliziertere Tasks erledigen kann ...

In jedem Fall aber nochmal danke für die Tips und bis bald ;)

LG .mitro
 

seb2

Gast
Ich habe zwar keine Ahnung von Delphi, aber lies Dir beispielsweise nochmal das Posting von Peter durch. Auf die Art und Weise -- genauso wie die NSButtons oder andere GUI-Elemente -- hast Du mitnichten für jede Aktion eine extra Unterklasse, sondern jedes GUI-Element hat zwei Instanzvariablen, nämlich einmal, wer auf einen Klick reagiert und das Ziel.
Sprich: jeder Button merkt sich einfach "Bei einem Klick auf mich rufe ich X an Y auf".