Whenever I try to create a custom window using NSBorderlessWindowMask and set an NSView (for example an NSImageView) as its contentView, I get a 1px gray border around the NSView and I don't seem to be able to get rid of it.
I have followed several approaches including Apple's RoundTransparentWindow sample code as well as several suggestions on StackOverflow.
I suspect the gray border is either coming from the window itself or the NSView.
Have any of you experienced this problem or do you have a possible solution?
The code is fairly straightforward. This is the init method of the custom window:
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
if (self != nil) {
[self setAlphaValue:1.0];
[self setBackgroundColor:[NSColor clearColor]];
[self setOpaque:NO];
}
return self;
}
To test this, in IB I place an NSImageView in that custom window WITHOUT border and yet the image in the NSImageView has a border. The same goes for other NSView subclasses, such as NSTextField, NSTableView.
In addition, I also noticed that the same is happening with the sample application (RoundTransparentWindow) of Apple. Is it even possible to draw an NSView in a custom window without a 1px border?
Thanks
Are you sure this happens when you use a regular NSView with no drawing? I bet not. Other controls (like NSImageView)have borders. Maybe you should double check to make sure they're turned off whe possible.
Update - How do you get your view into your window? You don't include that code. I created a basic test project (download it here) with an image well and it works just fine. See for yourself.
Related
I'm experience the strangest thing. I'm working on a project that I started noticing this issue, so I created a sandboxed test to simplify the problem and see if I can figure it out.
I have document based application with a single window controller. inside that are these objects:
Subclassed NSScrollView with isFlipped=YES
Subclassed NSView with isFlipped=YES, this is the documentView in the above scrollview.
An NSImage in the document view
Then I try and fade the image to alpha 0 like this:
- (void)windowDidLoad {
[super windowDidLoad];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(test) userInfo:nil repeats:FALSE];
}
- (void) test {
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:4];
self.errorOutline.animator.alphaValue = 0;
[NSAnimationContext endGrouping];
}
This is how it looks in Xcode:
This is what happens when it starts animating:
I've noticed that if I resize the window continually while it's animating, I get a ghosting image like effect where I an see the rest of the image.
Another strange issue is that if I set isFlipped=NO, then the issue doesn't happen. Which is not an option - the whole reason I'm flipping the view is so it's easier to manage adding cells to it without calculating positions and heights backwards.
Update: I've filed a radar bug as this is a really strange issue. http://openradar.appspot.com/20680289
I have created a custom NSWindow using:
self = [super initWithContentRect:contentRect styleMask:8 backing:bufferingType defer:flag];
Which handles resizing fine. However, it doesn't change the cursor when i hover over the borders. I could do this myself but i cannot create a trackingRect which goes beyond the edges of the window.
Any ideas how i could manage this would be great.
Thanks,
Ben
I came across this, the fix for me was to subclass NSWindow and put this in the implementation:
- (BOOL)canBecomeKeyWindow
{
return YES;
}
NSWindow.styleMask indicating what kinds of control items it displays should include NSResizableWindowMask that tells to display a resize control.
[window setStyleMask:NSResizableWindowMask];
I have made a slick NSScroller subclass, but can't figure out how to make it overlay on top of the NSScrollView instead of pushing the documentView aside.
Here you can see the background of a NSCollectionView that I wish to make 100% wide, and have the scroller sit along top. Currently, I have to set a white background to the scroller because drawing with a clearColor is not showing as transparent, but as black.
Am I going about this the wrong way? Am I missing something obvious here? How can I achieve the behavior of a transparent-tracked NSScroller that sits atop a NSScrollView's contents?
I was able to get the positioning by implementing tile in the subclass OF NSSCROLLVIEW
- (void)tile {
[super tile];
[[self contentView] setFrame:[self bounds]];
}
And it turns out that trying to draw clear color was the problem to begin with. In the scroller subclass, I just omitted any drawing that had to do with the slider track completely BY OVERRIDING DRAWRECT: OF THE NSSCROLLER SUBCLASS, LIKE SO:
- (void)drawRect:(NSRect)dirtyRect
{
[self drawKnob];
}
Note that for this to work properly, you MUST enable layer-backing for the scrollView!
That is, call:
[scrollViewInstance setWantsLayer:YES];
or set it in Interface Builder.
If you don't do this, the scrollView's contentView will draw ON TOP OF the scrollers. Also: you should be aware that what you're doing is essentially overlapping two NSViews (NSScroller on top of NSScrollView --- both inherit from NSView.) Unlike UIViews on iOS, overlapping NSViews on OS X is not officially supported by any current version of the OS (10.6 down). Turning on CALayers seems to make it work, but it's still something to bear in mind. Of course, turning on layers can seriously kill drawing performance.
See this SO question for more detail: Is there a proper way to handle overlapping NSView siblings?
What's about this color: [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.0]
I think you have to modify the sizes with the interface builder.
I have a NSTextView with a sizeable quantity of text. Whenever I scroll however, the view isn't updated properly. There are some artifacts that remain at the top or the bottom of the view. It appears that the view doesn't refresh itself often enough. If I scroll very slowly the view updates correctly though. If I add a border to the view everything works perfectly, borderless view is the one that has a problem. Here's a link to a screenshot:
Thanks
Have you set the setDrawsBackground and copiesOnScroll propertes for either the NSScrollView or the NSClipView?
The first thing I would suggest is turning off the "draws background" property of the NSScrollView:
[myScrollView setDrawsBackground:NO];
Note that this should be set on the NSScrollView, and not on the embedded NSClipView.
The following excerpt from the documentation may be relevant:
If your NSScrollView encloses an NSClipView sending a setDrawsBackground: message with a parameter of NO to the NSScrollView has the added effect of sending the NSClipView a setCopiesOnScroll: message with a parameter of NO. The side effect of sending the setDrawsBackground: message directly to the NSClipView instead would be the appearance of “trails” (vestiges of previous drawing) in the document view as it is scrolled.
Looks like the text field isn't even in the scrolling-area... Are you sure something isnt overlapping it?
I had a similar trouble - artifacts develop when the NSTextView is embedded in another scrollview (ie. a NSTableView).
I actually turned on the setdrawsbackground, and then added a nice color to make it disappear again.
-(void)awakeFromNib{
NSScrollView *scroll = [self enclosingScrollView];
[scroll setBorderType:NSNoBorder];
[scroll setDrawsBackground:YES];
[scroll setBackgroundColor:[NSColor windowBackgroundColor]];
}
This in combination with a scrollWheel event let me use the NSTextView in a NSTableView.
-(void)scrollWheel:(NSEvent *)theEvent{
NSScrollView *scroll = [self enclosingScrollView];
[[scroll superview] scrollWheel:theEvent];
}
I had the same trouble some time ago. I don't remember how I solved it.
Try to place the NSTextView to another view if the superview is a custom view. Just to see what will happen.
The problem
I have a transparent NSView on a transparent NSWindow. The view's drawRect: method draws some content (NSImages, NSBezierPaths and NSStrings) on the view but leaves parts of it transparent.
Clicking on the regions of the view that have been drawn on invokes the usual mouse event handling methods (mouseDown: and mouseUp:).
Clicking on the transparent areas gives focus to whatever window is behind my transparent window.
I would like to make parts of the transparent region clickable so that accidentally clicking between the elements drawn on my view does not cause the window to lose focus.
Solutions already attempted
Overriding the NSView's hitTest: method. Found that hitTest: was only called when clicking on a non-transparent area of the view.
Overriding the NSView's opaqueAncestor method. Found that this was not called when clicking on any part of the view.
Filling portions of the transparent area with [NSColor clearColor] in the drawRect: method, and with an almost-but-not-quite-transparent colour. This had no effect.
Experimented with the NSTrackingArea class. This appears to only add support for mouseEntered:, mouseExited:, mouseMoved:, and cursorUpdate: methods, not mouseUp: and mouseDown:.
I had the same problem. It looks like [window setIgnoresMouseEvents:NO] will do it.
(On Lion, at least. See http://www.cocoabuilder.com/archive/cocoa/306910-lion-breaks-the-ability-to-click-through-transparent-window-areas-when-the-window-is-resizable.html)
As far as I know, click events to transparent portions of windows aren't delivered to your application at all, so none of the normal event-chain overrides (i.e -hitTest:, -sendEvent:, etc) will work. The only way I can think of off the top of my head is to use Quartz Event Taps to capture all mouse clicks and then figure out if they're over a transparent area of your window manually. That, frankly, sounds like a huge PITA for not much gain.
George : you mentioned that you tried filling portions with an almost but not quite transparent color. In my testing, it only seems to work if the alpha value is above 0.05, so you might have some luck with something like this:
[[NSColor colorWithCalibratedRed:0.01 green:0.01 blue:0.01 alpha:0.05] set];
It's an ugly kludge, but it might work well enough to avoid using an event tap.
Did you try overriding
- (NSView *)hitTest:(NSPoint)aPoint
in your NSView sublcass?
You can use an event monitor to catch events outside a window/view.
https://developer.apple.com/library/mac/documentation/cocoa/conceptual/eventoverview/MonitoringEvents/MonitoringEvents.html
You can override the hitTest method in your NSView so that it always returns itself.
According to the NSView documentation, the hitTest method will either return the NSView that the user has clicked on, or nil if the point is not inside the NSView. In this case, I would invoke [super hitTest:], and then return the current view only if the result would otherwise be nil (just in case your custom view contains subviews).
- (NSView *)hitTest:(NSPoint)aPoint
{
NSView * clickedView = [super hitTest:aPoint];
if (clickedView == nil)
{
clickedView = self;
}
return clickedView;
}
You can do:
NSView* windowContent = [window contentView];
[windowContent setWantsLayer:YES]
Making sure that the background is transparent:
[[windowContent layer] setBackgroundColor:[[NSColor clearColor] CGColor]];
Another option would be to add a transparent background image that fills the contentView.