nswindow样式为fullSizeContentView时如何处理mouseEntered:和mouseExited:事件?

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

我有一个 macOS 应用程序,其视图占据整个窗口,并在窗口的 styleMask 中设置了 NSWindowStyleMaskFullSizeContentView。我想在鼠标进入窗口时显示标题栏和窗口按钮,并在鼠标退出窗口时隐藏它们。

我使用的跟踪区域的矩形为 window.contentView.bounds,并从标题栏的高度中减去标题栏的高度。

我已经实现了 mouseEntered: 和 mouseExited: 方法来处理显示/隐藏操作。

我遇到的问题是,当我将鼠标移动到窗口的标题栏时,应用程序快速连续接收多个 mouseExited:/mouseEntered: 事件,导致标题栏出现“颤动”效果。

为了重现这个问题,我首先在 Xcode 中创建了一个 Objective-C 项目,并使用 IB 将窗口属性设置为“全尺寸内容视图”。然后如图所示编辑ViewController.m。

    //
    //  ViewController.m
    //  Repro
    //
    
    #import "ViewController.h"
    
    @implementation ViewController
    {
        NSTrackingArea  *trackingArea;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        // Do any additional setup after loading the view.
    }
    - (void)viewWillAppear
    {
        // background color
        self.view.wantsLayer = true;
        self.view.layer.backgroundColor = [NSColor systemBlueColor].CGColor;
    
        // tracking area
        [self setupTrackingArea:self.view.window.contentView.bounds];
        
        return;
    }
    - (void)setupTrackingArea:(CGRect)frame
    {
        if (trackingArea)
        {
            [self.view removeTrackingArea:trackingArea];
        }
    
        NSTrackingAreaOptions   options = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect | NSTrackingMouseMoved;
    
        // subtract the titlebar height from the content view height
        frame.size.height -= [self titlebarHeight:self.view.window];
    
        trackingArea = [[NSTrackingArea alloc]initWithRect:frame
                               options:options
                                 owner:self
                              userInfo:nil];
        [self.view addTrackingArea:trackingArea];
    }
    - (CGFloat)titlebarHeight:(NSWindow *)window
    {
        CGFloat windowHeight = window.contentView.frame.size.height;
        CGFloat contentHeight = window.contentLayoutRect.size.height;
        CGFloat titlebarHeight = windowHeight - contentHeight;
        return titlebarHeight;
    }
    
    - (void)mouseEntered:(NSEvent *)event
    {
        [self showTitleBar];
        [self showWindowButtons:self.view.window];
    
        return;
    }
    - (void)mouseExited:(NSEvent *)event
    {
        [self hideTitleBar];
        [self hideWindowButtons:self.view.window];
        return;
    }
    
    - (void)showTitleBar
    {
        self.view.window.titlebarAppearsTransparent = false;
        self.view.window.title = @"Repro";
        return;
    }
    - (void)hideTitleBar
    {
        self.view.window.titlebarAppearsTransparent = true;
        self.view.window.title = @"";
        return;
    }
    
    - (void)hideWindowButtons:(NSWindow *)window
    {
        [window standardWindowButton:NSWindowZoomButton].hidden = true;
        [window standardWindowButton:NSWindowMiniaturizeButton].hidden = true;
        [window standardWindowButton:NSWindowCloseButton].hidden = true;
        return;
    }
    - (void)showWindowButtons:(NSWindow *)window
    {
        [window standardWindowButton:NSWindowZoomButton].hidden = false;
        [window standardWindowButton:NSWindowMiniaturizeButton].hidden = false;
        [window standardWindowButton:NSWindowCloseButton].hidden = false;
        return;
    }

@end
macos window mouseevent
1个回答
0
投票

感谢 Willeke 的建议(非常感谢您的帮助!),有一个解决方案。它涉及 NSView 的子类化(我称之为 MyView),将所有跟踪区域处理移至该视图中,并将其从 ViewController 中删除。 MyView.m 是:

//
//  MyView.m
//  Repro
//

#import "MyView.h"

@implementation MyView
{
        NSTrackingArea  *trackingArea;
}

- (void)viewWillMoveToWindow:(NSWindow *)newWindow
{
        if (newWindow)
        {
                newWindow.styleMask |= NSWindowStyleMaskFullSizeContentView;

                [self setupTrackingArea:newWindow];
        }
        [super viewWillMoveToWindow:newWindow];
        return;
}
- (void)updateTrackingAreas
{
        [self setupTrackingArea:self.window];

        [super updateTrackingAreas];

        return;
}

- (void)setupTrackingArea:(NSWindow *)window
{
        if (trackingArea)
                [self removeTrackingArea:trackingArea];

        NSTrackingAreaOptions   options = NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways;
        trackingArea = [[NSTrackingArea alloc]initWithRect:self.bounds
                                                   options:options
                                                     owner:self
                                                  userInfo:nil];
        [self addTrackingArea:trackingArea];
        return;
}
- (void)mouseEntered:(NSEvent *)event
{
        [self showTitleBar];
        [self showWindowButtons:self.window];

        return;
}
- (void)mouseExited:(NSEvent *)event
{
        [self hideTitleBar];
        [self hideWindowButtons:self.window];
        return;
}

- (void)showTitleBar
{
        self.window.titlebarAppearsTransparent = false;
        self.window.title = [NSProcessInfo processInfo].processName;
        return;
}
- (void)hideTitleBar
{
        self.window.titlebarAppearsTransparent = true;
        self.window.title = @"";
        return;
}

- (void)hideWindowButtons:(NSWindow *)window
{
        // hide the minimize and zoom buttons (yellow and green)
        [window standardWindowButton:NSWindowZoomButton].hidden = true;
        [window standardWindowButton:NSWindowMiniaturizeButton].hidden = true;
        [window standardWindowButton:NSWindowCloseButton].hidden = true;
        return;
}
- (void)showWindowButtons:(NSWindow *)window
{
        [window standardWindowButton:NSWindowZoomButton].hidden = false;
        [window standardWindowButton:NSWindowMiniaturizeButton].hidden = false;
        [window standardWindowButton:NSWindowCloseButton].hidden = false;
        return;
}
@end
© www.soinside.com 2019 - 2024. All rights reserved.