Cocoa/OSX - NSWindow standardWindowButton behaving strangely once copied and added again

夙愿已清 提交于 2019-11-28 23:07:49

问题


In my app I change the position of the standardWindowButtons close / miniturize / expand like so:

 //Create the buttons
    NSButton *minitButton = [NSWindow standardWindowButton:NSWindowMiniaturizeButton forStyleMask:window.styleMask];
NSButton *closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:window.styleMask];
NSButton *fullScreenButton = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:window.styleMask];


//set their location
[closeButton setFrame:CGRectMake(7+70, window.frame.size.height - 22 - 52, closeButton.frame.size.width, closeButton.frame.size.height)];
[fullScreenButton setFrame:CGRectMake(47+70, window.frame.size.height - 22 -52, fullScreenButton.frame.size.width, fullScreenButton.frame.size.height)];
[minitButton setFrame:CGRectMake(27+70, window.frame.size.height - 22 - 52, minitButton.frame.size.width, minitButton.frame.size.height)];

//add them to the window
[window.contentView addSubview:closeButton];
[window.contentView addSubview:fullScreenButton];
[window.contentView addSubview:minitButton];

Now when the window appears with the buttons there is two problems: 1. They are grey and not their correct color 2. when the mouse is over them they do not show the + - or x sign

can anyone tell me what I am doing wrong. Thanks.


回答1:


Here is the mechanics of this hover magic: Before drawing itself standard circled button (such as NSWindowMiniaturizeButton) calls their superview undocumented method _mouseInGroup:. If this method returns YES circled button draws itself with icon inside. That's all.

If you place these buttons inside your own view, you can simply implement this method and control this mouse-hover-appearance as you want. If you just move or relayout these buttons and they still be subviews of NSThemeFrame (or something similar), you have to swizzle method _mouseInGroup: for this class, and probably it doesn't worth it because we have perfectly simple previous method.

In my case I have custom NSView that contains my standard buttons as subviews and this code makes all described above magic:

- (void)updateTrackingAreas
{
    NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil];
    [self addTrackingArea:trackingArea];
}

- (void)mouseEntered:(NSEvent *)event
{
    [super mouseEntered:event];
    self.mouseInside = YES;
    [self setNeedsDisplayForStandardWindowButtons];
}

- (void)mouseExited:(NSEvent *)event
{
    [super mouseExited:event];
    self.mouseInside = NO;
    [self setNeedsDisplayForStandardWindowButtons];
}

- (BOOL)_mouseInGroup:(NSButton *)button
{
    return self.mouseInside;
}

- (void)setNeedsDisplayForStandardWindowButtons
{
    [self.closeButtonView setNeedsDisplay];
    [self.miniaturizeButtonView setNeedsDisplay];
    [self.zoomButtonView setNeedsDisplay];
}



回答2:


I'm fully aware that this question is old and Valentin Shergin's answer is correct. It prevents the utilize of any Private API, unlike Google did in Chrome. Just wanted to share a method for those who don't feel like subclass NSView just to put those buttons in an existed view (such as self.window.contentView).

As I just wanted to reposition the NSWindowButtons via setFrame:, I found out that once the window was resized, the tracking areas seems to "fix" themselves automagically, without any Private API usage (at least in 10.11).

Thus, you can do things like the following to apply "fake resize" to the window that you repositioned your buttons:

NSRect frame = [self.window frame];
frame.size = NSMakeSize(frame.size.width, frame.size.height+1.f);
[self.window setFrame:frame display:NO animate:NO];
frame.size = NSMakeSize(frame.size.width, frame.size.height-1.f);
[self.window setFrame:frame display:NO animate:YES];

(I did it within my main window's NSWindowDelegate windowDidBecomeMain:. Should work as long as the window is loaded and visible.)




回答3:


You're not adding them again. You're moving them to contentView. The buttons are originally in window.contentView.superview.

[window.contentView.superview addSubview:closeButton];
[window.contentView.superview addSubview:fullScreenButton];
[window.contentView.superview addSubview:minitButton];

Should get you the correct behaviour without requiring a trackingArea.




回答4:


Call [button highlight:yes] for each button.



来源:https://stackoverflow.com/questions/7634788/cocoa-osx-nswindow-standardwindowbutton-behaving-strangely-once-copied-and-add

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!