objective-c cocoa nsoutlineview

objective c - ¿Cómo se agrega el menú contextual al NSOutlineView(es decir, al menú del botón derecho)?



objective-c cocoa (4)

Aquí hay un ejemplo de Swift 2.0 que usa una subclase y extiende el NSOutlineDelegate predeterminado para que pueda definir sus menús en el delegado.

protocol MenuOutlineViewDelegate : NSOutlineViewDelegate { func outlineView(outlineView: NSOutlineView, menuForItem item: AnyObject) -> NSMenu? } class MenuOutlineView: NSOutlineView { override func menuForEvent(event: NSEvent) -> NSMenu? { let point = self.convertPoint(event.locationInWindow, fromView: nil) let row = self.rowAtPoint(point) let item = self.itemAtRow(row) if (item == nil) { return nil } return (self.delegate() as! MenuOutlineViewDelegate).outlineView(self, menuForItem: item!) } }

¿Cómo se agrega la capacidad de hacer clic con el botón derecho en una fila en un NSOutlineView para que pueda decir eliminar un objeto o alguna otra actividad? (es decir, Me gusta cuando haces clic derecho en una carpeta en la aplicación Apple Mail)

Creo que estoy a mitad de camino, tengo una subclase de NSOutlineView que me permite capturar el clic derecho y mostrar un menú contextual basado en la fila seleccionada en lugar de la fila en la que el mouse hace clic.

@implementation NSContextOutlineView - (NSMenu *)defaultMenu { if([self selectedRow] < 0) return nil; NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@"Model browser context menu"] autorelease]; [theMenu insertItemWithTitle:@"Add package" action:@selector(addSite:) keyEquivalent:@"" atIndex:0]; NSString* deleteItem = [NSString stringWithFormat: @"Remove ''%i''", [self selectedRow]]; [theMenu insertItemWithTitle: deleteItem action:@selector(removeSite:) keyEquivalent:@"" atIndex:1]; return theMenu; } - (NSMenu *)menuForEvent:(NSEvent *)theEvent { return [self defaultMenu]; } @end

Lo siento si la respuesta es obvia. No puedo encontrar ayuda en línea o en la documentación.

Gracias a Void por la respuesta, me llevó a usar esto:

- (NSMenu *)menuForEvent:(NSEvent *)theEvent { NSPoint pt = [self convertPoint:[theEvent locationInWindow] fromView:nil]; id item = [self itemAtRow: [self rowAtPoint:pt]]; return [self defaultMenuFor: item]; }


En su método menuForEvent puede averiguar en qué fila se produjo el clic. Puede pasar eso como un parámetro a su método predeterminado de menú - tal vez llamarlo valor predeterminadoMenuForRow:

-(NSMenu*)menuForEvent:(NSEvent*)evt { NSPoint pt = [self convertPoint:[evt locationInWindow] fromView:nil]; int row=[self rowAtPoint:pt]; return [self defaultMenuForRow:row]; }

Ahora puede crear el menú para la fila que encontró en el evento ...

-(NSMenu*)defaultMenuForRow:(int)row { if (row < 0) return nil; NSMenu *theMenu = [[[NSMenu alloc] initWithTitle:@"Model browser context menu"] autorelease]; [theMenu insertItemWithTitle:@"Add package" action:@selector(addSite:) keyEquivalent:@"" atIndex:0]; [theMenu insertItemWithTitle:[NSString stringWithFormat:@"Remove ''%i''", row] action:@selector(removeSite:) keyEquivalent:@"" atIndex:0]; // you''ll need to find a way of getting the information about the // row that is to be removed to the removeSite method // assuming that an ivar ''contextRow'' is used for this contextRow = row; return theMenu; }

Además, como ya se mencionó en los comentarios, realmente no debería usar el prefijo NS en sus propias clases. Existe la posibilidad de un choque en el futuro y confundirá a todos los que están viendo su código, incluido usted mismo :)

Espero que esto ayude...


Mucho más tarde que la pregunta del OP, pero para otros como yo que se preguntan, aquí está mi solución. También necesita subclasificar NSOutlineView, que no es alentada por Apple doc, de todos modos ...

En lugar de anular menuForEvent: rightMouseDown:

- (void)rightMouseDown:(NSEvent *)event { NSPoint pt = [self convertPoint:[event locationInWindow] fromView:nil]; NSInteger row = [self rowAtPoint:pt]; id item = [self itemAtRow:row]; NSMenu *menu; //set the menu to one you have defined either in code or IB through outlets self.menu = menu; [super rightMouseDown:event]; }

Esto tiene la ventaja de mantener llamadas de delegado para actualizar el menú a partir de entonces y también mantiene el trazado de fila en el botón derecho.


Si lo prefiere, puede adjuntar el menú a la vista de celda individual o vista de fila y compilarlo con el generador de interfaz:

@implementation BSMotleyOutlineView -(NSMenu *)menuForEvent:(NSEvent *)event { NSPoint pt = [self convertPoint:[event locationInWindow] fromView:nil]; NSInteger row = [self rowAtPoint:pt]; if (row >= 0) { NSTableRowView* rowView = [self rowViewAtRow:row makeIfNecessary:NO]; if (rowView) { NSInteger col = [self columnAtPoint:pt]; if (col >= 0) { NSTableCellView* cellView = [rowView viewAtColumn:col]; NSMenu* cellMenu = cellView.menu; if(cellMenu) { return cellMenu; } } NSMenu* rowMenu = rowView.menu; if (rowMenu) { return rowMenu; } } } return [super menuForEvent:event]; } @end