I am creating an app where I need to have a transparent NSView with a transparent PNG image inside. The problem is, the NSView I'm drawing has a gray background on it. I have it subclassed (as TransparentRectangleView) but don't know what to put in drawRect to make it transparent.
I have already overridden the isOpaque method to return NO but it doesn't seem to help...
Alternatively, is there already a subclassed NSView that is similar to the iPhone's UIImageView (as long as I can add subviews inside, I need to add some text inside).
To make a view transparent, simply fill it with [NSColor clearColor].
- (void)drawRect:(NSRect)rect {
[[NSColor clearColor] set];
NSRectFill(rect);
}
The default implementation of isOpaque returns NO, so if you are subclassing NSView and not some other view you don't need to worry about overriding it.
The accepted answer does not work for me since mine window is opaque. As http://www.drissman.com/blog/archives/2009/10/09/nsrectfill_and_nscolor_clearcolor.html (and the discussion below) said, the following codes work:
- (void)drawRect:(NSRect)rect {
[[NSColor clearColor] set];
NSRectFillUsingOperation(rect, NSCompositeSourceOver);
// do other drawings
}
The Swift version:
override func draw(_ dirtyRect: NSRect) {
NSColor.clear.set()
dirtyRect.fill()
}
Related
I have an NSPopMenuButton which is connected to an NSMenu in the standard way. I tried sub-classing both in an attempt to change the background color of the menu itself. I'm clearly not doing something correctly, so any advice would be helpful.
Tried (NSPopUpButton) customPopUpButton.m:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
[[NSColor grayColor] set];
NSRectFill(dirtyRect);
}
Which gave me:
I'd actually rather it be like:
I tried creating another class to override NSPopUpButtonCell as suggested by another answer, but I must not know how to implement it correctly as it seems to have no effect other than what the code above does.
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
[[NSColor grayColor] set];
NSRectFill(cellFrame);
[super drawInteriorWithFrame:cellFrame inView:controlView];
}
Something to note is that my deployment target is macOS 10.11 if that makes any difference.
Your customized NSPopUpButton drawing is filling the entire drawing area with color. Default title drawing is missing (under the filled color).
Try customizing NSPopUpButtonCell drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView.
Everywhere on the internet I can read that to change the background color of a NSView you can just override its method drawRect like this:
- (void)drawRect:(NSRect)rect
{
[[NSColor yellowColor] set];
NSRectFill(rect);
}
For example here.
However, in my case, the color is drawn on top of the view (I can't see anymore the content), which is quite logical to me. DrawRect is supposed to draw the view, not just its background.
what am I missing?
You should call [super drawRect:rect] after filling the background. Otherwise, you're simply replacing everything that would be drawn by the superclass's implementation.
The examples you refer to are displaying the subviews of the view above the background.
I am trying to tackle a problem which sounds pretty simple: changing the background color of an NSPopupButton.
Interface Builder only allows changing the style to a pre-defined one and doesn't allow changing the background color. Also, setting up an IBOutlet didn't help since NSPopupButton doesn't have a setBackgroundColor method.
I also tried subclassing NSPopupButton to override the drawRect method. Here's what I have tried:
- (void)drawRect:(NSRect)dirtyRect
{
[[NSColor redColor] setFill];
NSRectFill(dirtyRect);
}
This draws a red rectangle over the NSPopupButton rather than setting it as a background color.
Any ideas on how to go about solving this?
You should create a subclass of NSPopUpButtonCell, then override
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView
NSPopupButtonCell is a subclass of NSButtonCell which defines several methods for drawing individual cell components, eg bezel, title, image.
You can then expand the NSPopupButton and change its cell subclass to your new subclass and it should use your drawing methods.
Cocoa primarily uses NSCell to handle drawing, unlike iOS
Swift version of #DanBrooker's answer. The example shows setting a background color
class PopUpButtonCell: NSPopUpButtonCell {
override func drawBezel(withFrame frame: NSRect, in controlView: NSView) {
guard let context = NSGraphicsContext.current?.cgContext else { return }
NSColor.red.setFill() // NSColor.white.setFill()
context.fill(frame)
}
}
The button is draw by the system, so there isn't a real way to set the background color in a way that the system draws it like you want.The only thing that you can do is to draw it in the drawRect method, also drawing the title, and drawing a portion of the rectangle.
I'm trying to create a custom NSButton with a 50% opaque black background and white text. To do this I've subclassed NSButton and overloaded DrawRect:
- (void) drawRect:(NSRect)dirtyRect
{
[self setBordered:NO];
//REMED since it has same effect as NSRectFill below
//[[self cell] setBackgroundColor:[NSColor colorWithCalibratedRed:0 green:0 blue:0 alpha:0.2]];
NSColor* backgroundColor = [NSColor colorWithCalibratedWhite:0 alpha:0.3f];
[backgroundColor setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
}
The white text appears fine but the button's background is always 100% opaque. The alpha value is not interpreted.
Any ideas? Thanks!
The default operation of NSRectFill() is copy which is not what you want. Replace it with
NSRectFillUsingOperation(dirtyRect, NSCompositeSourceAtop);
Another solution I found was to keep my code the same but turn on the Core Animation Layer for each button in Interface Builder. I don't know enough about Core Animation Layer to know why this worked. I had previously turned CAL off because it was making my fonts look very jagged.
Is there a way to "highlight" a NSImageView with the default highlight color of the mac? I'm simply looking for a way to tint my nsimageview so that the user can identify the object easily.
Thanks,
Kevin
If one of the built-in options of NSImageView isn't sufficient, you could subclass NSImageView, and in drawRect, do:
- (void)drawRect:(NSRect)frame {
[super drawRect:frame]; // this takes care of image
[NSBezierPath setDefaultLineWidth:4.0];
[[NSColor highlightColor] set];
[NSBezierPath strokeRect:frame]; // will give a 2 pixel wide border
}
Ahh, to have it as a variable state, I'd probably define an instance variable then, such as isHighlighted to keep track of that state. Then, whenever anything happens that would change the highlighted state, you'll set the view as needing redisplay. You could do this in the set/get methods for instance:
- (void)setHighlighted:(BOOL)aHighlighted {
isHighlighted = aHighlighted;
[self setNeedsDisplay:YES];
}
Then, update your drawRect: method to take into account the isHighlighted flag. How you achieve an unhighlighted look may depend on the style of image view. You could try just calling super to do the drawing, but if in testing, you see any residual or stray highlighted pixel information that super's drawing didn't overwrite, you may want to first draw clear color, then call super.
So, something like this:
- (void)drawRect:(NSRect)frame {
isHighlighted ? [[NSColor highlightColor] set] : [[NSColor clearColor] set];
[NSBezierPath setDefaultLineWidth:4.0];
if (isHighlighted) {
[super drawRect:frame];
[NSBezierPath strokeRect:frame]; // will give a 2 pixel wide border
} else {
[NSBezierPath fillRect:frame];
[super drawRect:frame];
}
}