Cocoa/OSX - NSWindow standardWindowButton 在复制并再次添加后行为异常

问题描述 投票:0回答:5

在我的应用程序中,我更改了标准窗口按钮关闭/缩小/展开的位置,如下所示:

 //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];

现在,当带有按钮的窗口出现时,存在两个问题: 1.它们是灰色的,而不是正确的颜色 2.当鼠标悬停在它们上方时,它们不会显示 + - 或 x 符号

谁能告诉我我做错了什么。谢谢。

objective-c macos cocoa nswindow nsbutton
5个回答
11
投票

这是这种悬停魔法的机制:在绘制自身之前,标准圆形按钮(例如

NSWindowMiniaturizeButton
)调用其
superview
未记录的方法
_mouseInGroup:
。如果此方法返回
YES
,则圆形按钮会在内部绘制图标。仅此而已。

如果您将这些按钮放在您自己的视图中,您可以简单地实现此方法并根据需要控制此鼠标悬停外观。如果你只是移动或重新布局这些按钮,而它们仍然是

subview
NSThemeFrame
(或类似的东西),那么你必须为这个类调整方法
_mouseInGroup:
,而且可能不值得,因为我们有完美的简单的以前的方法。

就我而言,我有自定义的

NSView
,其中包含我的标准按钮
subview
,并且此代码使上述所有内容变得神奇:

- (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
投票

我完全意识到这个问题是并且Valentin Shergin的答案正确。它阻止使用任何“私人 API”,与“Google 在 Chrome 中所做的”不同。只是想为那些不喜欢子类 NSView 的人分享一种方法,只是将这些按钮放在现有视图中(例如 self.window.contentView)。


因为我只是想通过
NSWindowButton
重新定位

setFrame:

,我发现一旦窗口

调整大小
,跟踪区域似乎会自动“
修复
”,无需使用任何私有 API (至少在 10.11 中)。 因此,您可以执行以下操作,将“fake resize”应用到您重新定位按钮的窗口: 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];

(我是在主窗口的 NSWindowDelegate

windowDidBecomeMain:
 中完成的。只要窗口已加载且
可见

,就应该可以工作。)

    
您不会再次添加它们。您正在将它们移动到 contentView。按钮最初位于 window.contentView.superview 中。

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


0
投票

过了这么久,
Valentin Shergin 的回答

仍然有效!


0
投票

// Need to first add your traffic light buttons to this stack view class FauxTitleBarView: NSStackView { var isMouseInside: Bool = false @objc func _mouseInGroup(_ button: NSButton) -> Bool { return isMouseInside } private func markButtonsDirty() { for btn in views { btn.needsDisplay = true } } override func mouseEntered(with event: NSEvent) { isMouseInside = true markButtonsDirty() } override func mouseExited(with event: NSEvent) { isMouseInside = false markButtonsDirty() } } class MyWindowController: NSWindowController, NSWindowDelegate { var fauxTitleBar: FauxTitleBarView // ... func windowDidBecomeMain(_ notification: Notification) { // The traffic light buttons should change to active color for button in fauxTitleBar.views { button.needsDisplay = true } } func windowDidResignMain(_ notification: Notification) { // The traffic light buttons should change to inactive color for button in fauxTitleBar.views { button.needsDisplay = true } } }

为每个按钮调用

[button highlight:yes]

-1
投票

© www.soinside.com 2019 - 2024. All rights reserved.