it-swarm.com.de

programmgesteuertes Erstellen des ersten Fensters der Kakao-App (OS X)

Normalerweise erstelle ich eine iOS-App, aber jetzt versuche ich, eine OS X-App zu erstellen, und ich bin ganz am Anfang verloren. Angenommen, der Stil, den ich für iOS-Apps verwende, ist völlig programmatisch, es gibt keine xib-Dateien oder was auch immer, nur weil ich beim Tippen viel mehr Kontrolle habe als beim Ziehen. Bei der OS X-Programmierung werden jedoch zunächst einige xib-Dateien mit den Menüelementen und einem Standardfenster erstellt. Es gibt eine ganze Reihe von Elementen in den Menüelementen, daher möchte ich wahrscheinlich nicht herumspielen, sondern mein erstes Fenster programmgesteuert selbst erstellen.

Also habe ich das gemacht:

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

Deshalb habe ich hier zuerst ein Fenster erstellt und benutze diesen windowController, um dieses Fenster zu initialisieren. Das Fenster wird auf diese Weise angezeigt, aber ich kann hier nur die inneren Elemente wie Schaltflächen und Beschriftungen angeben, nicht jedoch im windowController. Ich fühle mich schlecht, also habe ich es anders versucht.

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

und danach möchte ich die anderen Elemente in der Funktion loadWindow: im windowController so einstellen:

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

Das funktioniert leider nie. Der loadWindow: wird niemals aufgerufen, noch der windowDidLoad:. Wohin sind sie gegangen?

Und bitte frag nicht, warum ich keine Federn benutze. Ich möchte einige hochgradig angepasste Ansichten erstellen, möglicherweise OpenGL, sodass ich nicht glaube, dass Nibs damit umgehen können. Ich bin sehr dankbar, wenn jemand helfen könnte. Vielen Dank.

Und wer weiß, wie man die Menüelemente programmgesteuert von Grund auf neu startet?

Ich verwende den neuesten XCode.

17
wlicpsc

Ich habe einen ganzen Sonntag damit verbracht, mich selbst mit diesem Problem zu befassen. Wie die Person, die die Frage stellt, ziehe ich es vor, iOS und OSX (meistens) ohne nib-Dateien oder Interface Builder zu codieren und auf Bare Metal zu gehen. Ich benutze allerdings NSConstraints. Es ist wahrscheinlich NICHT WERT, IB zu vermeiden, wenn Sie einfachere Benutzeroberflächen verwenden. Wenn Sie jedoch eine komplexere Benutzeroberfläche verwenden, wird es schwieriger.

Es stellt sich als ziemlich einfach heraus, und zum Wohle der "Community" dachte ich, ich würde hier eine kurze, aktuelle Antwort veröffentlichen. Es gibt einige ältere Blog-Posts, und die, die ich am nützlichsten fand, waren die von Lap Cat Software . "Tip O The Hat" für Sie, Sir!

Dies setzt ARC voraus. Ändern Sie Ihr main () so, dass es ungefähr so ​​aussieht:

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

Sie werden feststellen, dass sich noch eine Feder (xib) darin befindet. Dies ist nur für das Hauptmenü. Wie sich auch heute (2014) herausstellt, lässt sich der Menüpunkt Position 0 scheinbar nicht einfach einstellen. Das ist diejenige mit dem Titel = zu Ihrem App-Namen. Sie können alles rechts davon mit [NSApplication setMainMenu] einstellen, aber nicht mit diesem. Daher habe ich mich dafür entschieden, die von Xcode erstellte Hauptmenü-Schreibfeder in neuen Projekten beizubehalten und sie auf Position 0 zu reduzieren. Ich denke, das ist ein fairer Kompromiss, mit dem ich leben kann. Ein kurzer Plug für UI Sanity ... beim Erstellen von Menüs folgen Sie bitte dem gleichen Grundmuster wie bei anderen Mac OSX Apps .

Ändern Sie als Nächstes das AppDelegate so, dass es ungefähr so ​​aussieht:

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

Und Bingo ... Sie können loslegen! Sie können von dort aus in AppDelegate arbeiten, so wie Sie es gewohnt sind. Hoffentlich hilft das!

UPDATE: Ich erstelle keine Menüs mehr im Code, wie ich oben gezeigt habe. Ich habe festgestellt, dass Sie MainMenu.xib source in Xcode 6.1 bearbeiten können. Funktioniert gut, sehr flexibel und man muss nur ein wenig experimentieren, um zu sehen, wie es funktioniert. Schneller als im Code herumzuspielen und einfach zu lokalisieren! Sehen Sie sich das Bild an, um zu verstehen, worum es mir geht:

Edit MainMenu.xib

39
Cliff Ribaudo

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

In main.Swift

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

Schnell 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

Überschreiben Sie die -init -Methode in Ihrer AppWindowController -Klasse, um das Fenster zu erstellen, und rufen Sie dann die -initWithWindow: -Methode von super (die vom NSWindowController als Initialisierer bezeichnet wird) mit diesem Fenster auf.

Generell stimme ich den Kommentaren zu, dass es wenig Grund gibt, NIBs zu meiden.

0
Ken Thomases