【问题标题】:Get ALL views and subview of NSWindow获取 NSWindow 的所有视图和子视图
【发布时间】:2011-07-23 17:55:41
【问题描述】:

有没有办法我可以获得 NSWindow 的所有视图和子视图以及这些子视图的子视图(你明白了......)?

谢谢。

【问题讨论】:

  • 欢迎来到 StackOverflow!为什么不将用户名从 user635064 更改为更独特的名称?此外,如果您将正确答案标记为正确答案,您将更有可能获得帮助。
  • 同意用户名,但不知道您为什么告诉我要标记问题正确?如果对我有帮助,我总是将问题标记为正确...
  • 只需将您的视图添加到 NSMutableArray 以便稍后枚举。

标签: objective-c cocoa nsview nswindow


【解决方案1】:

如果视图中有视图,上述解决方案将不起作用。我们需要做一个递归解决方案,如下所示。

-(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];
}

【讨论】:

    【解决方案2】:

    有一条私人消息可以发送到NSView 以打印控制层次结构。

    [NSView _subtreeDescription] 为您提供NSView 的整个层次结构,即它的子级和它们的子级。

    【讨论】:

      【解决方案3】:
      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);
          ...
      

      【讨论】:

        【解决方案4】:
        NSArray *arrofView = [[self view] subviews];
        

        【讨论】:

        • OP 正在寻找子视图他们的子视图(等等,我想)。
        【解决方案5】:

        如果我理解正确,您将不得不创建一个递归调用自身的方法。像这样的:

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

        然后你会调用类似的东西

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

        获取您的意见。 (如果您不使用 GC,请不要忘记进行内存管理。)

        【讨论】:

        • 递归方法永远不会像你设计的那样结束。
        • 谢谢,虽然这将无限递归直到堆栈溢出,我将添加一个基本情况。但这是最好的方法吗?
        • @Enchilada:不要忘记释放数组。 @user635064:不,它不会无限递归。如果您将视图添加为它自己的子视图之一的子视图,则可以,但这将是一个封闭的循环,无法从窗口的contentView 访问。
        • @Enchilada:这个方法的真正问题不是它无限递归,而是你正在枚举一个你正在变异的数组。
        • 呸,无法编辑我之前的评论。这是一个更好的方法:@Moshe:它只会递归到视图层次结构中的视图深度。因此,除非您可以创建 nib 文件或以编程方式创建具有无限数量的子视图的视图层次结构,否则没有无限递归(其行为将导致“第一个”无限递归,而不是在调用该方法时遇到的任何情况)。
        【解决方案6】:

        不确定其他答案中的无限递归,但在对数组进行快速枚举时绝对不能修改数组。这是我为 iOS 编写的一种方法,它遍历所有子视图,直到没有更多可探索的地方。我认为相同或类似的方法适用于 NSView。希望这会有所帮助。

        (编辑:现在……如果我再往下看一点我的搜索结果,我会首先发现这个非常简单的方法: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;
        
        }
        

        来自示例视图的记录结果:

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

        【讨论】:

          【解决方案7】:

          这是 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
          

          我使用视图层次结构创建了一个快速 nib 文件,它打印了以下内容:

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

          我应该补充的一个问题是,除了作为调试工具之外,我不清楚这将如何有用。但即便如此,也可能有更简单的做事方式。

          【讨论】:

          • 也适用于 iOS:NS -> UI。
          • 不适用于 ARC:*** -[NSMutableArray addObjectsFromArray:]:数组参数不是 NSArray
          • “更简单的做事方式”是简单地将您的视图添加到 NSMutableArray,并让 NSMutableArray 在更大范围内可访问。这样做也更有效率。
          猜你喜欢
          • 2014-12-16
          • 2011-12-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多