【问题标题】:Making a Grid in an NSView在 NSView 中制作网格
【发布时间】:2016-01-08 02:56:47
【问题描述】:

我目前有一个NSView 绘制网格图案(本质上是水平和垂直线的指南),其想法是用户可以更改网格的间距和网格的颜色。

网格的目的是在排列对象时充当用户的指南。除了一个例外,一切都很好。当我通过拖动调整大小手柄来调整NSWindow 的大小时,如果我的网格间距特别小(比如 10 像素)。拖动调整大小本质上变得昏昏欲睡。

我的drawRect网格代码如下:

-(void)drawRect:(NSRect)dirtyRect {

    NSRect thisViewSize = [self bounds];

    // Set the line color

    [[NSColor colorWithDeviceRed:0 
                           green:(255/255.0) 
                            blue:(255/255.0) 
                           alpha:1] set];

    // Draw the vertical lines first

    NSBezierPath * verticalLinePath = [NSBezierPath bezierPath];

    int gridWidth = thisViewSize.size.width;
    int gridHeight = thisViewSize.size.height;

    int i;

    while (i < gridWidth)
    {
        i = i + [self currentSpacing];

        NSPoint startPoint = {i,0};
        NSPoint endPoint = {i, gridHeight};

        [verticalLinePath setLineWidth:1];
        [verticalLinePath moveToPoint:startPoint];
        [verticalLinePath lineToPoint:endPoint];
        [verticalLinePath stroke];
    }

    // Draw the horizontal lines

    NSBezierPath * horizontalLinePath = [NSBezierPath bezierPath];

    i = 0;

    while (i < gridHeight)
    {
        i = i + [self currentSpacing];

        NSPoint startPoint = {0,i};
        NSPoint endPoint = {gridWidth, i};

        [horizontalLinePath setLineWidth:1];
        [horizontalLinePath moveToPoint:startPoint];
        [horizontalLinePath lineToPoint:endPoint];

        [horizontalLinePath stroke];
    }
}

我怀疑这完全与我绘制网格的方式有关,并且我愿意接受有关如何更好地处理它的建议。

我可以看到效率低下的地方,拖动调整大小 NSWindow 在调整大小时不断调用此视图中的 drawRect,并且网格越接近,父窗口每像素拖动的计算越多.

我想在调整窗口大小时隐藏视图,但感觉不那么动态。我希望用户体验非常流畅,没有任何明显的延迟或闪烁。

有人对绘制网格的更好或更有效的方法有任何想法吗?

一如既往,非常感谢所有帮助。

【问题讨论】:

    标签: objective-c cocoa grid nsview drawrect


    【解决方案1】:

    您无意中在算法中引入了Schlemiel。每次在循环中调用 moveToPointlineToPoint 时,实际上都是在同一路径中添加更多行,all 每次在该路径上调用 stroke 时都会绘制这些行。

    这意味着你第一次画一条线,第二次画两条线,第三次画三条线,等等......

    一个快速的解决方法是每次循环都使用一条新路径只需在循环之后执行stroke (感谢 Jason Coco 的想法):

    path = [NSBezierPath path];
    while (...)
    {
        ...
    
        [path setLineWidth:1];
        [path moveToPoint:startPoint];  
        [path lineToPoint:endPoint];
    }
    [path stroke];
    

    更新: 另一种方法是完全避免创建 NSBezierPath,而只使用 strokeLineFromPoint:toPoint: 类方法:

    [NSBezierPath setDefaultLineWidth:1];
    while (...)
    {
        ...
        [NSBezierPath strokeLineFromPoint:startPoint toPoint:endPoint];
    }
    

    更新 #2:到目前为止,我对这些方法进行了一些基本的基准测试。我正在使用大小为 800x600 像素的窗口,网格间距为 10 像素,并且我让 cocoa 重绘窗口一千次,从 800x600 缩放到 900x700 并再次缩放。在我的 2GHz Core Duo Intel MacBook 上运行,我看到以下时间:

    Original method posted in question:  206.53 seconds  
    Calling stroke after the loops:       16.68 seconds  
    New path each time through the loop:  16.68 seconds  
    Using strokeLineFromPoint:toPoint:    16.68 seconds  
    

    这意味着减速完全是由重复引起的,并且任何几个微观改进中的任何一个都无法真正加快速度。这应该不足为奇,因为在屏幕上实际绘制像素(几乎总是)比简单的循环和数学运算占用更多的处理器资源。

    经验教训:

    1. 隐藏的 Schlemiels 可以真的减慢速度。
    2. 始终配置您的代码before doing unnecessary optimization

    【讨论】:

    • 既然是描边路径而不是真正生成效率低下的路径,为什么不直接保留代码,而是将描边移到循环外?
    • @Jason Coco:这是个好主意。我很好奇这两种方法中哪一种在改变之后更快。
    • 我会同时尝试并让您知道...谢谢!请继续关注更新
    • @e.James - 看起来路径中风是罪魁祸首。您的替代解决方案(使用strokeLineFromPoint:toPoint:)比将路径笔划移动到循环外稍微慢一点,但只是稍微慢一点。对于我正在使用的规模,它非常有效。感谢您和@Jason Coco 的帮助。
    • 不客气。顺便说一句,好问题。我运行了一些基准测试,只是为了看看结果如何。在我的答案中查看结果。干杯!
    【解决方案2】:

    您应该运行 Instruments Cpu Sampler 以确定大部分时间花在哪里,然后根据该信息进行优化。如果是中风,请将其放在循环之外。如果它正在绘制路径,请尝试将渲染卸载到 gpu。看看 CALayer 能不能帮上忙。

    【讨论】:

      【解决方案3】:

      聚会可能会迟到,但有人会觉得这很有帮助。最近,我需要一个客户的自定义组件,以便重新创建一个网格可调整大小的覆盖 UIView。以下内容应该适用于工作,即使尺寸很小也不会出现问题。

      代码是针对iPhone(UIView)的,但是可以很快的移植到NSView上。

      - (void)drawRect:(CGRect)rect {
          CGContextRef context = UIGraphicsGetCurrentContext();
          CGContextClearRect(context, rect);
          CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
      
          //corners
          CGContextSetLineWidth(context, 5.0);
          CGContextMoveToPoint(context, 0, 0);
          CGContextAddLineToPoint(context, 15, 0);
          CGContextMoveToPoint(context, 0, 0);
          CGContextAddLineToPoint(context, 0, 15);
          CGContextMoveToPoint(context, rect.size.width, 0);
          CGContextAddLineToPoint(context, rect.size.width-15, 0);
          CGContextMoveToPoint(context, rect.size.width, 0);
          CGContextAddLineToPoint(context, rect.size.width, 15);
          CGContextMoveToPoint(context, 0, rect.size.height);
          CGContextAddLineToPoint(context, 15, rect.size.height);
          CGContextMoveToPoint(context, 0, rect.size.height);
          CGContextAddLineToPoint(context, 0, rect.size.height-15);
          CGContextMoveToPoint(context, rect.size.width, rect.size.height);
          CGContextAddLineToPoint(context, rect.size.width-15, rect.size.height);
          CGContextMoveToPoint(context, rect.size.width, rect.size.height);
          CGContextAddLineToPoint(context, rect.size.width, rect.size.height-15);
          CGContextStrokePath(context);
      
      
          //border
          CGFloat correctRatio = 2.0;
          CGContextSetLineWidth(context, correctRatio);
          CGContextAddRect(context, rect);
          CGContextStrokePath(context);
      
          //grid
          CGContextSetLineWidth(context, 0.5);
          for (int i=0; i<4; i++) {
              //vertical
              CGPoint aPoint = CGPointMake(i*(rect.size.width/4), 0.0);
              CGContextMoveToPoint(context, aPoint.x, aPoint.y);
              CGContextAddLineToPoint(context,aPoint.x, rect.size.height);
              CGContextStrokePath(context);
      
              //horizontal
              aPoint = CGPointMake(0.0, i*(rect.size.height/4));
              CGContextMoveToPoint(context, aPoint.x, aPoint.y);
              CGContextAddLineToPoint(context,rect.size.width, aPoint.y);
              CGContextStrokePath(context);
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多