Draw image background in NSView under transparent elements - objective-c

I want to draw image background in NSView and place some elements which also have transparent background on top of it.
I've overrided draw rect of NSView:
- (void)drawRect:(NSRect)rect
{
[NSGraphicsContext saveGraphicsState];
NSImage *image = [NSImage imageNamed:#"header_background.gif"];
[image drawInRect:CGRectMake(0, rect.size.height - 75, rect.size.width, 75) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
}
NSWindow init:
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag];
if (self) {
[self setOpaque:NO];
[self setHasShadow:YES];
[self setBackgroundColor:[NSColor clearColor]];
}
return self;
}
After that a've got such weird effect. Backgrounds of Sliders and buttons are also blinking sometimes
What am I doing wrong?

Well, first off, your “color” is ignored when drawing images, so that’s not doing anything. Second, the code I see here probably isn’t causing the problem, can you post the rest of the file?
Right now I’m suspecting maybe you have marked this view as being opaque, when it’s not, or that you have something else odd in your view hierarchy.

Related

Use color with alpha fill NSView?

I write a window and two views,
set background color of window to blue,
and draw a image in view1,
and fill view2 with a color with alpha,like this:
//AppDelegate
[self.window setLevel:(NSStatusWindowLevel + 2)];
TestView *view1 = [[TestView alloc] initWithFrame:NSMakeRect(0, 0, self.window.frame.size.width, self.window.frame.size.height)];
TestView2 *view2 = [[TestView2 alloc] initWithFrame:NSMakeRect(0, 0, self.window.frame.size.width, self.window.frame.size.height)];
[self.window setContentView:view1];
[self.window.contentView addSubview:view2];
//View1
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
NSImage *image = [NSImage imageNamed:#"testImage"];
[image drawInRect:dirtyRect];
}
//view2
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
NSRectFill(dirtyRect);
}
But when the app run, I found I the backgroundcolor of window and image of View1 did not show, only the view2 show, and it is transparent,through it can see the desktop.
If I did not add subview view2, the app runs correctly, the blue background color and the image.
Does anybody know why, really thanks for the help, I will wait on line.
I change the NSRectFill to
NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
Then it turns right.

NSView draw permanently to background

I'm trying to draw some things on the background of my windows. Therefore I subclassed the NSView of the window and added some drawing code like this:
- (void)drawRect:(NSRect)dirtyRect {
float color = 0.95;
[[NSColor colorWithDeviceRed:color green:color blue:color alpha:1.0] set];
NSRectFill(NSMakeRect(320, 0, 220, NSHeight(dirtyRect)-60));
}
This works great, but as soon as I open a NSComboBox or if I activate a checkbox, the background of these elements erases my just drawn rect.
I don't understand this, because checking for example the checkbox causes, that drawRect is called (I added a NSLog). Only resizing the window draws my rect again.
EDIT:
here is a screenshot of the problem:
I sometimes face the same problem. I think the following is what I use.
/// .h
#interface BackgroundView1 : NSView {
NSImage *myImage;
}
// .m
- (void)awakeFromNib {
[self setupBackgroundImage];
}
- (void)setupBackgroundImage {
NSColor *c = [NSColor colorWithDeviceRed:0.0f/255.0f green:55.0f/255.0f blue:150.0f/255.0f alpha:1.0f];
if (myImage == nil)
myImage = [self createColorImage:NSMakeSize(1,1):c];
}
- (void)drawRect:(NSRect)rect {
[myImage drawInRect:NSMakeRect([self bounds].origin.x,[self bounds].origin.y,[self frame].size.width,[self frame].size.height)
fromRect:NSMakeRect(0,0,[myImage size].width, [myImage size].height)
operation:NSCompositeCopy
fraction:1.0];
}
// Start Functions //
- (NSImage *)createColorImage:(NSSize)size :(NSColor *)color {
NSImage *image = [[NSImage alloc] initWithSize:size];
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:size.width
pixelsHigh:size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:0
bitsPerPixel:0];
[image addRepresentation:rep];
[image lockFocus]; // Lock focus of image, making it a destination for drawing
[color set];
NSRectFill(NSMakeRect(0,0,size.width,size.height));
[image unlockFocus];
return image;
}
// End Functions //

Objective-C tiled background image in NSview

I have 2 NSViews arranged side by side that have backgrounds made from tiled images.
When I add constraints to the views so that they resize with the main window the tiled background image no longer displays and the background is just black.
What am I missing here?
#import "imageWellGraphics.h"
#implementation imageWellGraphics
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGAffineTransform affineTransform = CGContextGetCTM(context);
NSImage* image = [NSImage imageNamed: #"tile.png"];
NSColor* imagePattern = [NSColor colorWithPatternImage: image];
NSRect frame = NSInsetRect(self.bounds, 1, 1);
NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRect:NSMakeRect(NSMinX(frame), NSMinY(frame), NSWidth(frame), NSHeight(frame))];
[NSGraphicsContext saveGraphicsState];
CGContextSetPatternPhase(context, NSMakeSize(affineTransform.tx, affineTransform.ty));
[imagePattern setFill];
[rectanglePath fill];
[NSGraphicsContext restoreGraphicsState];
}
#end
Include this line inside drawrect method and check:-
[super drawRect:dirtyRect];
Well, it turns out the problem was me not properly understanding/using Images.xcassets for my background image.

Cache NSView Context

I'm trying to store NSView Current Context and draw it later to NSView again. I was wondering what is the fastest and most efficient way to do this?
You can draw your content to an NSImage and just redraw the image later, but you need to invalidate the cache when needed (this depends on what your view does).
Example:
#interface SOCacheView : NSView
#end
#implementation SOCacheView
{
NSImage *_cache;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
if (!_cache) [self prepareImage];
[_cache drawAtPoint:NSZeroPoint fromRect:self.bounds operation:NSCompositeSourceOver fraction:1.0];
}
- (void)prepareImage
{
_cache = [[NSImage alloc] initWithSize:self.bounds.size];
[_cache lockFocus];
// do the drawing here...
[[NSColor blueColor] setFill];
NSRectFill(NSMakeRect(0, 0, NSWidth(self.bounds)/2, NSHeight(self.bounds)));
[[NSColor redColor] setFill];
NSRectFill(NSMakeRect(NSWidth(self.bounds)/2, 0, NSWidth(self.bounds)/2, NSHeight(self.bounds)));
[_cache unlockFocus];
}
To invalidate the cached drawing, just set _cache to nil.
Here's a sample project for you to play with 😉

addSubview in Cocoa framework

I have a regular DocumentView class in a Window. I have the following code once a user presses a button:
- (void)handleButtonPress:(NSNotification *)note{
// draw new graph view
EDGraphView *graph = [[EDGraphView alloc] init];
[self addSubview:graph];
[self setNeedsDisplay:TRUE];
NSLog(#"Button was pressed");
}
This gets called correctly because I get the output "Button was pressed" every time I click on the button. In addition to that the drawRect method below of the view gets called as well.
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds = [self bounds];
[[NSColor whiteColor] set];
[NSBezierPath fillRect:bounds];
for(EDGraphView *graph in [self subviews]){
[graph setNeedsDisplay:TRUE];
NSLog("calling set needs display on graph object!");
}
}
However when I go in the EDGraphView class and edit the drawRect method to look like the following
- (void)drawRect:(NSRect)dirtyRect
{
NSLog(#"redrawing graph view.");
}
It never gets called! I must be missing something about the whole setNeedsDisplay and drawRect process.
Any suggestions?
hi Normaly you don't call setneeddisplay into a drawrect.
have you tried (with the super)? :
- (void)drawRect:(NSRect)dirtyRect
{
NSRect bounds = [self bounds];
[[NSColor whiteColor] set];
[NSBezierPath fillRect:bounds];
[super drawRect:rect];
}
Got it...I needed to make the following init call on my subview:
EDGraphView *graph = [[EDGraphView alloc] initWithFrame:bounds];
Now it calls the drawRect method!