oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

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

Setting Document File Types in Project Builder

Before we have a functioning image viewer application we have to tell Project Builder what file types are supported by ImageApp. The place for making these changes is under the Targets tab, and within Targets under Application Settings. In this view, scroll down to the section labeled Document Types. Here you will see a table and several text fields for inputting information about document types. The table shows the document types currently supported by the application.

Changing Doc Types
Here is where we change the document types for the application.

Reading the documentation related to NSImage reveals that this class supports a number of image file formats out of the box: JPEG, GIF, PNG, TIFF, PICT, PDF, BMP, EPS, and raw, untagged image data.

Highlight the default entry in the Document Types table and let's make some changes. In the fields below we want to change the name to JPEG -- the name can be anything you like, but it's best to keep it relevant. Under Extensions list the possible file extensions that can be expected for a JPEG. Type in "jpg jpeg JPG JPEG" (with or without the quotes, it doesn't matter). Spaces separate the various extensions.

Now, under OS Types we want to put the four-letter type code for JPEG, which is JPEG. Finally make sure the document class is MyDocument, and the role is Viewer. To commit the changes click on the Change button.

We now want to add entries for the other supported file types, so make the changes shown in the table below for each file type and then click the Add button, rather than the Change button. The role for these types will be Viewer, and the document class will, of course, be MyDocument.

Name Extensions OS Type

The two OS types in quotes are those that have a space at the end. OS types are four-character codes, and the ones for PDF and BMP have a space as their fourth character. We're not going to add support for raw image data, as that would require the user to provide information about the image before it can be displayed, and we don't have an interface set up to do such a thing.

By the way, if you're curious about how you can determine the OS Type for a particular file, Apple provides as part of the developer tools installation a command line utility found in /Developer/Tools called GetFileInfo. When you run this tool with a file name supplied as an argument it will print out information about that file, including the type code -- that's how I determined the type codes in the list above.

When Project Builder compiles an application the information from the Document Types table is put in the file Info.plist, which is found in the Contents directory of your application's bundle. If, after compiling and running your application, you find that you can't open up these file types, try doing a clean build of your project by clicking on the broom icon in the toolbar, and then building your project again. This will delete the old Info.plist and make a new one.

Finally we have an image viewer application. After a quick compile and run you should be able to open up the indicated image file formats and zoom and scroll around.

Before we close shop for the day, I have one last tidbit I would like to add. What we're going to do now is add another feature to our application that will make the user experience a bit more enjoyable. We're going to add some code that will do a type of validation on the scroll bars in the scroll view. Let's go on with this now.

The Scroll Bars

The thing about scroll views is that by default the scroll bars are always present, even if the contents of the scroll view are significantly smaller than the scroll view itself.

Also in Programming with Cocoa

Understanding the NSTableView Class

Inside StYNCies, Part 2

Inside StYNCies

Build an eDoc Reader for Your iPod, Part 3

What we're going to do now is implement some code that will compare the size of the view to the size of the scroll view, and based on that comparison hide or show the scroll bars. This validation will be done in IAImageView, and the name of this method is -validateScrollers. We will invoke this method before doing anything else in -drawRect:. So going back to -drawRect: in IAImageView, we add:

- (void)drawRect:(NSRect)rect {
    [self validateScrollers];
    [super drawRect:rect];

When overriding -drawRect: in a subclass of NSImageView we must be certain to send a similar -drawRect: message to super so the NSImagePart of IAImageView has a chance to render the image.

So the premise of -validateScrollers is easy enough. If the width of the image view's frame is greater than the width of the scroll view, then we show the horizontal scroller. If not, then we hide that scroller. The same goes for the vertical scroller: if the height of the image view's frame is greater than the height of the scroll view's frame, we show the scroller -- if not, we hide the scroller. We can set whether the scroll view has a horizontal or vertical scroller by sending -setHasHorizontalScroller: or -setHasVerticalScroller: messages, respectively, which take BOOL arguments. Let's now take a look at the code:

- (void)validateScrollers
    NSScrollView *scrollView = [[self superview] superview];

    NSSize selfSize = [self frame].size;
    NSSize sViewSize = [scrollView frame].size;
    BOOL hFlag = selfSize.width > sViewSize.width;
    BOOL vFlag = selfSize.height > sViewSize.height;
    [scrollView setHasHorizontalScroller:hFlag];
    [scrollView setHasVerticalScroller:vFlag];

In the first line of this method we access the scroll view by sending a superview message to self (IAImageView), and then another superview message to the view returned by the first superview message to self. What is a superview, you ask? In Cocoa, views within windows are arranged within a spatial hierarchy. That is, a view has one superview, and one or more subviews.

In our application, IAImageView is at the bottom of the hierarchy, and the content view of the window is at the top of the hierarchy. IAImageView's superview is an instance of NSClippingView, whose superview is in turn the scroll view. The superview of the scroll view is the content view of the window.

But that's not the whole story. NSScrollViews, in addition to having an NSClipView as a subview, have NSScrollers, which descend from NSView. So the scroll view has three subviews -- the two scrollers and the clip view. Likewise, the window's content view has two more subviews in addition to the scroll view; they are the two text fields at the bottom of the window that make up our zoom control.

The image below shows a schematic representation of this hierarchy in our document window.

The view hierarchy for our application's window.

So by invoking superview twice, we step up two views from IAImageView in the view hierarchy to retrieve the scroll view.

Moving on with the code, we retrieve the sizes of the frames for the view and the scroll view. In the following two lines we have two BOOL variables, hFlag and vFlag, whose values are the results of the comparisons shown on the right side of the assignment operators.

Essentially, if the width of the view's frame is greater than the width of the scroll view's frame, then hFlag is YES. Likewise for vFlag in the y-direction. These two BOOL variables are then passed as arguments to -setHasHorizontalScroller: and -setHasVerticalScroller:. And that's all there is to it.

By calling [self validateScrollers] in drawRect:, we will have the scrollers appear and hide in real-time whenever the view's contents are redrawn.


Today's column was a long one. Here is the project folder for ImageApp to help you digest this mess of information. I had intended to throw a lot more stuff at you, but as I wrote I realized I had created a monster. In fact, the concept that impelled me to write this app, and that I wanted to write about, now won't see the light of day for another two columns! So while this column had -- in my opinion -- some pretty interesting pearls of wisdom, it was ultimately a foundation for even more interesting things to come.

In the next column you can look forward to implementing a fairly nifty save method, filled with lots of good info about images and image reps. We will also implement some smart, window-zooming behavior, and even printing. So see you next time.

Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.

Return to the Mac DevCenter.