Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Senor Cuete

macrumors 6502
Original poster
Nov 9, 2011
432
32
My Cocoa multiple document application draws some NSImages into NSView sub-classes. These are drawn to fill the frame / rect. I decided to draw these shadowed. Rather than change the frames of the view sub-classes in my .xib files and rewrite the code in their drawRect:methods, I decided to make their frames larger programmatically, draw the images transformed in the amount needed for the shadowing and restore the frames, etc. At the start of my drawRect method I save the frame and graphics context. After drawing the NSImages I restore them. This works perfectly when drawing to a window but when printing or saving, the frames are far from where they should be, offset by some large x in origin. For example creating an NS PrintOperation using the superview like this:

Code:
NSPrintOperation *op = [NSPrintOperation printOperationWithView: superview];
creates a mess.

Here is a code example:

Code:
- (void) drawRect: (NSRect)rect
{
    drawingRect = rect;

    [NSGraphicsContext saveGraphicsState];
    NSRect savedFrame = [self frame];
    NSRect myFrame = [self frame];
    
    NSAffineTransform* xform = [NSAffineTransform transform];
    NSShadow* theShadow = [[[NSShadow alloc] init] autorelease];
    setDrawShadowed(&myFrame, self, xform, theShadow);
    //above function changes the frame and creates an NSAffineTransform so
    //the NSImage will be drawn where it belongs

    //Draw NSImage here
    
    [self setFrame: savedFrame];
    [NSGraphicsContext restoreGraphicsState];
    //or you could [xform invert]; to revert the transformation*/
}

Here is the function that creates the shadowing and the transform. This only works if drawing to the screen:

Code:
void setDrawShadowed(NSRect* frame, id classInstance, NSAffineTransform * xform, NSShadow *theShadow){
    frame->size.height += 4.0;
    frame->size.width += 4.0;
    frame->origin.y -= 3.0;
    [classInstance setFrame: *frame]; //set NSView frame to new frame
    //transform drawing coordinates in current context to draw correctly:
    [xform translateXBy: 0.0 yBy: 3.0];
    [xform concat];
    
    [theShadow setShadowOffset: NSMakeSize(3.0, -3.0)];
    [theShadow setShadowBlurRadius: 2.0];
    [theShadow setShadowColor: [[NSColor blackColor] colorWithAlphaComponent: 0.4]];
    [theShadow set];
}
 
Update

If you change a the frame of a subclass of an NSView in its drawRect method and then restore it, it will display correctly when you are drawing to the screen but not while printing or saving:

Code:
NSRect savedFrame = [self frame];
NSRect myFrame = [self frame];
myFrame.origin.x += 1;
[self setFrame: myFrame];
[self setFrame: savedFrame];

If you put these lines of code in your drawRect method it will draw correctly to the screen but when printing or saving, the frame of the NSView's subclass will be outside of the superclass's frame. For example if you print by overriding the superclass's

Code:
- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError

method, the method
Code:
NSPrintOperation *op = [NSPrintOperation printOperationWithView: superview printInfo: tempPrintInfo];

will generate an unusable NSPrintOperation; If changing the frame of an NSView subclass is not acceptable, why does Cocoa give you access to it?
 
Changing Frame is the Problem

If I alter my NSView subclass' frame using methods such as setFrame: or setFrameSize: programmatically, subsequent drawing to the screen will work but printing or saving won't. Either the NSImages won't appear or they will be in the wrong place. Yes I set the superview and my NSView subclass to need display and yes I reset the bounds and frame after drawing. Any Ideas?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.