Kontextmenü in einer NSOutlineView

  • Kontextmenü in einer NSOutlineView

    Ich möchte in einer NSOutlineView ein Kontextmenü anzeigen. Dazu habe ich im Interface Builder in dem entsprechenden Nib-File ein NSMenu angelegt und das Outlet "menu" der NSOutlineView mit diesem NSMenu verbunden.
    Laut Doku sollte das ausreichen, damit dieses Menu per rechter Mausklick bzw. Control-Klick angezeigt wird.

    Leider tut es das aber nicht.

    Was mache ich falsch bzw. was muss ich machen, damit ich ein Kontextmenu in der OulineView angezeigt bekomme?
  • Ich mach' dafür immer eine Unterklasse von NSOutlineView, heißt bei mir SKOutlineView:

    SKOutlineView.h:

    Quellcode

    1. #import <Foundation/Foundation.h>
    2. @interface SKOutlineView : NSOutlineView {
    3. }
    4. @end


    und SKOutlineView.m:

    Quellcode

    1. #import "SKOutlineView.h"
    2. @implementation SKOutlineView
    3. - (NSMenu *)menuForEvent:(NSEvent *)event
    4. {
    5. int row = [super rowAtPoint:[super convertPoint:[event locationInWindow] fromView:nil]];
    6. if ([self numberOfSelectedRows] <= 1) [self selectRow:row byExtendingSelection:NO];
    7. return [[self delegate] contextMenuForItem:[self itemAtRow:row]];
    8. }
    9. @end
    Alles anzeigen


    Die .h in den InterfaceBuilder ziehen, im IB den OutlineView anklicken, im Inspector zu "Custom Class" gehen und "SKOutlineView" anklicken.

    Dein Delegate muß dann nur noch

    Quellcode

    1. - (NSMenu *)contextMenuForItem:(id)item;


    implementieren, bekommt dann in item übergeben, für welches Item das Kontextmenü sein soll und da kannst Du dann entweder dynamisch eins zusammenbasteln oder auch eins aus einem Nib.

    Ich mach' das immer so, weil's eigentlich immer irgendwelche "representedObjects" zu setzen gibt oder irgendwelche MenuItems enabled oder disabled werden müssen.

    Wenn Du mehrere Spalten hast, sag bescheid, das hier ist die "simple" Version, die "extended Version" :D übergibt auch die Spalte mit.
    if (!exit(-1)) fprintf(stderr, "exit call failed. Program will continue\n");

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von seb2 ()

  • Danke für die schnelle Hilfe zu so später Stunde!

    Ich hatte mir schon fast gedacht, dass man ohne abzuleiten das nicht hinbekommt, obwohl doch durch das Delegate-Prinzip die Notwendigkeit des ständigen Ableitens verringert werden soll.

    Laut Doku gibt die NSView-Implementierung der Methode 'menuForEvent:' einfach das Ergebnis der Methode 'menu' zurück, welche das Menu sein sollte, dass man in das Outlet 'menu' geschrieben hat (per Interface Builder).

    Ich werde deinen Code-Vorschlag 'mal ausprobieren (aber erst morgen ;)
  • Original von Stalkingwolf
    Aber man kommt ja nicht drumherum ;)
    /quote]

    Doch man kann mit Categorien arbeiten, das menuForEvent Problem habe ich so gelöst:

    Quellcode

    1. @implementation NSOutlineView (MyExtensions)
    2. // return the selected item
    3. - (id) selectedItem
    4. {
    5. return [self itemAtRow: [self selectedRow]];
    6. }
    7. //
    8. -(NSMenu*) menuForEvent:(NSEvent*)evt
    9. {
    10. NSPoint point = [self convertPoint:[evt locationInWindow] fromView:NULL];
    11. int column = [self columnAtPoint:point];
    12. int row = [self rowAtPoint:point];
    13. if ( column >= 0 && row >= 0 && [[self delegate] respondsToSelector:@selector(outlineView:menuForTableColumn:item:)] )
    14. return [[self delegate] outlineView:self menuForTableColumn:[[self tableColumns] objectAtIndex:column] item: [self itemAtRow: row]];
    15. return NULL;
    16. }
    17. @end
    Alles anzeigen
    Xcode 4 sucks – „,Multiple exclamation marks‘, he went on, shaking his head, are a sure sign of a diseased mind.‘“ (Terry Pratchett 1992: Eric)

    "Wir ordnen und befehlen hiermit allen Ernstes, dass die Advocati wollene schwarze Mäntel, welche bis unter das Knie gehen, unserer Verordnung gemäß zu tragen haben, damit man die Spitzbuben schon von weitem erkennt." (Friedrich Wilhelm I., Soldatenkönig)
  • Die Methode "menuForEvent:" über eine Kategorie zu überschreiben, ist ja ein interessante Lösung!

    Ich wußte nicht, dass das möglich ist.
    Denn: Wird die Methode einer Klasse in mehreren Kategorien überschrieben, welche Implementierung wird dann bei dem Aufruf der entsprechenden Methode ausgeführt?
    Schließlich existieren die Kategorien gleichberechtigt nebeneinander und sind nicht wie bei der Ableitung in eine Reihenfolge gebracht.
  • Ich habe es zwar noch nicht ausprobiert, aber wenn man einer Klasse in mehreren unterschiedlichen Categories die gleiche Methode unterjubeln will, sollte der Compiler meckern bzw. spätestens der Linker.
    Das das hier mit einer Category funktioniert liegt daran, dass NSOutlineView ja nicht selbst -menuForEvent: implementiert, sondern nur geerbt hat. Die Category überschreibt die geerbte Methode. Hätte NSOutlineView -menuForEvent: selbst bereits überschrieben, würde das mit der Category nicht mehr klappen. Dann muss man 'ne Subklasse machen.

    Michael
  • Original von chacko
    Denn: Wird die Methode einer Klasse in mehreren Kategorien überschrieben, welche Implementierung wird dann bei dem Aufruf der entsprechenden Methode ausgeführt?


    Wieso willst Du eine Methode in mehrere Kategorien überschreiben?

    In meiner Kategorie wird in der Delegate-Klasse abgefragt ob die Methode outlineView:menuForTableColumn:item: unterstützt wird. Erst dann wird die Methode in der Delegate-Klasse aufgerufen, gibt es die Methode nicht passiert auch nichts.

    Gruß, Michael
    Xcode 4 sucks – „,Multiple exclamation marks‘, he went on, shaking his head, are a sure sign of a diseased mind.‘“ (Terry Pratchett 1992: Eric)

    "Wir ordnen und befehlen hiermit allen Ernstes, dass die Advocati wollene schwarze Mäntel, welche bis unter das Knie gehen, unserer Verordnung gemäß zu tragen haben, damit man die Spitzbuben schon von weitem erkennt." (Friedrich Wilhelm I., Soldatenkönig)
  • Wieso willst Du eine Methode in mehrere Kategorien überschreiben?
    In meiner Kategorie wird in der Delegate-Klasse abgefragt ob die Methode outlineView:menuForTableColumn:item: unterstützt wird. Erst dann wird die Methode in der Delegate-Klasse aufgerufen, gibt es die Methode nicht passiert auch nichts.


    Es geht mir nicht um die Methode, die durch den Delegate implementiert werden KANN, sondern um die Tatsache, dass du in deiner Category zu NSOutlineView eine Methode überschreibst, die von NSView, also einer Basisklasse von NSOutlineView, definiert wird ("menuForEvent:").
    Ich wußte nicht, dass man in einer Category eine Methode der Klasse, zu der die Category gehört, (oder eine der Basisklassen) überschreiben kann.
    Ich habe mir dann die Frage gestellt, wie das Verhalten der Sprache ist, wenn die Methode einer Klasse in mehreren Categories zu dieser Klasse überschrieben wird.

    Ich habe dazu nochmal die Doku zu Objective-C konsultiert und habe folgendes zu dem Thema gefunden:
    There's no limit to the number of categories that you can add to a class, but each category name must be different, and each should declare and define a different set of methods.
    The methods added in a category can be used to extend the functionality of the class or override methods the class inherits. A category can also override methods declared in the class interface. However, it cannot reliably override methods declared in another category of the same class. A category is not a substitute for a subclass. It's best if categories don't attempt to redefine methods that are explicitly declared in the class's @interface section. Also note that a class can't define the same method more than once.
    When a category overrides an inherited method, the new version can, as usual, incorporate the inherited version through a message to super. But there's no way for a category method to incorporate a method with the same name defined for the same class.

    Also:
    - Das überschreiben von Methoden durch EINE Categorien ist zwar möglich, aber nicht "die feine englische Art".
    - Falls eine Methode in mehreren Categories überschrieben wurde, ist nicht festgelegt (deterministisch), welche Implementierung zur Laufzeit aufgerufen wird; Obj-C ermittelt ja als Sprachen mit dynamischer Bindung erst zur Laufzeit, welche Implementierung aufgerufen wird.
    - Aus überschreibenden Methoden in Categories kann man nicht die Implementierung der zugehörigen Klasse aufrufen - nur die Implementierungen einer der Basisklassen (über "super")

    Ich habe 'mal ein kleines Testprogramm geschrieben - und tatsächlich verhält es sich so wie in der Doku beschrieben...
  • Original von chacko
    Es geht mir nicht um die Methode, die durch den Delegate implementiert werden KANN, sondern um die Tatsache, dass du in deiner Category zu NSOutlineView eine Methode überschreibst, die von NSView, also einer Basisklasse von NSOutlineView, definiert wird ("menuForEvent:").
    Ich wußte nicht, dass man in einer Category eine Methode der Klasse, zu der die Category gehört, (oder eine der Basisklassen) überschreiben kann.
    Ich habe mir dann die Frage gestellt, wie das Verhalten der Sprache ist, wenn die Methode einer Klasse in mehreren Categories zu dieser Klasse überschrieben wird.


    Sorry, da habe ich Dich falsch verstanden.

    Gruß, Michael
    Xcode 4 sucks – „,Multiple exclamation marks‘, he went on, shaking his head, are a sure sign of a diseased mind.‘“ (Terry Pratchett 1992: Eric)

    "Wir ordnen und befehlen hiermit allen Ernstes, dass die Advocati wollene schwarze Mäntel, welche bis unter das Knie gehen, unserer Verordnung gemäß zu tragen haben, damit man die Spitzbuben schon von weitem erkennt." (Friedrich Wilhelm I., Soldatenkönig)