以编程方式创建可可应用(OS X)的初始窗口 [英] programmatically create initial window of cocoa app (OS X)
问题描述
通常,我正在制作iOS应用程序,但现在我正在尝试制作OS X应用程序,一开始我迷路了.说我使iOS应用程序完全采用编程风格,没有xib文件或其他任何东西,仅仅是因为我通过打字比拖动拥有更多控制权.但是,在OS X编程中,它从带有菜单项和默认窗口的一些xib文件开始.菜单项中有很多项,因此可能不是我想要弄乱的东西,但我想以编程方式自己创建第一个窗口.
Usually I am making iOS app but now I am trying to make an OS X app, and I am lost at the very beginning. Say the style I make the iOS apps are totally programmatic, there's no xib files or whatsoever just because that I have a lot more control by typing than dragging. However in OS X programming, it starts with some xib files with the menu items and a default window. There are quite a lot of items in the menu items so that's probably not something I want to mess around, but I want to programmatically create my first window myself.
所以我做到了:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSUInteger windowStyleMask = NSTitledWindowMask|NSResizableWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask;
NSWindow* appWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(200, 200, 1280, 720) styleMask:windowStyleMask backing:NSBackingStoreBuffered defer:NO];
appWindow.backgroundColor = [NSColor lightGrayColor];
appWindow.minSize = NSMakeSize(1280, 720);
appWindow.title = @"Sample Window";
[appWindow makeKeyAndOrderFront:self];
_appWindowController = [[AppWindowController alloc] initWithWindow:appWindow];
[_appWindowController showWindow:self];
}
因此,在这里,我首先创建了一个窗口,并使用该windowController来初始化此窗口.窗口确实以这种方式显示,但是我只能指定内部元素,例如此处的按钮和标签,而不能在windowController中指定.这让我感到难过,所以我尝试了另一种方法.
So here, I have created a window first, and use that windowController to init this window. The window does show up in this way, but I can only specify the inner elements, like buttons and labels here, but not in the windowController. It makes me feel bad so I tried another way.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_appWindowController = [[AppWindowController alloc] init];
[_appWindowController showWindow:self];
}
之后,我要像这样在windowController中的loadWindow:
函数中设置其他元素:
and after this I want to set the other elements in the loadWindow:
function in the windowController like this:
- (void)loadWindow
{
[self.window setFrame:NSMakeRect(200, 200, 1280, 720) display:YES];
self.window.title = @"Sample window";
self.window.backgroundColor = [NSColor lightGrayColor];
NSButton* sampleButton = [[NSButton alloc] initWithFrame:NSRectFromCGRect(CGRectMake(100, 100, 200, 23))];
sampleButton.title = @"Sample Button!";
[sampleButton setButtonType:NSMomentaryLightButton];
[sampleButton setBezelStyle:NSRoundedBezelStyle];
[self.window.contentView addSubview:sampleButton];
NSLog(@"Loaded window!");
[self.window makeKeyAndOrderFront:nil];
}
不幸的是,这永远行不通. loadWindow:
从不被调用,windowDidLoad:
也从不被调用.他们去哪了?
Unfortunately, this never works. the loadWindow:
never gets called, nor windowDidLoad:
. Where did they go?
请不要问为什么我不使用笔尖.我希望在内部(可能是OpenGL)制作一些高度自定义的视图,因此我认为笔尖无法处理它.如果有人可以提供帮助,我将不胜感激.谢谢.
And please don't ask why I don't use nibs. I wish to make some highly customized views inside, possibly OpenGL, so I don't think nibs can handle it. I am greatly appreciated if anyone could help. Thanks.
而且,还有谁知道如何以编程方式从头开始菜单项?
And also, who knows how to even start the menu items from scratch, programmatically?
我正在使用最新的XCode.
I am using the latest XCode.
推荐答案
我整个星期天都在自己研究这个问题.就像问这个问题的人一样,我更喜欢在不包含nib文件(大多数情况下)或Interface Builder的情况下对iOS和OSX进行编码,以简化工作.我确实使用NSConstraints.如果您要使用更简单的UI,那么避免IB可能是不值得的,但是,当您进入更复杂的UI时,它会变得越来越困难.
I spent an entire Sunday digging into this problem myself. Like the person asking the question, I prefer coding iOS and OSX without nib files (mostly) or Interface Builder and to go bare metal. I DO use NSConstraints though. It is probably NOT WORTH avoiding IB if you're doing simpler UIs, however when you get into a more complex UI it gets harder.
事实证明,这样做非常简单,为了社区"的利益,我想在这里发布一个简洁的最新答案.有一些较旧的Blog帖子,我发现最有用的是 Lap Cat软件中的博客.先生,给您帽子的提示"!
It turns out to be fairly simple to do, and for the benefit of the "Community" I thought I'd post a concise up to date answer here. There ARE some older Blog Posts out there and the one I found most useful were the ones from Lap Cat Software. 'Tip O The Hat' to you sir!
这假定为ARC.修改您的main()看起来像这样:
This Assumes ARC. Modify your main() to look something like this:
#import <Cocoa/Cocoa.h>
#import "AppDelegate.h"
int main(int argc, const char *argv[])
{
NSArray *tl;
NSApplication *application = [NSApplication sharedApplication];
[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:application topLevelObjects:&tl];
AppDelegate *applicationDelegate = [[AppDelegate alloc] init]; // Instantiate App delegate
[application setDelegate:applicationDelegate]; // Assign delegate to the NSApplication
[application run]; // Call the Apps Run method
return 0; // App Never gets here.
}
您会注意到那里仍然有一个Nib(xib).这仅用于主菜单.事实证明,即使在今天(2014年),显然也无法轻松设置位置0菜单项.那就是标题=您的应用程序名称的那个.您可以使用[NSApplication setMainMenu]
将所有内容都设置在其右侧,但不能使用该设置.因此,我选择将Xcode创建的MainMenu Nib保留在新项目中,并将其剥离到仅位置0的位置.我认为这是一个公平的妥协,我可以接受. 一个简短的UI Sanity插件...在创建菜单时,请遵循与其他Mac OSX Apps相同的基本模式.
You'll note that there is still a Nib (xib) in there. This is for the main menu only. As it turns out even today (2014) apparently no way to easily set the position 0 menu item. That's the one with the title = to your App name. You can set everything to the right of it using [NSApplication setMainMenu]
but not that one. So I opted to keep the MainMenu Nib created by Xcode in new projects, and strip it down to just the position 0 item. I think that is a fair compromise and something I can live with. One brief plug for UI Sanity... when you're creating Menus please follow the same basic pattern as other Mac OSX Apps.
接下来,修改AppDelegate使其类似于以下内容:
Next modify the AppDelegate to look something like this:
-(id)init
{
if(self = [super init]) {
NSRect contentSize = NSMakeRect(500.0, 500.0, 1000.0, 1000.0);
NSUInteger windowStyleMask = NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
window = [[NSWindow alloc] initWithContentRect:contentSize styleMask:windowStyleMask backing:NSBackingStoreBuffered defer:YES];
window.backgroundColor = [NSColor whiteColor];
window.title = @"MyBareMetalApp";
// Setup Preference Menu Action/Target on MainMenu
NSMenu *mm = [NSApp mainMenu];
NSMenuItem *myBareMetalAppItem = [mm itemAtIndex:0];
NSMenu *subMenu = [myBareMetalAppItem submenu];
NSMenuItem *prefMenu = [subMenu itemWithTag:100];
prefMenu.target = self;
prefMenu.action = @selector(showPreferencesMenu:);
// Create a view
view = [[NSTabView alloc] initWithFrame:CGRectMake(0, 0, 700, 700)];
}
return self;
}
-(IBAction)showPreferencesMenu:(id)sender
{
[NSApp runModalForWindow:[[PreferencesWindow alloc] initWithAppFrame:window.frame]];
}
-(void)applicationWillFinishLaunching:(NSNotification *)notification
{
[window setContentView:view]; // Hook the view up to the window
}
-(void)applicationDidFinishLaunching:(NSNotification *)notification
{
[window makeKeyAndOrderFront:self]; // Show the window
}
还有宾果游戏……你很好!就像您熟悉的一样,您可以从那里开始在AppDelegate中工作.希望有帮助!
And Bingo... you're good to go! You can start working from there in the AppDelegate pretty much like you're familiar with. Hope that helps!
更新:如上所述,我不再在代码中创建菜单.我发现您可以在Xcode 6.1中编辑 MainMenu.xib 源.效果很好,非常灵活,只需要做一点试验就可以知道它是如何工作的.比弄乱代码更快,并且易于本地化!看到图片以了解我的意思:
UPDATE: I don't create menus in code anymore as I've shown above. I've discovered you can edit MainMenu.xib source in Xcode 6.1. Works nice, very flexible and all it takes is a little experimentation to see how it works. Faster than messing around in code and easy to localize! See the picture to understand what I am on about:
这篇关于以编程方式创建可可应用(OS X)的初始窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!