Redrawing NSCollectionView on Scroll Causes Breakup of Graphics
I have a minor irritant in an NSCollectionView
in which the NSCollectionViewItem
's break up visually when I scroll the window.
The rate of breakup depends upon the rate of scrol开发者_StackOverflow社区ling. For example, if I scroll slowly the breakup occurs more often. Fast scrolling less so. It appears that the problem is when the custom NSView of the NSCollectionViewItem
I am using crosses the boundary of the viewable frame.
My NSView (custom view of the NSCollectionViewItem
) has a very simple drawing algorithm - nothing too complex.
Essentially I create a frame within the dirtyRect of the drawRect method and create a few frames inside that:
-(void)drawRect:(NSRect)dirtyRect
{
NSRect mOuterFrame = NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, 104, 94);
NSRect mSelectedFrame = NSInsetRect(mOuterFrame, 2, 2);
NSRect mRedFrame = NSInsetRect(mSelectedFrame, 2, 2);
NSRect mInnerFrame = NSInsetRect(mRedFrame, 2, 2);
NSBezierPath * mOuterFramePath = [NSBezierPath bezierPathWithRect:mOuterFrame];
NSBezierPath * mSelectedFramePath = [NSBezierPath bezierPathWithRect:mSelectedFrame];
NSBezierPath * mRedFramePath = [NSBezierPath bezierPathWithRect:mRedFrame];
NSBezierPath * mInnerFramePath = [NSBezierPath bezierPathWithRect:mInnerFrame];
[mainBackgroundColor set];
[mOuterFramePath fill];
if (selected)
[[NSColor yellowColor] set];
else
[mainBackgroundColor set];
[mSelectedFramePath fill];
if (isRedBorder)
[[NSColor redColor] set];
else
[mainBackgroundColor set];
[mRedFramePath fill];
[[NSColor blackColor] set];
[mInnerFramePath fill];
}
I have tried locking the focus and releasing before and after the code as well as setting the graphics context and restoring it - none of which seem to solve the problem.
I am using Snow Leopard - not that I think that makes a difference.
Solution Update
For anyone interested here is the solution to the problem as recommended by NSResponder. I was creating the initial mOuterFrame
based upon the drawRect:
methods dirtyRect
which, as pointed out, was the incorrect thing to do. A quick change from:
NSRect mOuterFrame = NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, 104, 94);
To a 0 based origination point:
NSRect mOuterFrame = NSMakeRect(0, 0, 104, 94);
I also tweaked the efficiency of the code, being as I am using only rectangles, as suggested although the code change above was enough to resolve the problem in itself. I had to add a change to get a two pixel line. New method:
-(void)drawRect:(NSRect)dirtyRect
{
NSRect mOuterFrame = NSMakeRect(0, 0, 104, 94);
NSRect mSelectedFrame = NSInsetRect(mOuterFrame, 2, 2);
NSRect mRedFrame = NSInsetRect(mSelectedFrame, 2, 2);
NSRect mInnerFrame = NSInsetRect(mRedFrame, 2, 2);
[NSBezierPath setDefaultLineWidth:2.0];
[mainBackgroundColor set];
[NSBezierPath strokeRect:mOuterFrame];
if (selected)
[[NSColor yellowColor] set];
else
[mainBackgroundColor set];
[NSBezierPath strokeRect:mSelectedFrame];
if (isRedBorder)
[[NSColor redColor] set];
else
[mainBackgroundColor set];
[NSBezierPath strokeRect:mRedFrame];
[[NSColor blackColor] set];
[NSBezierPath strokeRect:mInnerFrame];
}
First thing I noticed is that your code above is rather wasteful, since you're creating a bunch of paths when you could just be using NSFrameRect() and NSRectFill() instead.
Secondly, the geometry of what you draw shouldn't be dependent on the rectangle passed to -drawRect:. That rectangle just tells you what the area to update is, so you can be more efficient in deciding what to draw if your view is complex.
精彩评论