如何在屏幕上围绕给定矩形绘制轮廓?

时间:2020-09-23 07:50:29

标签: objective-c macos cocoa core-graphics

我的目标是在另一个应用程序的窗口周围绘制轮廓。与Microsoft Teams在桌面共享期间绘制轮廓类似。

例如,如下图所示,Safari窗口周围的轮廓。

Something like this

使用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开发的经验很少,我将不胜感激。

我应该如何绘制此轮廓,在需要时对其进行更新和隐藏?

1 个答案:

答案 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;
}

相关问题