在非活动NSWindow上更改鼠标光标

www*_*.se 5 macos mouse cocoa mouseover nswindow

我继承了NSWindow的子类,并拥有一个实现以下方法的MYWindow类:

-(void)resetCursorRects {
    NSImage *image = [NSImage imageNamed:@"cursor.png"];
    [image setSize:NSMakeSize(32, 32)];
    NSCursor *cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(1, 1)];
    [super resetCursorRects];    
    [self addCursorRect:[self bounds] cursor:cursor];
}
Run Code Online (Sandbox Code Playgroud)

这将更改整个窗口的光标,我将看到cursor.png而不是默认的鼠标指针。问题是,这仅在MYWindow设置为键窗口时才起作用,而键窗口当然并不重要。

在项目开始时,我只有一个主窗口,但是现在我需要有两个不同的MYWindow。两个窗口的问题无法同时设置为键窗口,因此自定义鼠标指针仅显示在活动窗口上。我需要单击另一个窗口以使光标出现。

有没有办法解决?所以我在两个窗口上都有一个自定义光标吗?

编辑:尝试了NSTrackingArea

我将此添加到了内容视图的init方法中:

self.trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame] options: (NSTrackingCursorUpdate | NSTrackingActiveAlways | NSTrackingMouseMoved) owner:self userInfo:nil];
[self addTrackingArea:self.trackingArea];
Run Code Online (Sandbox Code Playgroud)

然后,我覆盖了cursorUpdate:

-(void)cursorUpdate:(NSEvent *)event {
    NSLog(@"event : %@", event);
    [[NSCursor crosshairCursor] set];
}
Run Code Online (Sandbox Code Playgroud)

当包含NSImageView派生类的NSWindow是关键窗口时,这将使crosshairCursor显示。但是,如果我在应用程序中使另一个NSWindow成为键窗口,则光标会再次返回到标准光标。难道我做错了什么?

Val*_*gin 6

我为这个问题苦苦挣扎了很长一段时间,我认为只有一种方法可以在非活动应用程序(非前台窗口)上更改鼠标光标。这是hacky和神奇的方式。

在调用漂亮标准之前:

[[NSCursor pointingHandCursor] push];
Run Code Online (Sandbox Code Playgroud)

您必须致电:

void CGSSetConnectionProperty(int, int, int, int);
int CGSCreateCString(char *);
int CGSCreateBoolean(BOOL);
int _CGSDefaultConnection();
void CGSReleaseObj(int);
int propertyString, boolVal;

propertyString = CGSCreateCString("SetsCursorInBackground");
boolVal = CGSCreateBoolean(TRUE);
CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, boolVal);
CGSReleaseObj(propertyString);
CGSReleaseObj(boolVal);
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用的是 Swift:

把它放在你的YourApp-Bridging-Header.h

typedef int CGSConnectionID;
CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);
int _CGSDefaultConnection();
Run Code Online (Sandbox Code Playgroud)

然后调用:

let propertyString = CFStringCreateWithCString(kCFAllocatorDefault, "SetsCursorInBackground", 0)
CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue)
Run Code Online (Sandbox Code Playgroud)


www*_*.se 4

现在我终于找到了一个可行的解决方案。我不知道这将来是否会咬我的尾巴,但至少这在测试时似乎有效。

感谢威尔提供的例子,它让我成功了一半。但直到我最终将它与resetCursorRects结合起来,并在每个视图中使用特定光标定义了一个光标矩形时才出现这种情况。这花了我很长时间才弄清楚,我不知道该解决方案是否是最佳的(欢迎提出改进建议)

下面是最终使它对我有用的完整示例(self.cursor 是光标的实例)

- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
    NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil];
    [self addTrackingArea:trackingArea];
    [self.window invalidateCursorRectsForView:self];
}

- (void)resetCursorRects {
    [super resetCursorRects];
    [self addCursorRect:self.bounds cursor:self.cursor];
}

- (void)mouseEntered:(NSEvent *)theEvent {
    [super mouseEntered:theEvent];
    [self.cursor push];
}

- (void)mouseExited:(NSEvent *)theEvent {
    [super mouseExited:theEvent];
    [self.cursor pop];
}
Run Code Online (Sandbox Code Playgroud)