1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

[Cocoa] Brauche Hilfe beim Event Handling

Dieses Thema im Forum "OS X-Developer" wurde erstellt von .mitro, 15.11.06.

  1. .mitro

    .mitro Allington Pepping

    Dabei seit:
    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
     
  2. Wikinator

    Wikinator Adams Parmäne

    Dabei seit:
    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.
     
  3. .mitro

    .mitro Allington Pepping

    Dabei seit:
    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
     
  4. Wikinator

    Wikinator Adams Parmäne

    Dabei seit:
    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.
     
  5. .mitro

    .mitro Allington Pepping

    Dabei seit:
    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
     
  6. Wikinator

    Wikinator Adams Parmäne

    Dabei seit:
    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.
     
  7. .mitro

    .mitro Allington Pepping

    Dabei seit:
    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
     
  8. .mitro

    .mitro Allington Pepping

    Dabei seit:
    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
     
  9. Wikinator

    Wikinator Adams Parmäne

    Dabei seit:
    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.
     
  10. Peter Maurer

    Peter Maurer Carmeliter-Renette

    Dabei seit:
    16.03.04
    Beiträge:
    3.274
    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.
     
  11. .mitro

    .mitro Allington Pepping

    Dabei seit:
    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
     
  12. seb2

    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".
     

Diese Seite empfehlen