我的目标是在另一个应用程序的窗口周围绘制轮廓。与Microsoft Teams在桌面共享期间绘制轮廓类似。
例如,如下图所示,Safari窗口周围的轮廓。
使用macOS的Quartz Window Services和可访问性API,我能够获取Safari的坐标(x,y,宽度,高度),并且我订阅了发生在窗口上的事件,例如调整大小或窗口是否更改了位置
// How I get window coordinates
- (CGRect)selectedAppCoordinates:(long)windowId {
NSLog(@"selectedAppCoordinates - IN");
CGRect rect;
CGWindowID windowid[1];
windowid[0] = windowId;
CFArrayRef windowArray =
CFArrayCreate(nullptr, (const void **)windowid, 1, nullptr);
CFArrayRef windowsdescription =
CGWindowListCreateDescriptionFromArray(windowArray);
CFDictionaryRef windowdescription = (CFDictionaryRef)CFArrayGetValueAtIndex(
(CFArrayRef)windowsdescription, 0);
if (CFDictionaryContainsKey(windowdescription, kCGWindowBounds)) {
CFDictionaryRef bounds = (CFDictionaryRef)CFDictionaryGetValue(
windowdescription, kCGWindowBounds);
if (bounds) {
if (CGRectMakeWithDictionaryRepresentation(bounds, &rect)) {
NSLog(@"x: %f, y: %f, width: %f, height: %f", rect.origin.x,
rect.origin.y, rect.size.width, rect.size.height);
}
}
}
CFRelease(windowArray);
NSLog(@"selectedAppCoordinates - OUT");
return rect;
}
对我来说,问题是画轮廓。我对本机macOS开发的经验很少,我将不胜感激。
我应该如何绘制此轮廓,在需要时对其进行更新和隐藏?
答案 0 :(得分:1)
根据bhaller先前给出的建议,以下演示使用了第二个参考底图窗口,该窗口包含颜色填充视图,并且比主窗口稍大,以便可以看到其边缘。底层窗口通过窗口委托与主窗口绑定,以同步更改位置/大小,并且可以显示或隐藏。通过用以下代码替换主文件并另外删除Apple提供的AppDelegate文件,可以在Xcode中运行该演示(以避免重复的符号错误):
#import <Cocoa/Cocoa.h>
@interface CustomView : NSView
@end
@implementation CustomView
- (id)initWithFrame:(NSRect)frameRect{
if ((self = [super initWithFrame:frameRect]) != nil) {
// Add initialization code here
}
return self;
}
- (void)drawRect:(NSRect)rect {
// ****** Background ***** //
[[NSColor redColor] set];
[NSBezierPath fillRect:rect];
}
// ----- Use this if you want 0,0 (origin) to be top, left ---- //
// ----- Otherwise origin will be at bottom, left (Unflipped) ----- //
-(BOOL)isFlipped
{
return YES;
}
@end
@interface WindowDelegate : NSObject <NSWindowDelegate>
@property(strong) NSWindow *underlayWnd;
@end
@implementation WindowDelegate
- (void)windowDidResize:(NSNotification *)notification {
NSRect frameR = NSMakeRect([notification.object frame].origin.x - 10, [notification.object frame].origin.y - 10, [notification.object frame].size.width + 20, [notification.object frame].size.height + 20);
[_underlayWnd setFrame:frameR display:YES];
}
- (void)windowDidEndLiveResize:(NSNotification *)notification {
NSRect frameR = NSMakeRect([notification.object frame].origin.x - 10, [notification.object frame].origin.y - 10, [notification.object frame].size.width + 20, [notification.object frame].size.height + 20);
[_underlayWnd setFrame:frameR display:YES];
}
- (void)windowDidMove:(NSNotification *)notification {
NSRect frameR = NSMakeRect([notification.object frame].origin.x - 10, [notification.object frame].origin.y - 10, [notification.object frame].size.width + 20, [notification.object frame].size.height + 20);
[_underlayWnd setFrame:frameR display:YES];
}
- (void)windowDidMiniaturize:(NSNotification *)notification {
NSRect frameR = NSMakeRect([notification.object frame].origin.x - 10, [notification.object frame].origin.y - 10, [notification.object frame].size.width + 20, [notification.object frame].size.height + 20);
[_underlayWnd setFrame:frameR display:YES];
}
@end
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
NSWindow *window;
NSWindow *underlayWnd;
WindowDelegate *windowDelegate;
CustomView *view;
}
- (void) myShowAction;
- (void) myHideAction;
- (void) buildMenu;
- (void) buildWindow;
@end
@implementation AppDelegate
-(void) myHideAction {
[underlayWnd orderOut:nil];
}
-(void) myShowAction {
[underlayWnd orderFront:nil];
[window makeKeyAndOrderFront: nil];
}
- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new];
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quit"
action:@selector(terminate:) keyEquivalent:@"q"];
[appMenu addItem:quitMenuItem];
[menuBarItem setSubmenu:appMenu];
}
- (void) buildWindow {
windowDelegate = [[WindowDelegate alloc]init];
#define _wndW 700
#define _wndH 550
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable
backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: @"Test window"];
[window setDelegate: windowDelegate];
[window makeKeyAndOrderFront: nil];
NSRect frameR = NSMakeRect([window frame].origin.x - 10, [window frame].origin.y - 10, [window frame].size.width + 20, [window frame].size.height + 20);
underlayWnd = [[NSWindow alloc] initWithContentRect:frameR styleMask: NSWindowStyleMaskBorderless backing: NSBackingStoreBuffered defer: NO];
[underlayWnd setIgnoresMouseEvents:true];
[underlayWnd orderWindow:NSWindowBelow relativeTo:0];
// **** Custom View **** //
view = [[CustomView alloc]initWithFrame:NSMakeRect(0,0,frameR.size.width, frameR.size.height)];
[view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
[[underlayWnd contentView] addSubview:view]
[windowDelegate setUnderlayWnd:underlayWnd];
// **** Hide Button **** //
NSButton *hideBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, 30, 165, 30 )];
[hideBtn setBezelStyle:NSBezelStyleRounded ];
[hideBtn setTitle: @"Hide underlay window"];
[hideBtn setAction: @selector (myHideAction)];
[[window contentView] addSubview: hideBtn];
// **** Show Button **** //
NSButton *showBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 210, 30, 165, 30 )];
[showBtn setBezelStyle:NSBezelStyleRounded ];
[showBtn setTitle: @"Show underlay window"];
[showBtn setAction: @selector (myShowAction)];
[[window contentView] addSubview: showBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: @"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:@selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification
{
[self buildMenu];
[self buildWindow];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification
{
}
@end
int main (){
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}