Objective-C Drawing without drawRect: shapes won't display - objective-c

I have a class called mapWindow which is hooked up to a window in IB.
No matter what, the red circle which I want the program to render won't show up unless the code is under drawRect or I move the window borders. Not even unlocking and locking the focus updates the window.
theOtherWindowView is actually a NSView hooked up to a custom view in IB.
- (void)test
{
[theOtherWindowView lockFocus];
NSBezierPath *path = [NSBezierPath bezierPath];
NSPoint center = [self drawPoint];
[path moveToPoint: center];
[path appendBezierPathWithArcWithCenter:center
radius:explosionRadius
startAngle:0
endAngle:360];
[[NSColor redColor] set];
[path fill];
[theOtherWindowView unlockFocus];
}
I don't want to use drawRect because I want multiple instances not one shape that has it's coordinates changed every update.
I've also tried [self lockFocus] and [mapWindow lockFous]

Keep doing your drawing in -drawRect:. When -drawRect: is sent, your view's coordinate system and clipping boundaries will have been set up for you, and your window's drawing context will be the current one.
In that method, draw as many of these circles as you want.

Related

Set the border of a subclassed NSTableCellView

As mentioned in the title of this post I want to set the border (color and width) of a subclassed NSTableCellView which is used inside a view-based NSTableView. I tried the following
self.layer.borderColor = [[NSColor greenColor] CGColor];
self.layer.borderWidth = 3.0;
I placed the code in initWithCoder and awakeFromNib without the desired result. Changing the backgroundColor is possible within the drawRect-Method. Can someone point me to the right direction?
Thanks
EDIT
Here is my solution using NSFrameRect
- (void)drawRect:(NSRect)dirtyRect
{
[NSGraphicsContext saveGraphicsState];
[[NSColor lightGrayColor]set];
NSFrameRect([self bounds]);
[NSGraphicsContext restoreGraphicsState];
}
Views on OS X are not layer backed by default. You first need to setWantsLayer: YES
But if you are using drawRect: you can just use NSFrameRect() or one of the similar functions or draw with an NSBezierPath in you cell view subclass. However, keep in mind that usually the row view does background drawing in view based tables.
Sounds like you have a bit of learning yet to do about drawing in Cocoa.

Subviews of NSRect not affected by NSAffineTransform

When applying an NSAffineTransform rotate and translate to an NSRect, none of the sub views are affected by the transform. I've included the code below.
- (void)drawRect:(NSRect)dirtyRect
{
NSAffineTransform * transform = [NSAffineTransform transform];
[transform translateXBy:13.0 yBy:3.0];
[transform rotateByDegrees:-45];
[transform translateXBy:-13.0 yBy:3.0];
[transform concat];
NSImageView *imageViewWatchPointer;
NSRect watchPointer = NSMakeRect(0, 0, 134, 49);
imageViewWatchPointer = [[NSImageView alloc] initWithFrame:watchPointer];
[imageViewWatchPointer setImageScaling:NSScaleNone];
[imageViewWatchPointer setImage:[NSImage imageNamed:#"mastery_watch_pointer"]];
[self addSubview:imageViewWatchPointer];
[[NSColor blueColor] set];
NSRectFill(watchPointer);
}
You're not applying transform to anything. You're creating it and then throwing it away. In any case, you never add subviews in drawRect:. drawRect: is for custom-drawing the current view, not for managing the view hierarchy. The way you've done this, you're adding a new NSImageView every time the main view is redrawn.
I recommend going back to the Cocoa Drawing Guide to understand how Cocoa drawing works.
Looking at your code, I don't believe you need drawRect: at all. You just want to add a subview, probably in awakeFromNib or initWithFrame:. I assume you want the view rotated. The easiest way to do that is to give it a backing layer (setWantsLayer:), and then set the affineTransform on the layer.
Alternately, in drawRect:, you could rotate the context and just draw the image itself (without using an NSImageView). See the Cocoa Drawing Guide for details on how to do custom drawing.

Issue with setPatternPhase: in an NSSplitView for NSColor using colorWithPatternImage:

I have searched around and haven't found anything regarding this particular problem. I have a window with a vertical NSSplitView. Within the right view of the splitview, I have an NSBox object set to fill the contents of the view. I am loading in custom nibs using setContentView: to swap in views to the NSBox on the righthand side of the splitview. In my custom views I'm tying to fill the views with an NSColor object that uses a NSImage to pattern the background. All of this is working as expected. I am using the code based on this article: http://www.mere-mortal-software.com/blog/details.php?d=2007-01-08 to set the phase of the pattern to the top-left corner:
[[NSGraphicsContext currentContext] saveGraphicsState];
[[NSGraphicsContext currentContext] setPatternPhase: NSMakePoint( [self bounds].origin.x,
[self bounds].size.height )];
[[self leatherColor] set];
NSRectFill( [self bounds] );
[[NSGraphicsContext currentContext] restoreGraphicsState];
with the intention that the pattern appears to remain constant in the upper lefthand corner of the NSBox when the views are re-sized as would be the expected behavior (via the splitview moving or the window itself being resized). I have implemented this in a stripped-down test app with just a window and a custom view and it behaves as expected.
In my project with the splitview however, it is behaving like the patternPhase is being set on the upper lefthand corner of the entire window instead of the upper lefthand corner of the right-half of the splitview (i.e. it should shift with resizing the splitview) It behaves like it's "revealing a larger image instead of shifting with it. I'm pretty certain this is an issue with multiple coordinate spaces, me misunderstanding how the coordinates of an NSSplitView work, or something to do with the view hierarchy. From the documentation on NSGraphicsContext, in the setPatternPhase: method it says: "For example, setting the pattern phase to (2,3) has the effect of moving the start of pattern cell tiling to the point (2,3) in default user space." Will the default user space correspond with the bounds of my custom view, or could it be that I am creating the point based on the right side view set of coordinates and the setPatternPhase implements it for the full width of the spitview (including the left-half)?
Any suggestions/advice/help you could provide would be greatly appreciated.
Edit: I have uploaded a copy of the project so you can see the behavior: http://dl.dropbox.com/u/6679821/ViewSwitcher.zip
You need to adjust the phase depending on where the view sits in the window. I use this category on NSView:
#implementation NSView (RKAdditions)
- (void)rk_drawPatternImage:(NSColor*)patternColor inRect:(NSRect)rect
{
[self rk_drawPatternImage:patternColor inBezierPath:[NSBezierPath bezierPathWithRect:rect]];
}
- (void)rk_drawPatternImage:(NSColor*)patternColor inBezierPath:(NSBezierPath*)path
{
[NSGraphicsContext saveGraphicsState];
CGFloat yOffset = NSMaxY([self convertRect:self.bounds toView:nil]);
CGFloat xOffset = NSMinX([self convertRect:self.bounds toView:nil]);
[[NSGraphicsContext currentContext] setPatternPhase:NSMakePoint(xOffset, yOffset)];
[patternColor set];
[path fill];
[NSGraphicsContext restoreGraphicsState];
}
#end
In your case you'd modify -drawRect: to look like this:
-(void) drawRect: (NSRect)dirtyRect
{
[self rk_drawPatternImage:[self leatherColor] inRect:self.bounds];
}

Cocoa drawing glitches when window loses then regains main status

Various things, including (perhaps most notably) the window losing its main status and then being brought back into focus, cause some of my custom views to develop rendering glitches until I do something (such as resize the window) to cause these custom views to redraw. I assume this is due to some sort of caching bug in AppKit, and I'm sure I'm not the only one getting this behaviour, so does anyone know how to work around it?
Here's an example:
Notice the weird dark line at the left of the view's background? This is drawn even without the subviews in the view. I get other similar bugs in some of my other views.
Here's the code that does the drawing:
void EDDrawGlossEffectInRect(NSRect dirtyRect) {
NSRect topRect, bottomRect;
NSDivideRect(dirtyRect, &topRect, &bottomRect, (dirtyRect.size.height / 2), NSMaxYEdge);
[EDLightChromeColor set];
NSRectFill(topRect);
[EDMidChromeColor set];
NSRectFill(bottomRect);
}
and
-(void)drawRect:(NSRect)dirtyRect {
EDDrawGlossEffectInRect(dirtyRect);
NSBezierPath *path = [NSBezierPath bezierPath];
[path setLineWidth:1.0];
NSPoint startPoint = {0, dirtyRect.size.height};
NSPoint endPoint = {dirtyRect.size.width, dirtyRect.size.height};
[path moveToPoint:startPoint];
[path lineToPoint:endPoint];
[[NSColor colorWithCalibratedWhite:0.7 alpha:1] set];
[path stroke];
}
The view is created programatically, not with Interface Builder, which I'm not using for this project.
dirtyRect will not necessarily cover your view's visible rect, so you might want to see which part of your view's bounds intersect with the dirtyRect and just repaint that. Otherwise, just repaint the bounds of the view. Resizing the window can cause the entire bounds to be dirty (usually), which is probably why you're seeing full repaints at that point.

Custom NSScrollers having weird effect from Core Animation

I am making custom NSScrollers for use in NSScrollView. But when any of the superviews of the NSScroller gets Core Animation enabled. I get this drawing issue that's a huge nuisance. Whenever i scroll into the corners of the scroll view the scrollers clip. But if a scroller starts out drawing in the corner, the scroller part stays in that corner. What could be causing this problem? I have too much code to show on here. But here is my drawing code:
NSRect knobRect = [self rectForPart:NSScrollerKnob];
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:knobRect
xRadius:CornerRadius
yRadius:CornerRadius];
[path setLineWidth:2];
[[NSColor colorWithDeviceRed:0.114 green:0.114 blue:0.114 alpha:0.3] set];
[path fill];
[[NSColor colorWithDeviceWhite:1.0
alpha:0.100] set];
// Clip drawing to this path; draw nothing outwith the path.
[path addClip];
[path stroke];
I already tried to get rid of everything except the fill but it didnt work. This issue goes away if I call setNeedsDisplay:YES on the super view when setFloatValue is called.
Clipping Issue http://idkz.org/b814ee5c875c9f44cc2d1345e4489420
it seems that the answer to the problem seems to be to call:
[self setArrowsPosition:NSScrollerArrowsNone];
And it magically works :D
Edit, but I get a similar effect when I drag the scrollbar. :'( Is there anyway to clear the graphics without redrawing the scrollview itself? :(
You probably found this out by know, but in your case, the following piece should solve your drawing issue:
-(BOOL)isOpaque {
return NO;
}