oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Working With Bitmap Images; Document-Based Application Redux
Pages: 1, 2, 3, 4, 5

IAWindowController and the Interface

NSWindowControllers are responsible for owning and controlling a window. Subclasses can extend this functionality by overriding methods to give the window a custom title, providing a smart, window-zooming mechanism, and other things. As we now know, subclasses of NSWindowController in document-based applications have the additional job of managing the user interface for the document.

With regard to managing the user interface, IAWindowController has two responsibilities. The first is to control an image view in which the document's data is displayed. The second job is to take a user-input zoom setting from an interface control and tell the image view to resize the image accordingly, which is a standard feature in almost every graphics application I know of. So if the user wants to view the image full size he enters 100%, half-size 50%, and so on.

The actual working machinery of the scaling will be implemented by IAImageView -- IAWindowController acts as an intermediary between the UI control and the view. The second responsibility is to get a document's image and set it to be displayed in the image view as part of its initialization.

Before we can do our work in Interface Builder, we need to declare some actions and outlets in IAWindowController from Project Builder. Specifically, we have one action, -changeScale:, and two outlets -- one for the image view and the other for the zoom control. After it's all said and done IAWindowController.h should look like the following:

#import <AppKit/AppKit.h>
@class IAImageView;

@interface IAWindowController : NSWindowController {
    IBOutlet IAImageView *view;
    IBOutlet NSTextField *zoomControl;
- (IBAction)changeScale:(id)sender;


Notice that rather than import the interface to IAImageView, we used Objective-C's @class compiler directive to indicate that IAWindowController is a class. Doing this saves time compiling in larger projects since it's one less file that needs to be imported.

Also, we get rid of any compiler warnings about not knowing what IAImageView is (note that we still need to import IAImageView.h into IAWindowController.m). We could also have done this in MyDocument.h -- adding @class IAWindowController rather than importing the header.

With the interface for IAWindowController set up in Project Builder we can now import it into our nib and build an interface around it. We also need to import IAImageView's interface. Open IAWindow.nib and drag the header files IAWindowController.h and IAImageView.h from Project Builder onto the nib window. We're now set to start working on the interface.

Building the Interface

The way we make connections to the outlets and actions of IAWindowController is to change the class of File's Owner in the nib. Right now its class is set to MyDocument; we'll change this to IAWindowController. This means we're transferring ownership of the nib from MyDocument to IAWindowController. Do this by selecting the File's Owner icon and opening the attributes info panel. Here you can choose IAWindowController from the list, and with that, our outlets and actions from IAWindowController are available for connecting to, by way of File's Owner. Slick.

As part of making IAWindowController File's Owner, we have to make a key connection between the window and File's Owner. Drag a connection from File's Owner to the window icon, and if it's not connected already, make a connection to the outlet window. This effectively makes IAWindowController the owner of the window.

Now delete any text in the window and drag an NSImageView object onto the window. This is found in the upper-left corner of the Cocoa-Others palette, with a picture of a mountain as part of the icon. With the image view in the window, we want to change the border of the view from its current style to the border-less style. We also need to change the scaling behavior from "Proportionally" to "To Fit." This is all done under the attributes info panel. Finally, we change the class of the image view from NSImageView to IAImageView from the custom class panel (Command-5).

The next step is to place the image view within a scroll view. A scroll view is a subclass of NSView that displays another view, but takes care of large contents by providing scroll bars (instances of NSScroller, called scrollers) to display different parts of the interior view, which in this case is our image view. To make the image view a subview of a scroll view we simply select the image view object and then choose Layout --> Make subviews of --> Scroll View.

Notice how the view container is stuck to the bottom left corner of the scroll view. That is because it is assumed the view size will change programmatically, and it is unimportant how it is laid out in IB. We also want to make sure the struts and springs of the scroll view are set up so that the size of the scroll view is flexible when the window is resized, as shown in the image below.

Set the Struts
Set the struts and springs of the scroll view as I have done here.

Finally, add a Zoom: label and text field below the scroll view, and arrange things so they look something like what I have below:

This is how my interface is arranged; make yours similar. The border of the image view is shown just so you know it's there; it should be a border-less image view.

One last thing we want to do before making the connections is to attach a number formatter to the text field. A number formatter is an instance of NSNumberFormatter that defines how numbers will be displayed in a text field. For our zoom control we want a scale percentage to be shown.

Number Formatter

The NSNumberFormatter object in the Cocoa-Others palette.

To attach an NSNumberFormatter to a text field, drag from the Cocoa-Views Palette the object with the dollar sign and an arrow and drop it on top of the text field. This action attaches the formatter to the text field.

To view and modify the options for the formatter select the text field to which it is attached (the only one in the window in our case) and press command-6. This will bring up in the Info panel for the NSNumberFormatter options. In this panel you will find a list of the various ways positive and negative numbers can be formatted. Choose the one which is 100% and -100%.

Formatters are a pretty handy class of objects. All the user needs to do now is type 85 and "85%" is displayed. Formatters are also capable of rounding; if the user input 12.3, then "12%" would show up. Because we configured the formatter wholly in IB, it is something we can experiment with by doing a test run of the interface (command-R).

To finish things up let's make some connections between File's Owner and the interface. Drag a wire from File's Owner to the IAImageView object within the scroll view and connect it to view. Likewise, make a connection from File's Owner to the text field (via the zoomControl outlet), and from the text field to the changeScale: action in File's Owner.

So that's our interface; not much else to it.

Pages: 1, 2, 3, 4, 5

Next Pagearrow