9
votes

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;
    }
4
Why do you want to do this in the first place? You should generally use Interface Builder to create your application's human interface.Chris Hanson
I'm creating a port of another GUI toolkit.Daniel Furrer
@Chris Hanson: There are MANY reasons to build user interfaces programmatically. To think one should always use Interface Builder is naive. If only I could vote down this inexperienced comment.ctpenrose
@ctpenrose: A comment can't be inexperienced, only a person can. And I'm not inexperienced with Cocoa or Objective-C, or with Mac development for many years before Apple bought NeXT. I've seen, time and again, that developers used to other toolkits (Windows/Java) immediately try to implement their entire UI in code like the OP's question. As I said in general you shouldn't do that, you should just use IB. In cases where it's needed, use code, but be smart about it, don't knee-jerk to it because other platforms' tools suck.Chris Hanson
From what I have experienced reading developer forums, is that comments which try to guess the intention of the developer rather than answer the question, often to fail to add value to the discussion.ctpenrose

4 Answers

9
votes

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.

2
votes

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.

2
votes

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.

0
votes

I spent an entire day looking for answers to the GUI and Menu portion of this question. There are not that many current, concise answers out there to the question. So after solving it for myself, I posted an answer which addresses this on Stack here: Cocoa GUI Programmatically. I add a referral to it here to help community members who are digging around for the same answers.