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.
Related
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'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.
I'm creating a NSColor using colorWithPatternImage as it shown in Apple example:
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
backgrColor = [[NSColor colorWithPatternImage:[NSImage imageNamed:#"greenfelt"]] retain];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
[backgrColor set];
NSRectFill(dirtyRect);
}
The image is taken from the same example and it works there. When I try it in my application, the view is colored in black. Why can it be?
Thanks
It's probably not finding the image, most likely because you're not using an extension on the filename.
Update: A quick test confirms that omitting the extension should still work. But it still may not be finding the image. Maybe it wasn't added to the project or you mistyped the name? Also, I assume that this view is actually being created using -initWithFrame:, right?
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()
}
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];
}
}