我目前有一个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
,网格越近,每个像素阻力越大父窗口。
我正在考虑将视图隐藏在窗口的大小调整上,但它感觉不那么动态。我希望用户体验非常流畅,没有任何明显的延迟或闪烁。
有没有人对更好或更有效的绘制网格方法有任何想法?
所有的帮助,一如既往,非常感谢。
答案 0 :(得分:13)
您无意中在您的算法中引入了Schlemiel。每次在循环中调用moveToPoint
和lineToPoint
时,实际上是在同一路径中添加了更多行,每次调用{{1>时都会绘制所有在那条路上。
这意味着你第一次画一行,第二次画两行,第三次画三行等等......
快速解决方法是每次循环使用新路径只需在循环后执行stroke
(感谢Jason Coco这个想法):
stroke
更新: 另一种方法是避免完全创建path = [NSBezierPath path];
while (...)
{
...
[path setLineWidth:1];
[path moveToPoint:startPoint];
[path lineToPoint:endPoint];
}
[path stroke];
,只使用strokeLineFromPoint:toPoint:类方法:
NSBezierPath
更新#2: 到目前为止,我对这些方法做了一些基本的基准测试。我正在使用一个800x600像素的窗口,十个像素的网格间距,我有可可重绘窗口一千次,从800x600扩展到900x700并再次返回。在我的2GHz Core Duo Intel MacBook上运行,我看到以下几次:
[NSBezierPath setDefaultLineWidth:1];
while (...)
{
...
[NSBezierPath strokeLineFromPoint:startPoint toPoint:endPoint];
}
这意味着减速完全是由重复引起的,而且几项微观改进中的任何一项都没有做到实际加快速度。这不应该是一个惊喜,因为屏幕上像素的实际绘制(几乎总是)比简单的循环和数学运算更加处理器密集。
要吸取的教训:
答案 1 :(得分:0)
您应该运行Instruments Cpu Sampler来确定大部分时间花在哪里,然后根据该信息进行优化。如果是中风,将它放在循环外面。如果它正在绘制路径,请尝试将渲染卸载到gpu。看看CALayer是否可以提供帮助。
答案 2 :(得分:0)
也许这个派对迟到了,不过有人会觉得这很有帮助。最近,我需要为客户定制组件,以便重新创建网格可调整大小的叠加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);
}
}