objective-c - 以编程方式创建 cocoa 应用程序的初始窗口(OS X)

标签 objective-c macos cocoa

通常我正在制作 iOS 应用程序,但现在我正在尝试制作 OS X 应用程序,但我一开始就迷路了。假设我制作 iOS 应用程序的风格完全是程序化的,没有 xib 文件或其他任何东西,只是因为我通过键入比拖动有更多的控制权。然而在 OS X 编程中,它从一些带有菜单项和默认窗口的 xib 文件开始。菜单项中有很多项目,所以我可能不想弄乱这些东西,但我想自己以编程方式创建我的第一个窗口。

所以我这样做了:

- (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 中指定。这让我感觉很糟糕,所以我尝试了另一种方式。

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    _appWindowController = [[AppWindowController alloc] init];
    [_appWindowController showWindow:self];
}

然后我想在 windowController 的 loadWindow: 函数中设置其他元素,如下所示:

- (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: 也不会被调用。他们去哪儿了?

请不要问我为什么不使用 Nib 。我希望在内部制作一些高度自定义的 View ,可能是 OpenGL,所以我认为 nibs 无法处理它。如果有人可以提供帮助,我将不胜感激。谢谢。

而且,谁知道如何以编程方式从头开始菜单项?

我使用的是最新的 Xcode。

最佳答案

我自己花了整个星期天来研究这个问题。就像问这个问题的人一样,我更喜欢在没有 nib 文件(主要是)或 Interface Builder 的情况下编写 iOS 和 OSX 代码,并使用裸机。不过我确实使用 NSConstraints。如果您正在做更简单的 UI,那么避免 IB 可能是不值得的,但是当您进入更复杂的 UI 时,它会变得更难。

结果证明做起来相当简单,为了“社区”的利益,我想我应该在这里发布一个简明的最新答案。那里有一些较旧的博客文章,我发现最有用的一篇来自 Lap Cat Software。 . “Tip O The Hat”给您,先生!

这假设 ARC。将您的 main() 修改为如下所示:

#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 应用程序相同的基本模式

接下来将 AppDelegate 修改为如下所示:

-(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 中工作,就像您熟悉的那样。希望对您有所帮助!

更新:我不再用代码创建菜单,如上所示。我发现您可以在 Xcode 6.1 中编辑 MainMenu.xib 源代码。效果很好,非常灵活,只需要一点点实验就可以知道它是如何工作的。比乱写代码更快,而且易于本地化!查看图片以了解我的意思:

Edit MainMenu.xib

关于objective-c - 以编程方式创建 cocoa 应用程序的初始窗口(OS X),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15694510/

相关文章:

ios - 在特征上设置通知会导致无效句柄错误

linux - mac : using . 配置文件自定义命令

cocoa - 在应用程序加载之前将数据加载到 Cocoa View 中

macos - Cocoa:本地化对话框

python - 使用 Python 在 OSX 上写入 MySQL 的设置更简单

objective-c - 如何获取计算机当前的音量级别?

iphone - 无法使用其他文件中的类的方法

objective-c - 触摸 UIButton 并在 UIView 或 UIViewController 上显示 Unity

ios - 根据 UICollectionView 中的图像动态更改单元格大小

ios - 在 ios8 中使用共享扩展共享图像