views:

1083

answers:

3

I found out how to create a window in Cocoa programmatically but can't figure out how to react to events. The window is not reacting to a Quit request or button click.

I tried adding the following controller and used setDelegate/setTarget without luck:

    @interface AppController : NSObject {
    }
    - (IBAction)doSomething:(id)sender;
    @end

    @implementation AppController
    - (IBAction)doSomething:(id)sender;
    {
        printf("Button clicked!\n");
    }
    @end

    int main(int argc, char **args){
        NSRect frame = NSMakeRect(0, 0, 200, 200);

        AppController *controller = [[AppController alloc] init];

>       [[NSApplication sharedApplication] setDelegate:controller];
        NSWindow* window  = [[NSWindow alloc] initWithContentRect:frame
                                            styleMask:NSBorderlessWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask
                                            backing:NSBackingStoreBuffered
                                            defer:NO];
        [window setBackgroundColor:[NSColor blueColor]];

        NSButton *button = [ [ NSButton alloc ] initWithFrame: NSMakeRect( 30.0, 20.0, 80.0, 50.0 ) ];
        [ button setBezelStyle:NSRoundedBezelStyle];
        [ button setTitle: @"Click" ];
>       [ button setAction:@selector(doSomething:)];
>       [ button setTarget:controller];
        [ [ window contentView ] addSubview: button ];

        [window makeKeyAndOrderFront:NSApp];

        [[NSRunLoop currentRunLoop] run];
        return 0;
    }
+3  A: 

I found out how to create a window in Cocoa programmatically …

Why? Why not just make a nib?

The window is not reacting to a Quit request or button click.

How would you quit a window? This isn't Windows 3; applications can have multiple windows on Mac OS X. As such, closing a window and quitting an application are separate actions.

[[NSRunLoop currentRunLoop] run];

Except in rare circumstances, running the run loop is NSApplication's job, and you should leave that to it. Use NSApplicationMain or -[NSApplication run] to tell the application to run.

Peter Hosey
- I'm porting another GUI toolkit (written in another programming language) to the Mac. So the GUI is very dynamic and I don't think there's a point in having a NIB file.- Quit: Through the application menu- Calling run on the application does the trick, thanks!Thanks.
Daniel Furrer
+3  A: 

You need to invoke -[NSApplication run] instead of -[[NSRunLoop currentRunLoop] run]. The reason should be clear if you look at the basic structure of the method:

- (void)run
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    [self finishLaunching];

    shouldKeepRunning = YES;
    do
    {
        [pool release];
        pool = [[NSAutoreleasePool alloc] init];

        NSEvent *event =
            [self
                nextEventMatchingMask:NSAnyEventMask
                untilDate:[NSDate distantFuture]
                inMode:NSDefaultRunLoopMode
                dequeue:YES];

        [self sendEvent:event];
        [self updateWindows];
    } while (shouldKeepRunning);

    [pool release];
}

NSApplication encapsulates a lot about how to get an event, how to dispatch them and how to update windows.

Matt Gallagher
Nice, thanks. That solves my problem. Where did you get this source code from?So it seems that I can even implement my own run loop somewhere and use this provided logic.
Daniel Furrer
I created this code for my blog post: http://cocoawithlove.com/2009/01/demystifying-nsapplication-by.htmlI reconstructed this method by reading the documentation for NSApplication closely and guessing at all implied steps until it worked.
Matt Gallagher
A: 

Excellent question. I think Matt Gallagher answered it already, but if you want to go further with this, you'll have to delve into Apple's event-handling documentation. Bear in mind that doing everything programmatically will require a solid understanding of cocoa fundamentals.

e.James