NSStatusBarButton保持突出显示

时间:2014-09-23 21:03:28

标签: objective-c macos cocoa osx-yosemite nsstatusitem

从OS X 10.10开始,大多数NSStatusItem都被弃用,而不是button属性,该属性由NSStatusBarButton组成。它应该像普通按钮一样工作,但不幸的是,NSStatusButton中的cellsetCell方法也已被弃用。因此,我很难找到一种方法来保持按钮在点击后突出显示(通常按钮在鼠标按下时突出显示,在鼠标向上突出显示。我希望在鼠标按下后保持按钮突出显示)。

在其操作中调用[NSStatusButton setHighlighted:]不起作用,因为一旦鼠标启动它似乎不会突出显示。另一方面,使用延迟在下一个循环(即[self performSelector: withDelay:])上调用它会导致突出显示以相当难看的方式闪烁。它有效,但看起来不太好。

将按钮类型设置为NSToggleButton会完全删除突出显示,而是突出显示奇怪的模板图像。

这是我能想到的唯一方法。无论如何都要覆盖这个NSButtonCell mouseUp行为吗?

10 个答案:

答案 0 :(得分:7)

这是另一个选择。不要设置NSStatusItem的{​​{1}}属性。而是添加本地事件监视器:

action

然后在[NSEvent addLocalMonitorForEventsMatchingMask:(NSLeftMouseDown | NSRightMouseDown) handler:^NSEvent *(NSEvent *event) { if (event.window == self.statusItem.button.window) { [self itemClicked]; return nil; } return event; }]; 中使用-itemClicked方法突出显示按钮:

highlight:

取消强调只需拨打按钮- (void)itemClicked { [self.statusItem.button highlight:YES]; // Do other stuff } 即可。

答案 1 :(得分:7)

Swift 3版Manfred Urban's回答。 适用于El Capitan。

extension NSStatusBarButton {

   public override func mouseDown(_ event: NSEvent) {

        if (event.modifierFlags.contains(NSControlKeyMask)) {
            self.rightMouseDown(event)
            return
        }

        self.highlight(true)

        (self.target as? TrivialTargetClass)?.togglePopover()
    }
}

如果合适,请不要忘记再次将按钮高亮显示属性设置为false。

答案 2 :(得分:4)

我在状态项中添加了一个子视图,在该视图中我添加了mouseDown等的事件处理程序,调用[[statusItem button] highlight:true]。事实证明setHighlighted:与亮点不同:。

NSArray *array = [NSArray arrayWithObjects:[statusItem button], [self statusItemView], nil];
[[[statusItem button] superview] setSubviews:array];
//Highlight like so:
[[statusItem button] highlight:true];

编辑:从El Capitan开始,此方法不再有效,statusItem.button.highlight = true也不会

答案 3 :(得分:4)

我自己在这个问题上苦苦挣扎,发现在mouseDown:的类别中覆盖NSStatusBarButton有效:

#import "MUTargetClass.h"

@implementation NSStatusBarButton (Additions)

- (void)mouseDown:(NSEvent *)theEvent
{
    // Relay CTRL+Click to perform a right click action
    if(theEvent.modifierFlags & NSControlKeyMask)
    {
        [self rightMouseDown:theEvent];
        return;
    }

    // Handle highlighting
    [self setHighlighted:YES];

    // Perform action on target
    [(MUTargetClass *)self.target actionSelector:self];
}

@end
然后

MUTargetClass可以实现:

#import "NSStatusBarButton+Additions.h"

@implementation MUTargetClass

[…]
    self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
    NSStatusBarButton *button = [self.statusItem button];
    [button setTarget:self];
[…]

- (void)actionSelector:(id)sender
{
    // Whatever behavior a click on the button should invoke
}

[…]
    // Reset button's highlighting status when done
    [[self.statusItem button] setHighlighted:NO];
[…]

@end

请注意,CTRL +点击按钮的功能会在mouseDown: - 覆盖中丢失。如上所示,可以通过将事件中继到rightMouseDown:来恢复它。

调用操作的一种更简单的方法是类别中的[self.target performSelector:self.action]和目标类中的[self.statusItem setAction:@selector(actionSelector:)],但是在ARC项目中这是may cause a leak

编辑:这也适用于El Capitan。

答案 4 :(得分:2)

TL; DR:NSButton内的NSImagetemplate=YESNSStatusItem个实例NSStatusBarButton视觉上看起来与highlight完全相同。您可以根据需要控制他们的NSStatusItem属性。

如果您想手动控制NSStatusBarButton的突出显示,同时使用NSButton获得所有外观优势,您可以使用略有不同的方法。 您可以创建自己的highlight实例,该实例具有完全由您控制的属性NSImage。然后,您必须创建template实例并将其YES属性设置为button。然后,您必须将此[NSStatusItem view]添加到softly deprecated(是,[NSStatusItem button]),或者甚至作为系统创建的NSStatusItem的子视图。在此之后,您必须使用[NSStatusItem drawStatusBarBackgroundInRect:withHighlight:]手动绘制NSStatusItem的背景(也已弃用,哦)。

通过这种方法,您可以完全控制function [Af,Bf] = rotateTwoPoints (A,B,t) % Definition of the rotation matrix (rotation around origin (0,0) ) R=[ ... cosd(t) -sind(t) sind(t) cosd(t) ]; % rotation of the points A and B Af = R*A; Bf = R*B; % Plot of the original line plot(A(1),A(2),'k*', B(1),B(2),'b*'); line([A(1) B(1)],[A(2) B(2)], 'Color','r'); grid on hold on % Plot of the rotated line plot(Af(1),Af(2),'g*', Bf(1),Bf(2),'r*'); line([Af(1) Bf(1)],[Af(2) Bf(2)], 'Color','b'); legend('A','B','line AB','Af','Bf','line AfBf','Location','northeastoutside'); daspect([1 1 1]) 的外观和感觉,并获得按钮图像的自动样式。

答案 5 :(得分:1)

一个想法是调动isHighlighted NSStatusBarButtonCell并返回任意值。 https://gist.github.com/questbeat/3244601c8dc779484076

但问题在于Apple的审核小组是否允许这种方法......

答案 6 :(得分:0)

卢克的回答很棒。我只是基于此分享我的实现。

NSButton *button = [[NSButton alloc] initWithFrame:self.statusItem.button.frame];
button.alphaValue = 0;
NSArray *array = @[self.statusItem.button, button];
self.statusItem.button.superview.subviews = array;

[button sendActionOn:(NSLeftMouseDownMask | NSRightMouseDownMask)];
button.target = self;
button.action = @selector(statusItemClicked);

答案 7 :(得分:0)

如果你安排突出显示按钮以便在主线程上执行后续操作,那么一切似乎都有效。这对El Capitan也有效。

    if self.appPopover.shown {
        self.appPopover.performClose(sender)
    } else {
        if let button = statusItem.button {
            // set the button's highlighted property to true
            dispatch_async(dispatch_get_main_queue(), {
                button.highlighted = true
            })

            appPopover.showRelativeToRect(button.bounds, ofView: button, preferredEdge: NSRectEdge.MinY)
        }
    }

这确实有效,但由于按钮状态从ON变为OFF然后再次打开,您可能会注意到一点点闪烁。 OFF因为弹出窗口显示而发生。因此,要解决此问题,只需在突出显示按钮后立即在dispatch_async()块内移动appPopover.showRelativeToRect()调用即可。

答案 8 :(得分:0)

这是@erikvdplas 答案的 Swift 5 版本。我在 macOS 11.4 Big Sur 上对此进行了测试。

extension NSStatusBarButton {
    public override func mouseDown(with event: NSEvent) {
        super.mouseDown(with: event)
        self.highlight((NSApp.delegate as! YourAppDelegateClass).popover.isShown)
    }
}

答案 9 :(得分:-1)

安东的解决方案非常完美。这是在Swift 3中:

NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { [weak self] event in
    if event.window == self?.statusItem.button?.window {
        // Your action:
        self?.togglePopover(self?.statusItem.button)
        return nil
    }

    return event
}

我添加了NSApplicationWillResignActive的观察者来关闭弹出窗口,并将按钮的isHighlighted设置为false