web-dev-qa-db-fra.com

créer par programme la fenêtre initiale de l'application cacao (OS X)

Habituellement, je crée une application iOS, mais maintenant j'essaie de créer une application OS X et je suis perdu au tout début. Disons que le style que je crée dans les applications iOS est totalement programmatique. Il n’ya pas de fichiers xib ou autre simplement parce que j’ai beaucoup plus de contrôle en tapant qu’en glissant. Toutefois, dans la programmation OS X, certains fichiers xib contenant les éléments de menu et une fenêtre par défaut commencent. Il y a beaucoup d'éléments dans les éléments de menu, donc ce n'est probablement pas quelque chose que je veux perdre, mais je veux créer par programme ma première fenêtre moi-même.

Alors j'ai fait ça:

- (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];
}

Donc ici, j'ai d'abord créé une fenêtre, et utilisez ce windowController pour lancer cette fenêtre. La fenêtre s’affiche de cette manière, mais je ne peux spécifier que les éléments internes, tels que les boutons et les étiquettes, mais pas dans le windowController. Je me sens mal alors j'ai essayé d'une autre manière.

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

et après cela, je veux définir les autres éléments de la fonction loadWindow: dans windowController comme ceci:

- (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];
}

Malheureusement, cela ne fonctionne jamais. le loadWindow: n'est jamais appelé, ni windowDidLoad:. Où sont-ils allés?

Et s'il vous plaît ne demandez pas pourquoi je n'utilise pas de plumes. Je souhaite créer des vues hautement personnalisées à l'intérieur, éventuellement OpenGL, afin que les nibs ne puissent pas le gérer. Je suis grandement apprécié si quelqu'un pouvait aider. Merci.

Et aussi, qui sait même comment démarrer les éléments de menu à partir de zéro, par programmation?

J'utilise le dernier XCode.

17
wlicpsc

J'ai passé tout un dimanche à m'attaquer à ce problème. À l'instar de la personne qui pose la question, je préfère coder iOS et OSX sans fichiers nib (la plupart du temps) ou Interface Builder et passer à l'état brut. J'utilise NSConstraints cependant. Il ne faut probablement pas éviter l'IB si vous utilisez des interfaces utilisateur plus simples, mais lorsque vous entrez dans une interface plus complexe, cela devient plus difficile.

Cela s’avère assez simple à faire, et pour le bénéfice de la "communauté", j’ai pensé poster une réponse concise et à jour ici. Il existe CERTAINES anciennes publications de blogues et celle que j’ai trouvée la plus utile était celle de Lap Cat Software . 'Tip O The Hat' à vous monsieur!

Cela suppose ARC. Modifiez votre main () pour ressembler à ceci:

#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.
}

Vous noterez qu'il y a toujours un Nib (xib) dedans. Ceci est pour le menu principal seulement. Même s’il s’avère qu’aujourd’hui (2014), il n’est apparemment pas possible de définir facilement l’option de menu position 0. C'est celui avec le titre = au nom de votre application. Vous pouvez tout placer à droite en utilisant [NSApplication setMainMenu] mais pas celui-là. J'ai donc choisi de conserver le Nib MainMenu créé par Xcode dans les nouveaux projets et de le réduire à l'élément de position 0. Je pense que c'est un compromis juste et une chose avec laquelle je peux vivre. Une brève prise pour UI Sanity ... lorsque vous créez des menus, veuillez suivre le même schéma de base que les autres applications Mac OSX .

Ensuite, modifiez AppDelegate pour ressembler à ceci:

-(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
} 

Et Bingo ... vous êtes prêt à partir! Vous pouvez commencer à travailler dans AppDelegate à peu près comme vous le savez bien. J'espère que cela pourra aider!

UPDATE: Je ne crée plus de menus dans le code comme je l’ai montré ci-dessus. J'ai découvert que vous pouvez éditer MainMenu.xib source dans Xcode 6.1. Fonctionne Bien, très flexible et il suffit d’un peu d’expérimentation pour voir comment cela fonctionne. Plus rapide que de déconner en code et facile à localiser! Voir la photo pour comprendre de quoi je parle:

Edit MainMenu.xib

39
Cliff Ribaudo

Voir https://github.com/sindresorhus/touch-bar-simulator/blob/master/Touch%20Bar%20Simulator/main.Swift

En main.Swift

let app = NSApplication.shared()
let delegate = AppDelegate()
app.delegate = delegate
app.run()
3
onmyway133

Swift 4:

// File main.Swift
autoreleasepool {
   // Even if we loading application manually we need to setup `Info.plist` key:
   // <key>NSPrincipalClass</key>
   // <string>NSApplication</string>
   // Otherwise Application will be loaded in `low resolution` mode.
   let app = Application.shared
   app.setActivationPolicy(.regular)
   app.run()
}

// File Application.Swift
public class Application: NSApplication {

   private lazy var mainWindowController = MainWindowController()
   private lazy var mainAppMenu = MainMenu()

   override init() {
      super.init()
      delegate = self
      mainMenu = mainAppMenu
   }

   public required init?(coder: NSCoder) {
      super.init(coder: coder) // This will newer called.
   }

}

extension Application: NSApplicationDelegate {

   public func applicationDidFinishLaunching(_ aNotification: Notification) {
      mainWindowController.showWindow(nil)
   }
}
0
Vlad

Remplacez la méthode -init dans votre classe AppWindowController pour créer la fenêtre, puis appelez la méthode super's -initWithWindow: (qui est l'initialiseur désigné par NSWindowController) avec cette fenêtre.

Mais je suis généralement d’accord avec les commentaires selon lesquels il n’ya aucune raison d’éviter les PNI.

0
Ken Thomases