2011-03-27 8 views
12

¿Hay alguna forma de que pueda obtener TODAS las vistas, subvistas y subvistas de estas subvistas (se entiende ...) de NSWindow?Obtenga TODAS las vistas y subvista de NSWindow

Gracias.

+3

Bienvenido a Stackoverflow! ¿Por qué no cambiar su nombre de usuario de user635064 a algo más único? Además, será más probable que obtenga ayuda si marca las respuestas correctas como tales. – Moshe

+2

Estoy de acuerdo con el nombre de usuario, pero no sé por qué me está diciendo que la pregunta es correcta. Siempre marcó una pregunta correcta si me ayudó ... – user635064

+0

@user Peter está en lo cierto. – Moshe

Respuesta

9

Aquí es una categoría en NSView:

@interface NSView (MDRecursiveSubviews) 
- (NSArray *)allSubviews; 
@end 

@implementation NSView (MDRecursiveSubviews) 

- (NSArray *)allSubviews { 
    NSMutableArray *allSubviews = [NSMutableArray arrayWithObject:self]; 
    NSArray *subviews = [self subviews]; 
    for (NSView *view in subviews) { 
     [allSubviews addObjectsFromArray:[view allSubviews]]; 
    } 
    return [[allSubviews copy] autorelease]; 
} 

@end 

Con un archivo de punta rápida que creé con una jerarquía de vista, impresa esto:

[RecursiveSubviewsAppDelegate awakeFromNib] allSubviews == (
    "<NSView: 0x10390dfd0>", 
    "<NSView: 0x103c07ae0>", 
    "<NSView: 0x100129cc0>", 
    "<NSButton: 0x100115ce0>", 
    "<NSButton: 0x100116900>", 
    "<NSButton: 0x1001165c0>", 
    "<NSButton: 0x100116130>", 
    "<NSButton: 0x100114ad0>", 
    "<NSButton: 0x100115910>", 
    "<NSButton: 0x100115090>", 
    "<NSScrollView: 0x103b07a30>", 
    "<NSClipView: 0x103b07d40>", 
    "<NSTextView: 0x103b083c0>\n 
Frame = {{0.00, 0.00}, {159.00, 58.00}}, 
Bounds = {{0.00, 0.00}, {159.00, 58.00}}\n 
Horizontally resizable: NO, Vertically resizable: YES\n 
MinSize = {159.00, 58.00}, MaxSize = {463.00, 10000000.00}\n", 
    "<NSScroller: 0x1001145b0>", 
    "<NSScroller: 0x100114840>", 
    "<NSScrollView: 0x10390ea00>", 
    "<NSClipView: 0x10390ef10>", 
    "<NSTableView: 0x10390f570>", 
    "<NSScroller: 0x103b06f10>", 
    "<NSScroller: 0x103b07460>", 
    "<NSClipView: 0x1039105d0>", 
    "<NSTableHeaderView: 0x103910300>", 
    "<_NSCornerView: 0x103911c20>" 

una nota de la preocupación que debo añadir es que no está claro para mí cómo esto sería útil, excepto como una herramienta de depuración. Pero incluso entonces, probablemente haya formas más fáciles de hacer las cosas.

+0

Funciona también para iOS: NS -> UI. – clozach

3

Si te entendí correctamente, deberías crear un método que se llame recursivamente. Algo como esto:

- (NSArray *)allSubviewsOfView:(NSView *)view 
{ 
    NSMutableArray *subviews = [[view subviews] mutableCopy]; 
    for (NSView *subview in [view subviews]) 
    [subviews addObjectsFromArray:[self allSubviewsOfView:subview]]; //recursive 
    return subviews; 
} 

A continuación, llamar algo así como

NSArray *allSubviewsOfWindow = [self allSubviewsOfView:[window contentView]]; 

para obtener sus puntos de vista. (Y no se olvide de hacer la gestión de memoria si no está usando GC.)

+0

Un método recursivo nunca terminará como lo diseñó. – Moshe

+0

Gracias, aunque esto se repetirá infinitamente hasta que se desborde la pila, agregaré un caso base. Pero, ¿es esta la mejor manera? – user635064

+1

@Enchilada: No te olvides de liberar la matriz. @ user635064: No, no se repetirá infinitamente. Podría hacerlo si agregara una vista como una subvista de una de sus propias subvistas, pero luego sería un ciclo cerrado, no accesible desde el 'contentView' de una ventana. –

2

No estoy seguro acerca de la recursividad infinita en las otras respuestas pero definitivamente no puede modificar una matriz mientras realiza una enumeración rápida en ella. Aquí hay un método que escribí para iOS que recorre todas las subvistas hasta que ya no queda nada por explorar. Supongo que lo mismo o similar funcionaría para NSView. Espero que esto ayude.

(Edit: Ahora ... si yo hubiera mirado un poco más allá de los resultados de mi búsqueda, me he encontrado de esta manera realmente fácil de hacerlo primero: How can I loop through all subviews of a UIView, and their subviews and their subviews)

- (NSMutableArray *)allSubviewsInView:(UIView *)parentView { 

    NSMutableArray *allSubviews  = [[NSMutableArray alloc] initWithObjects: nil]; 
    NSMutableArray *currentSubviews = [[NSMutableArray alloc] initWithObjects: parentView, nil]; 
    NSMutableArray *newSubviews  = [[NSMutableArray alloc] initWithObjects: parentView, nil]; 

    while (newSubviews.count) { 

     [newSubviews removeAllObjects]; 

     for (UIView *view in currentSubviews) { 

      for (UIView *subview in view.subviews) [newSubviews addObject:subview]; 

     } 

     [currentSubviews removeAllObjects]; 
     [currentSubviews addObjectsFromArray:newSubviews]; 
     [allSubviews addObjectsFromArray:newSubviews]; 

    } 

    NSLog(@"\n%d total subviews:\n%@",allSubviews.count, allSubviews); 

    return allSubviews; 

} 

resultados registrados por parte de un punto de vista de la muestra :

18 total subviews: 
(
    "<UIRoundedRectButton: 0x6a7a590; frame = (26 20; 72 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x6a772d0>>", 
    "<UISwitch: 0x6a7f930; frame = (26 76; 79 27); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x6a7fa20>>", 
    "<UIImageView: 0x685e4a0; frame = (82 20; 139 139); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x685eca0>>", 
    "<UITextView: 0x6893e40; frame = (20 196; 192 79); text = 'Lorem ipsum dolor sit er ...'; clipsToBounds = YES; autoresize = RM+BM; layer = <CALayer: 0x687c330>; contentOffset: {0, 0}>", 
    "<UIView: 0x6a88af0; frame = (26 304; 198 123); autoresize = RM+BM; tag = 1; layer = <CALayer: 0x6a88b20>>", 
    "<UIButtonLabel: 0x6a7f410; frame = (0 0; 0 0); clipsToBounds = YES; hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6a7f4d0>>", 
    "<_UISwitchInternalView: 0x6a7fa50; frame = (-1 0; 79 27); layer = <CALayer: 0x6a79b90>>", 
    "<UITextSelectionView: 0x6894070; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x68940d0>>", 
    "<UIImageView: 0x68924b0; frame = (0 72; 192 7); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x6892520>>", 
    "<UIImageView: 0x6894100; frame = (185 0; 7 79); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x6894180>>", 
    "<UIWebDocumentView: 0x7416600; frame = (0 0; 192 394); text = 'Lorem ipsum dolor sit er ...'; opaque = NO; userInteractionEnabled = NO; layer = <UIWebLayer: 0x6895330>>", 
    "<UIView: 0x6a88b50; frame = (10 10; 80 80); autoresize = W+H; tag = 2; layer = <CALayer: 0x6a88b80>>", 
    "<UIImageView: 0x6a80610; frame = (1 0; 77 27); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6a80650>>", 
    "<UIView: 0x6a806f0; frame = (1 0; 77 27); clipsToBounds = YES; alpha = 0; layer = <CALayer: 0x6a80720>>", 
    "<UIView: 0x6a88fa0; frame = (5 5; 50 50); autoresize = W+H; tag = 3; layer = <CALayer: 0x6a88fd0>>", 
    "<UIImageView: 0x6a808e0; frame = (-2 0; 79 27); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6a84d30>>", 
    "<UIImageView: 0x6a84c00; frame = (-2 0; 131 27); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6a84d90>>", 
    "<UIImageView: 0x6a84c40; frame = (49 0; 29 27); userInteractionEnabled = NO; layer = <CALayer: 0x6a84c80>>" 
) 
-2
NSArray *arrofView = [[self view] subviews]; 
+0

El OP estaba buscando subvistas _y_ sus subvistas (etc., supongo). – Monolo

8

Hay un mensaje privado que puede ser enviado en NSView para imprimir la jerarquía de control.

[NSView _subtreeDescription] le da toda la jerarquía de NSView, es decir, sus hijos y sus hijos.

4
static void dumpViews(NSView* v, int level) { 
    NSString* indent = @""; 
    for (int i = 0; i < level; i++) { 
     indent = [indent stringByAppendingString:@" "]; 
    } 
    NSLog(@"%@%@ %@", indent, [v class], NSStringFromRect(v.frame)); 
    if (v.subviews != null) { 
     for (id s in v.subviews) { 
      dumpViews(s, level + 1); 
     } 
    } 
} 

- (void) windowControllerDidLoadNib: (NSWindowController*) controller { 
    NSWindow* window = controller.window; 
    dumpViews(window.contentView, 0); 
    ... 
0

La solución anterior no funcionará si hay vistas dentro de las vistas. Tendríamos que hacer una solución recursiva como se muestra a continuación.

-(void) printViewHierarchy: (UIView *) view withTag: (NSInteger) tag { 
 
    if (view == nil) { 
 
    return; 
 
    } 
 
    if (view == nil || [view tag] == tag) { 
 
    NSLog(@"%@", view); 
 
    return; 
 
    } 
 
    for (UIView * subview in [view subviews]) { 
 
    [self printViewHierarchy: subview withTag: tag]; 
 
    } 
 
} 
 

 
- (void) findAllViews { 
 
    
 
    UIView * baseView = [UIView new]; 
 
    [baseView setTag: 1]; 
 
    
 
    UIView * secondRowA = [UIView new]; 
 
    [secondRowA setTag: 2]; 
 
    
 
    UIView * secondRowB = [UIView new]; 
 
    [secondRowB setTag: 3]; 
 
    
 
    UIView * thirdRowA = [UIView new]; 
 
    [thirdRowA setTag: 4]; 
 
    
 
    UIView * thirdRowB = [UIView new]; 
 
    [thirdRowB setTag: 5]; 
 
    
 
    [secondRowA addSubview: thirdRowA]; 
 
    [secondRowB addSubview: thirdRowB]; 
 
    
 
    [baseView addSubview: secondRowA]; 
 
    [baseView addSubview: secondRowB]; 
 
    
 
    [self printViewHierarchy: baseView withTag: 6]; 
 
}

Cuestiones relacionadas