Objective c 在屏幕边缘弹出一个窗口
我正在尝试用Objective-C为我的Mac电脑重新编写一个Windows应用程序,我希望能够做一些类似Mac电脑的热门角落的事情。如果我将鼠标移到屏幕左侧,它将使窗口可见,如果我将鼠标移到窗口位置之外,窗口将再次隐藏。(窗口将被推到屏幕左侧) 有人知道我在哪里可以找到一些演示代码(或参考资料)来说明如何做到这一点,或者至少知道如何知道鼠标在哪里,即使当前的应用程序不在顶部。(不知道该怎么说,也习惯于Windows世界) 多谢各位Objective c 在屏幕边缘弹出一个窗口,objective-c,cocoa,macos,Objective C,Cocoa,Macos,我正在尝试用Objective-C为我的Mac电脑重新编写一个Windows应用程序,我希望能够做一些类似Mac电脑的热门角落的事情。如果我将鼠标移到屏幕左侧,它将使窗口可见,如果我将鼠标移到窗口位置之外,窗口将再次隐藏。(窗口将被推到屏幕左侧) 有人知道我在哪里可以找到一些演示代码(或参考资料)来说明如何做到这一点,或者至少知道如何知道鼠标在哪里,即使当前的应用程序不在顶部。(不知道该怎么说,也习惯于Windows世界) 多谢各位 -Brad您需要在屏幕边缘设置一个不可见窗口,并设置窗口顺序,
-Brad您需要在屏幕边缘设置一个不可见窗口,并设置窗口顺序,使其始终位于顶部。然后,您可以在此窗口中侦听鼠标移动事件 要将窗口设置为不可见且位于顶部,请使用如下调用创建窗口子类:
[self setBackgroundColor:[NSColor clearColor]];
[self setExcludedFromWindowsMenu:YES];
[self setCanHide:NO];
[self setLevel:NSScreenSaverWindowLevel];
[self setAlphaValue:0.0f];
[self setOpaque:NO];
[self orderFrontRegardless];
然后,要启用鼠标移动事件
[self setAcceptsMouseMovedEvents:YES];
将导致窗口获取对以下对象的调用:
- (void)mouseMoved:(NSEvent *)theEvent
{
NSLog(@"mouse moved into invisible window.");
}
所以希望这足够给你一个开始
-Ken您可以看看我们在Visor项目中是如何做到的:
以下是我的想法。感谢Peter提供的上述提示
@interface SlidingWindow : NSWindow
{
CGRectEdge _slidingEdge;
NSView *_wrapperView;
}
@property (nonatomic, assign) CGRectEdge slidingEdge;
@property (nonatomic, retain) NSView *wrapperView;
-(id)initWithContentRect:(NSRect) contentRect
styleMask:(unsigned int) styleMask
backing:(NSBackingStoreType) backingType
defer:(BOOL) flag;
- (NSView*)wrapperViewWithFrame:(NSRect)bounds;
- (BOOL)mayOrderOut;
@end
@interface SlidingWindow ()
- (void)adjustWrapperView;
- (void)setWindowWidth:(NSNumber*)width;
- (void)setWindowHeight:(NSNumber*)height;
@end
@implementation SlidingWindow
@synthesize slidingEdge = _slidingEdge;
@synthesize wrapperView = _wrapperView;
- (id)initWithContentRect:(NSRect) contentRect
styleMask:(unsigned int) styleMask
backing:(NSBackingStoreType) backingType
defer:(BOOL) flag
{
if ((self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:backingType
defer:flag])) {
/* May want to setup some other options,
like transparent background or something */
[self setSlidingEdge:CGRectMaxYEdge];
[self setHidesOnDeactivate:YES];
[self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
}
return self;
}
- (NSView*)wrapperViewWithFrame:(NSRect)bounds
{
return [[[NSView alloc] initWithFrame:bounds] autorelease];
}
- (void)adjustWrapperView
{
if (self.wrapperView == nil) {
NSRect frame = [self frame];
NSRect bounds = NSMakeRect(0, 0, frame.size.width, frame.size.height);
NSView *wrapperView = [self wrapperViewWithFrame:bounds];
NSArray *subviews = [[[[self contentView] subviews] copy] autorelease];
for (NSView *view in subviews) {
[wrapperView addSubview:view];
}
[wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
[[self contentView] addSubview:wrapperView];
self.wrapperView = wrapperView;
}
switch (self.slidingEdge) {
case CGRectMaxXEdge:
[self.wrapperView setAutoresizingMask:(NSViewHeightSizable | NSViewMaxXMargin)];
break;
case CGRectMaxYEdge:
[self.wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)];
break;
case CGRectMinXEdge:
[self.wrapperView setAutoresizingMask:(NSViewHeightSizable | NSViewMinXMargin)];
break;
case CGRectMinYEdge:
default:
[self.wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
}
}
- (void)makeKeyAndOrderFront:(id)sender
{
[self adjustWrapperView];
if ([self isVisible]) {
[super makeKeyAndOrderFront:sender];
}
else {
NSRect screenRect = [[NSScreen menubarScreen] visibleFrame];
NSRect windowRect = [self frame];
CGFloat x;
CGFloat y;
NSRect startWindowRect;
NSRect endWindowRect;
switch (self.slidingEdge) {
case CGRectMinXEdge:
x = 0;
y = (screenRect.size.height - windowRect.size.height) / 2 + screenRect.origin.y;
startWindowRect = NSMakeRect(x - windowRect.size.width, y, 0, windowRect.size.height);
break;
case CGRectMinYEdge:
x = (screenRect.size.width - windowRect.size.width) / 2 + screenRect.origin.x;
y = 0;
startWindowRect = NSMakeRect(x, y - windowRect.size.height, windowRect.size.width, 0);
break;
case CGRectMaxXEdge:
x = screenRect.size.width - windowRect.size.width + screenRect.origin.x;
y = (screenRect.size.height - windowRect.size.height) / 2 + screenRect.origin.y;
startWindowRect = NSMakeRect(x + windowRect.size.width, y, 0, windowRect.size.height);
break;
case CGRectMaxYEdge:
default:
x = (screenRect.size.width - windowRect.size.width) / 2 + screenRect.origin.x;
y = screenRect.size.height - windowRect.size.height + screenRect.origin.y;
startWindowRect = NSMakeRect(x, y + windowRect.size.height, windowRect.size.width, 0);
}
endWindowRect = NSMakeRect(x, y, windowRect.size.width, windowRect.size.height);
[self setFrame:startWindowRect display:NO animate:NO];
[super makeKeyAndOrderFront:sender];
[self setFrame:endWindowRect display:YES animate:YES];
[self performSelector:@selector(makeResizable)
withObject:nil
afterDelay:1];
}
}
- (void)makeResizable
{
NSView *wrapperView = self.wrapperView;
NSRect frame = [self frame];
NSRect bounds = NSMakeRect(0, 0, frame.size.width, frame.size.height);
[wrapperView setFrame:bounds];
[wrapperView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
}
- (void)orderOut:(id)sender
{
[self adjustWrapperView];
NSRect startWindowRect = [self frame];
NSRect endWindowRect;
switch (self.slidingEdge) {
case CGRectMinXEdge:
endWindowRect = NSMakeRect(startWindowRect.origin.x,
startWindowRect.origin.y,
0,
startWindowRect.size.height);
break;
case CGRectMinYEdge:
endWindowRect = NSMakeRect(startWindowRect.origin.x,
startWindowRect.origin.y,
startWindowRect.size.width,
0);
break;
case CGRectMaxXEdge:
endWindowRect = NSMakeRect(startWindowRect.origin.x + startWindowRect.size.width,
startWindowRect.origin.y,
0,
startWindowRect.size.height);
break;
case CGRectMaxYEdge:
default:
endWindowRect = NSMakeRect(startWindowRect.origin.x,
startWindowRect.origin.y + startWindowRect.size.height,
startWindowRect.size.width,
0);
}
[self setFrame:endWindowRect display:YES animate:YES];
switch (self.slidingEdge) {
case CGRectMaxXEdge:
case CGRectMinXEdge:
if (startWindowRect.size.width > 0) {
[self performSelector:@selector(setWindowWidth:)
withObject:[NSNumber numberWithDouble:startWindowRect.size.width]
afterDelay:0];
}
break;
case CGRectMaxYEdge:
case CGRectMinYEdge:
default:
if (startWindowRect.size.height > 0) {
[self performSelector:@selector(setWindowHeight:)
withObject:[NSNumber numberWithDouble:startWindowRect.size.height]
afterDelay:0];
}
}
[super orderOut:sender];
}
- (void)setWindowWidth:(NSNumber*)width
{
NSRect startWindowRect = [self frame];
NSRect endWindowRect = NSMakeRect(startWindowRect.origin.x,
startWindowRect.origin.y,
[width doubleValue],
startWindowRect.size.height);
[self setFrame:endWindowRect display:NO animate:NO];
}
- (void)setWindowHeight:(NSNumber*)height
{
NSRect startWindowRect = [self frame];
NSRect endWindowRect = NSMakeRect(startWindowRect.origin.x,
startWindowRect.origin.y,
startWindowRect.size.width,
[height doubleValue]);
[self setFrame:endWindowRect display:NO animate:NO];
}
- (void)resignKeyWindow
{
[self orderOut:self];
[super resignKeyWindow];
}
- (BOOL)canBecomeKeyWindow
{
return YES;
}
- (void)performClose:(id)sender
{
[self close];
}
- (void)dealloc
{
[_wrapperView release], _wrapperView = nil;
[super dealloc];
}
@end
@implementation NSScreen (MenubarScreen)
+ (NSScreen*)menubarScreen
{
NSArray *screens = [self screens];
if ([screens count] > 0) {
return [screens objectAtIndex:0];
}
return nil;
}
@end
这是AutoHidingWindow-滑动窗口的一个子类,当鼠标点击屏幕边缘时弹出。欢迎反馈
@interface ActivationWindow : NSWindow
{
AutoHidingWindow *_activationDelegate;
NSTrackingArea *_trackingArea;
}
- (ActivationWindow*)initWithDelegate:(AutoHidingWindow*)activationDelegate;
@property (assign) AutoHidingWindow *activationDelegate;
@property (retain) NSTrackingArea *trackingArea;
- (void)adjustWindowFrame;
- (void)adjustTrackingArea;
@end
@interface AutoHidingWindow ()
- (void)autoShow;
- (void)autoHide;
@end
@implementation AutoHidingWindow
- (id)initWithContentRect:(NSRect) contentRect
styleMask:(unsigned int) styleMask
backing:(NSBackingStoreType) backingType
defer:(BOOL) flag
{
if ((self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:backingType
defer:flag])) {
_activationWindow = [[ActivationWindow alloc] initWithDelegate:self];
}
return self;
}
@synthesize activationWindow = _activationWindow;
- (void)dealloc
{
[_activationWindow release], _activationWindow = nil;
[super dealloc];
}
- (void)makeKeyAndOrderFront:(id)sender
{
[super makeKeyAndOrderFront:sender];
}
- (void)autoShow
{
[self makeKeyAndOrderFront:self];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(autoHide) object:nil];
[self performSelector:@selector(autoHide) withObject:nil afterDelay:2];
}
- (void)autoHide
{
NSPoint mouseLocation = [NSEvent mouseLocation];
NSRect windowFrame = [self frame];
if (NSPointInRect(mouseLocation, windowFrame)) {
[self performSelector:@selector(autoHide) withObject:nil afterDelay:2];
}
else {
[self orderOut:self];
}
}
@end
@implementation ActivationWindow
- (ActivationWindow*)initWithDelegate:(AutoHidingWindow*)activationDelegate
{
if ((self = [super initWithContentRect:[[NSScreen mainScreen] frame]
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO]) != nil) {
_activationDelegate = activationDelegate;
[self setBackgroundColor:[NSColor clearColor]];
[self setExcludedFromWindowsMenu:YES];
[self setCanHide:NO];
[self setHasShadow:NO];
[self setLevel:NSScreenSaverWindowLevel];
[self setAlphaValue:0.0];
[self setIgnoresMouseEvents:YES];
[self setOpaque:NO];
[self orderFrontRegardless];
[self adjustWindowFrame];
[self.activationDelegate addObserver:self
forKeyPath:@"slidingEdge"
options:0
context:@"slidingEdge"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(screenParametersChanged:)
name:NSApplicationDidChangeScreenParametersNotification
object:nil];
}
return self;
}
@synthesize activationDelegate = _activationDelegate;
@synthesize trackingArea = _trackingArea;
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([@"slidingEdge" isEqual:context]) {
[self adjustTrackingArea];
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self.activationDelegate removeObserver:self forKeyPath:@"slidingEdge"];
_activationDelegate = nil;
[_trackingArea release], _trackingArea = nil;
[super dealloc];
}
- (void)screenParametersChanged:(NSNotification *)notification
{
[self adjustWindowFrame];
}
- (void)adjustWindowFrame
{
NSScreen *mainScreen = [NSScreen mainScreen];
CGFloat menuBarHeight = [NSMenuView menuBarHeight];
NSRect windowFrame = [mainScreen frame];
windowFrame.size.height -= menuBarHeight;
[self setFrame:windowFrame display:NO];
[self adjustTrackingArea];
}
- (void)adjustTrackingArea
{
NSView *contentView = [self contentView];
NSRect trackingRect = contentView.bounds;
CGRectEdge slidingEdge = self.activationDelegate.slidingEdge;
CGFloat trackingRectSize = 2.0;
switch (slidingEdge) {
case CGRectMaxXEdge:
trackingRect.origin.x = trackingRect.origin.x + trackingRect.size.width - trackingRectSize;
trackingRect.size.width = trackingRectSize;
break;
case CGRectMaxYEdge:
trackingRect.origin.y = trackingRect.origin.y + trackingRect.size.height - trackingRectSize;
trackingRect.size.height = trackingRectSize;
break;
case CGRectMinXEdge:
trackingRect.origin.x = 0;
trackingRect.size.width = trackingRectSize;
break;
case CGRectMinYEdge:
default:
trackingRect.origin.y = 0;
trackingRect.size.height = trackingRectSize;
}
NSTrackingAreaOptions options =
NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved |
NSTrackingActiveAlways |
NSTrackingEnabledDuringMouseDrag;
NSTrackingArea *trackingArea = self.trackingArea;
if (trackingArea != nil) {
[contentView removeTrackingArea:trackingArea];
}
trackingArea = [[NSTrackingArea alloc] initWithRect:trackingRect
options:options
owner:self
userInfo:nil];
[contentView addTrackingArea:trackingArea];
self.trackingArea = [trackingArea autorelease];
}
- (void)mouseEntered:(NSEvent *)theEvent
{
[self.activationDelegate autoShow];
}
- (void)mouseMoved:(NSEvent *)theEvent
{
[self.activationDelegate autoShow];
}
- (void)mouseExited:(NSEvent *)theEvent
{
}
@end
这听起来更像是Quicksilver的书架和剪贴板历史记录窗口,以及(可选)Adium的联系人列表,当鼠标点击屏幕边缘时,可以在屏幕一侧弹出。这就是你在想的吗?是的,这就是我在想的。谜题的另一个部分是让窗户实际上弹出。您需要将窗口内容视图的直接子视图放到另一个视图中,并使其成为内容视图。将内容视图中视图的自动调整大小掩码设置为不调整大小,并将其原点固定到内容视图的左边缘(在您的示例中)。要隐藏窗口,请将窗口大小调整为1像素宽。要显示它,请恢复其正确大小。如果希望窗口的大小可以调整,则需要在显示/隐藏窗口后切换视图的自动调整大小掩码。之所以不简单地将窗口移入和移出,是因为用户可能在窗口将移出的区域中有另一个屏幕。然后,您没有隐藏窗口,只是将其移动到另一个屏幕,而不是用户想要的。(至于用户在这种情况下如何显示窗口,用户可以让窗口在小屏幕边缘上下移动,给他一些可以点击的东西。)覆盖窗口的一些东西我忘记了:[self-setHasShadow:NO];和[self-setIgnoresMouseEvents:否];因此,您的不可见窗口实际上不会阻止单击。我99%肯定你仍然会得到鼠标移动事件。为了补充Peter所说的,Cocoa不允许windows完全脱离屏幕。这就是为什么你不能简单地把它滑上滑下。然而,有一个棘手的解决办法。Cocoa在NSWindow的ConstraintFrameRect:toScreen:中执行限制。因此,如果您覆盖此例程,您可以使窗口脱离屏幕。这样做可能更容易,而无需实际调整窗口大小。不确定,谢谢大家的意见。。。我很感激。我注意到我在每个地方都混合了min和max,除了-adjustWrapperView@PierreBernard你在答案中修正了最小值和最大值,还是仍然是向后的。。此外,对于这个
@实现
,没有@接口
,也不清楚需要在其中包含什么…例如,没有定义任何滑动边
,等等@alexgray I现在已经用正确的最小/最大值SCOOL更新了代码。我唯一要注意的是+(NSScreen*)菜单屏幕
的类别。。我想说这是不需要的,因为您可以从文档中简单地调用[NSScreen mainScreen]
,no:“主屏幕不一定是包含菜单栏或其原点位于(0,0)的同一屏幕。主屏幕是指包含当前接收键盘事件的窗口的屏幕。它是主屏幕,因为它是用户最有可能与之交互的屏幕。“此项目发生了什么?链接已断开。”。看不出相关性。