我花了相当多的实验来澄清对Objective-C的"ModalForWindow"语言的一些混淆,以及随后如何使用模态会话.也许以下提示可以节省一些时间:
(如果您不熟悉这个概念:当一个窗口,通常是一个面板,运行模态时,它会阻止应用程序的其他部分响应,直到它被解除.)
"ModalForWindow"在不同的情况下意味着不同的东西.如果您使用loadNibNamed显示由xib定义的面板并且您希望它运行modal,请在显示后调用它:
// Make panelReviewImports modal, so that no other part of app will respond.
[[NSApplication sharedApplication] runModalForWindow:self.panelReviewImports];
Run Code Online (Sandbox Code Playgroud)
并在其解雇方法中采取以下措施:
[[NSApplication sharedApplication] stopModal];
Run Code Online (Sandbox Code Playgroud)
但对于NSAlert,beginSheetModalForWindow中的"窗口"指的是警报将作为工作表附加到的窗口,该窗口将被冻结,直到警报被解除.但该应用程序不会被冻结; 所有其他窗户将保持可操作性.如果您要附加警告如纸和也 明确冻结的应用程序的其余部分,按照beginSheet代码用一个简单的调用runModal并使用返回代码,如下所示:
[alert beginSheetModalForWindow:self.window
modalDelegate:self didEndSelector:@selector(abandonmentAlertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
NSInteger returnCode = [alert runModal];
[self abandonmentAlertDidEnd:alert returnCode:returnCode contextInfo:nil];
Run Code Online (Sandbox Code Playgroud)
(当然,您将实现了abandonmentAlertDidEnd:returnCode:contextInfo:代码作为类方法.)
或者,如果您希望警报作为居中面板运行,请自行调用runModal.
假设您要运行面板模式,如果用户提交无效条目,则后跟警报.在显示警报之前,您必须先停止模式 - 之后,由于某种原因,另一次调用runModalForWindow无法正常工作.对于此场景,您需要一个模态会话:
1)将NSModalSession属性添加到控制器类,因为modalSession必须可以跨多个方法访问.
2)显示面板后,调用beginModalSessionForWindow来实例化modalSession:
self.modalSession = [[NSApplication sharedApplication] beginModalSessionForWindow:self.panelForInput];
Run Code Online (Sandbox Code Playgroud)
3)使用调用runModalSession的while循环进行跟进,当它的返回值不等于NSRunContinuesResponse时断开:
while ([[NSApplication sharedApplication] runModalSession:self.modalSession] == NSRunContinuesResponse)
continue;
Run Code Online (Sandbox Code Playgroud)
循环将中断,当用户点击其中一个面板按钮时,应用程序将释放.(在面板的文本字段中输入将使模态会话保持不变.)
4)在按钮处理中,如果用户的条目无效,则使用runModal调用警报.
5)紧接警报调用之后,在解除警报后将执行的代码中,您将上面使用的相同的while循环置于其中.小组的模态会话重新开始.
6)在关闭面板的处理中,无论是在有效输入还是取消时,都会调用endModalSession,奇怪的是,这是不够的; 你也必须调用stopModal,即使你从未调用runModalForWindow.
[[NSApplication sharedApplication] endModalSession:self.modalSession];
[[NSApplication sharedApplication] stopModal];
[self.panelForInput close];
Run Code Online (Sandbox Code Playgroud) 我在XCode 4.6中创建了一个简单的Cocoa-Application,NSPanel而不是默认的NSWindow.当我启用非激活选项并启动应用程序时一切正常:
面板显示在其他所有内容之前,当鼠标光标悬停在面板边缘时,它会从正常的箭头光标变为适当的调整大小光标,因此用户知道他可以调整面板的大小.
这可以正常工作,因为我没有点击任何其他应用程序,例如Safari或Finder.
从我曾经把焦点放到另一个应用程序的那一刻起,我可以点击并将鼠标悬停在我的面板上,光标样式将不会再改变 - 它始终保持箭头状态,并且无法恢复正常行为.
面板保持可选,在前面,您仍然可以移动并调整其大小,但鼠标光标始终保持箭头状态.然后,您甚至无法使用以下内容手动更改它:[[NSCursor crosshairCursor] set].
所以我需要找到一种方法来创建一个NSPanel保持正常自动更改 - cursorstyle - 当悬停在面板边缘 - 行为时,即使您将焦点放在另一个应用程序上.
我已经尝试使用自定义的NSPanel类,我已经覆盖了 canBecomeKeyWindow和
canBecomeMainWindow方法,所以他们返回YES但即使我制作我的Panel KeyWindow和MainWindow...
[myPanel makeKeyAndOrderFront:self];
[myPanel makeMainWindow];
Run Code Online (Sandbox Code Playgroud)
...它无法解决游标问题.
如果有人能在这里帮助我会很棒:)
PS.:在我的项目中,Base SDK和Deployment Target设置为10.8
所以我发现所描述的问题与面板的窗口状态无关.如果将其设置为key或main,则无关紧要,而是游标问题(始终保持箭头)与应用程序的激活状态相关.
只要拥有该面板的应用程序处于活动状态,但是如果您单击另一个应用程序,我的应用程序将被停用并且不会再次激活 - 即使您单击该面板 - 因为non-activating启用了" " 选项,所以一切正常.
问题是我需要" - 选项 - non activating因为我正在创建一个状态栏屏幕捕获应用程序,应该显示并在其他所有操作之前运行,但不会停用任何正在运行的应用程序.我可以解决光标问题
[NSApp activateIgnoringOtherApps];
但随后拍摄在Safari中运行的全屏视频的屏幕截图会停用Safari并最小化视频,这是我不想要的.
所以我以为我已经覆盖了我的基地,但显然我错过了关键的一两步.
makeKeyAndOrderFront:当按下NSStatusItem时,我有一个显示()的NSPanel.事情很有效,但是当NSPanel显示标题栏时,面板也可以拖动.(这是不受欢迎的.)
第一个屏幕截图显示了在"外观"类别中在Interface Builder中启用"标题栏"的面板.(抱歉模糊不清,现在仍然处于锁定和关键状态.)

该只说是在Interface Builder中做出更改取消选中"标题栏"复选框.然后我保存并重新运行,这就是你在第二个屏幕截图中看到的内容.虽然出现轻微阴影,但面板却没有.

我试过的事情:
我子类的NSPanel并返回YES了canBecomeKeyWindow和canBecomeMainWindow一些调查后,但(前子类)都返回这些方法NO无论我是否使用了标题栏或不是.所以我认为这不是问题所在.
我确保NSPanel的框架设置正确.它有一个很好的高度,原点也设置正确.
编辑:忘记提及:
该应用程序是一个仅菜单栏的应用程序.在下面的屏幕截图中,请注意添加了一个附加条目Info.plist以强制执行此操作.

当用户按下我的主视图时,我需要以编程方式创建一个类似HUD的窗口.这是我使用的代码,但我只得到一个标准窗口.
videoWindow= [[NSPanel alloc]
initWithContentRect:NSMakeRect(200.0, 200.0, 300, 200)
styleMask:NSTitledWindowMask | NSClosableWindowMask
backing:NSBackingStoreBuffered defer:YES];
[videoWindow makeKeyAndOrderFront:nil];
Run Code Online (Sandbox Code Playgroud)
也许我没有使用正确的标志,但我没有在文档或Google上找到.有什么想法吗?
是否可以在NSPanel第一响应者状态内提供NSView而不提供NSPanel密钥窗口状态(使主应用程序窗口重新签名)?
谢谢.
我正在制作截图Mac应用程序.我正在尝试重建按下Cmd-Ctrl-Shift-4时发生的情况:十字线光标和屏幕截图的选择矩形.
我在所有其他窗户上使用自定义无边框NSWindow.我禁用光标以绘制自己的选择矩形.
我的问题是,只要我点击并拖动以捕获屏幕截图,我的应用就会被激活(因为我的屏蔽窗口拦截了点击).
有没有办法在我的自定义视图/窗口中接收点击而不启动我的应用程序?
我尝试使用NSPanel带有NSNonactivatingPanelMask标志的,但在这种情况下,我有光标问题:当另一个应用程序处于活动状态时,我无法绘制自己的,因为我无法隐藏其他应用程序的光标...
Apple提供了创建PDF文档的示例代码.但它使用CFURLRef
NSPanel savepanel提供NSURL.
我无法将NSURL转换为CFURLRef
path = CFStringCreateWithCString (NULL, filename, kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0);
NSLog(@"CFURLRef %@",url);
Run Code Online (Sandbox Code Playgroud)
输出是
2016-04-22 00:34:26.648 XXX分析[12242:813106] CFURLRef AnalysisReport.pdf - file:///Users/xxxxxx/Library/Containers/com.xxxxxx.xxxnalysis/Data/
转换我找到的代码
url = (__bridge CFURLRef)theFile;
NSLog(@"NSURL %@",url);
Run Code Online (Sandbox Code Playgroud)
输出是
2016-04-22 00:37:20.494 XXX分析[12325:816505] NSURL文件:///Users/xxxxxx/Documents/xxxnalysis.pdf
最后保存PDF文件但NSPanel关闭时程序崩溃.
我正在尝试添加一个小窗口,从系统中的任何位置向主应用程序提供"快速输入".
用户可以点击热键,窗口弹出,并漂浮在所有其他窗口之上.
在大多数情况下,这不是一个问题.我可以将NSWindow配置为:
level = Int(CGWindowLevelKey.TornOffMenuWindowLevelKey.rawValue)
collectionBehavior = .CanJoinAllSpaces
Run Code Online (Sandbox Code Playgroud)
我也可以使用NSNonactivatingPanelMask选项集作为NSPanel .
唯一的问题是:即使用户位于包含全屏应用程序的空间,我怎样才能使窗口弹出窗口?
我知道当应用程序LSUIElement=true(在Dock中没有位置的应用程序)时这是可能的,但我的不是.
在过去,我可以在Interface Builder的库中找到Panel,但是在Xcode 8中,我在storyboard编辑器中搜索了整个库,没有可用的Panel.苹果公司刚刚搬走了,NSPanel或者我弄错了什么?
我有一个app winth一个窗口和一个面板,附在这个窗口上.
脚步:
如何从面板设置焦点到主窗口(父窗口)?
nspanel ×10
cocoa ×8
nswindow ×5
objective-c ×4
macos ×3
cursor ×1
focus ×1
modal-dialog ×1
nsalert ×1
nsresponder ×1
nssavepanel ×1
nsurl ×1
nsview ×1
screenshot ×1
storyboard ×1
xcode ×1
xib ×1