# 6 - Adding a Button in the Window We are now going to add a button inside our window. But first, we need to prepare the ground with a very short introduction to the wonderful `NSView` class. 6.1 A Quick Introduction to Views ------------------------------------------------------------------------------- `NSView` is a class whose objects represent a rectangular area in a window. Each `NSView` has its own internal coordinate system; `NSView` provides a complete framework for managing the rectangle represented by the view, its coordinate system, and for drawing and getting user events inside the view's rectangle. Any object which can be displayed (and/or can accept user events) inside a window (such as a button, a text field, a scroll view, a slider, etc) is actually an instance of a subclass of `NSView`. The specific subclass (for example, `NSButton`) implements a specific way of drawing and managing user events inside the view's rectangle. An unsubclassed `NSView` by default draws nothing and reacts to no user events, even if it contains all the machinery (ready for subclasses to use) to do both. When you create a window, the library automatically creates an `NSView` covering the whole content area of the window. This view is called the window's *content view*. You can replace the default content view (which is transparent and reacts to no user events) with an `NSView` of your choice (which can be an instance of a subclass of `NSView`, such as a `NSButton` or a `NSScrollView`), but you should not change the rectangle it represents, which must always cover the whole window. If you want to have a view which covers only a part of a window, you need to add it as a *subview* of the content view. We will explore subviews in a forth-coming tutorial; in our first example, we will go for the simplest possible solution avoiding use of subviews: we will create a single `NSButton`, make a window to fit exactly our button, and then replace the default window's content view with our button. In this way we'll get a window containing exactly our button. In the next tutorial, we'll learn how to enclose views one over the other in a subview tree, so that we can put more things in a single window. ------------------------------------------------------------------------ 6.2 Creating a Button ------------------------------------------------------------------- Creating a button is quite easy: NSButton *myButton; myButton = AUTORELEASE ([NSButton new]); [myButton setTitle: @"Print Hello!"]; [myButton sizeToFit]; `setTitle:` sets the title (string) to be displayed on the button; `sizeToFit` resizes the button so that it fits the title it is displaying. Next, we need to set target and action of the button: [myButton setTarget: self]; [myButton setAction: @selector (printHello:)]; (`self` will refer to our custom object) ------------------------------------------------------------------------ 6.3 Putting the button in the window ---------------------------------------------------------------------------------- We now need to modify our code to create the window so that it creates a window exactly of the right size to contain our button. First, we need to get the size of the button: NSSize buttonSize; buttonSize = [myButton frame].size; `frame` is a method inherited by `NSView` which returns the rectangle enclosing the button (or, more generally, the rectangle enclosing/represented by an `NSView`). The `origin` of this rectangle is meaningless at this point; it is the `size` (which was set by `sizeToFit`) what we want. Then, we choose for the window a content rect with the `size` of the button, and with an `origin` of our choice; (100, 100) in this example: NSRect rect; rect = NSMakeRect (100, 100, buttonSize.width, buttonSize.height); At this point, we just create the window as before, but using this rectangle (full code below). The last thing to do is then replacing the default window content view with our button: [myWindow setContentView: myButton]; ------------------------------------------------------------------------ 6.4 Source Code ------------------------------------------------------------- We are ready to show the whole source code (the `GNUmakefile` is the usual one): #include #include @interface MyDelegate : NSObject { NSWindow *myWindow; } - (void) printHello: (id)sender; - (void) createMenu; - (void) createWindow; - (void) applicationWillFinishLaunching: (NSNotification *)not; - (void) applicationDidFinishLaunching: (NSNotification *)not; @end @implementation MyDelegate : NSObject - (void) dealloc { RELEASE (myWindow); } - (void) printHello: (id)sender { printf ("Hello!\n"); } - (void) createMenu { NSMenu *menu; menu = AUTORELEASE ([NSMenu new]); [menu addItemWithTitle: @"Quit" action: @selector (terminate:) keyEquivalent: @"q"]; [NSApp setMainMenu: menu]; } - (void) createWindow { NSRect rect; unsigned int styleMask = NSTitledWindowMask | NSMiniaturizableWindowMask; NSButton *myButton; NSSize buttonSize; myButton = AUTORELEASE ([NSButton new]); [myButton setTitle: @"Print Hello!"]; [myButton sizeToFit]; [myButton setTarget: self]; [myButton setAction: @selector (printHello:)]; buttonSize = [myButton frame].size; rect = NSMakeRect (100, 100, buttonSize.width, buttonSize.height); myWindow = [NSWindow alloc]; myWindow = [myWindow initWithContentRect: rect styleMask: styleMask backing: NSBackingStoreBuffered defer: NO]; [myWindow setTitle: @"This is a test window"]; [myWindow setContentView: myButton]; } - (void) applicationWillFinishLaunching: (NSNotification *)not { [self createMenu]; [self createWindow]; } - (void) applicationDidFinishLaunching: (NSNotification *)not; { [myWindow makeKeyAndOrderFront: nil]; } @end int main (int argc, const char **argv) { [NSApplication sharedApplication]; [NSApp setDelegate: [MyDelegate new]]; return NSApplicationMain (argc, argv); } ------------------------------------------------------------------------