oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Movies and Menus
Pages: 1, 2, 3


As its name implies, the class NSOpenPanel provides us with the standard Open panel for Cocoa applications. Using it is very straightforward, and thus very convenient. We will use an Open panel to allow the user to find a movie to open, and when the user clicks Open we will obtain from the NSOpenPanel object the URL for whichever file was selected by the user.

To run an Open panel, we first have to create an instance of NSOpenPanel using the class method +openPanel. We then use the method -runModalForDirectory:file:types:, which does the job of presenting the user with an Open panel on screen.

This method takes three arguments. The first argument is the directory we want the Open panel to default to when it appears. We will make this argument the home directory of the user, which is easily obtained with the function NSHomeDirectory(). The second argument is a file we want initially selected in the open panel; we'll just make this nil. The third argument is an array of file types that the Open panel will allow the user to select. For our purposes this array will contain strings representing the file types "mov," "mpg," "mp3," and "jpg." In an NSMovieView, you can open any file format supported by QuickTime.

Finally, note that -runModalForDirectory:file:types: returns an integer. This integer return value lets us know which button was pushed. This is analogous to what we've learned about how alert panels and other such devices work.

Let's look at the code for the method openMovie: and see how everything fits together:

- (IBAction)openMovie:(id)sender
  NSArray *fileTypes = [NSArray arrayWithObjects:@"mov", @"mpg", @"mp3", 
  @"jpg", nil];
  NSOpenPanel *oPanel = [NSOpenPanel openPanel];

  int result = [oPanel runModalForDirectory:NSHomeDirectory() file:nil types:fileTypes];
  if (result == NSOKButton) {
	NSArray *movieToOpen = [oPanel URLs];
	NSURL *movieURL = [movieToOpen objectAtIndex:0];

	NSMovie *movie = [[NSMovie alloc] initWithURL:movieURL byReference:NO];
	[movieView setMovie:movie];

We see in the first line that we create an array containing the strings for the file types we will allow the user to open. Note that when we use the NSArray convenience constructor +arrayWithObjects:, the last object to be added to the array must be followed by nil.

In the next line of code all we did was create a new NSOpenPanel object and assign it to the variable oPanel. In the third line, we tell the Open panel to display itself. As we discussed above, we had the panel open to the user's home directory by passing the return value of the function NSHomeDirectory() as the first argument, and then we opted against selecting an initial file, and we passed our fileTypes array as the final argument.

In the next part of the method, we have an if statement that evaluates true if the user clicks on the panel's Open button. What we do in this statement is retrieve from oPanel the file that was selected. We obtain this information by sending oPanel a URLs message, which returns an array of URLs for the selected files (an array is returned to allow for the possibility that the user selected multiple items in the Open panel). In the following line we pick the first object in the array and store it in the NSURL variable movieURL. This is the variable we will pass when we initialize the NSMovie object movie.

Related Reading

Mac OS X: The Missing ManualMac OS X: The Missing Manual
By David Pogue
Table of Contents
Full Description
Sample Chapter

Again, initialize movie by using the initWithURL:byReference: method, passing movieURL as the first argument. The second argument, byReference, is used to indicate whether or not we want to encode certain header information when the NSMovie object is archived. For our purposes here, we won't concern ourselves with this and simply pass NO. Finally, we set the movie view to display movie, and voila! Compile, run, watch some movies! Next we're going to move on to create a somewhat custom controls interface to the movie view.


In this next section, I'm going to discuss how to make menus, and in particular, how to assign a menu as the contextual menu of a view, as well as the Dock menu of the application, both of which are mindless tasks in Interface Builder. The menu we are adding to the application will be simple, consisting of three menu items labeled "Play," "Pause," and "Loop." To support these functions, add to the file Controller.h the following three action method declarations:

  • - (IBAction)playMovie:(id)sender;
  • - (IBAction)pauseMovie:(id)sender;
  • - (IBAction)toggleLoopMode:(id)sender;

Save these changes, and let's go into Interface Builder to build the menu.

In Interface Builder, we want to first make IB aware of the changes we just made to Controller.h -- that is, add these three actions to the Controller class in IB. To do this, select the Controller class from the Classes tab, and choose Read Files from the Classes menu.

This will bring up a dialog asking you which file to read from. Controller.h should be selected as the default. If not, select it and press return (or the Parse button). Assuming none of the existing outlets and actions have changed (and they shouldn't have), the class will automatically update itself to reflect the changes we made to Controller.h in Project Builder. Now we're ready to build the menus.

To create a new menu, simply drag the menu icon from the Cocoa-Menus palette onto Instances tab of the nib window. This will show the default menu, with two menu items. You can edit the attributes of these menu items by selecting on and pressing Command-1 to bring up the Info panel. Change the names of these items from "Item 1" and "Item 2" to "Play" and "Pause."

For "Loop," we need to add a third menu item. In the same Cocoa-Menus palette you will see an object labeled "Item;" drag this onto the menu window just below the "Pause" menu item. Now we're set to make some connections.

As you can imagine, Play will be connected to the action playMovie:, Pause to pauseMovie:, and Loop to toggleLoopMode:. Make these connections by dragging a wire from each menu item onto the Controller instance.

Now we want to make a couple more connections. The first connection will be between the NSMenu instance and the File's Owner object. Drag a wire from File's Owner to the icon labeled NSMenu and a list of File's Owner's outlets will show up. The outlet we want to connect to is dockMenu. We've just enabled our application to make use of a custom dock menu! That easily!

Similarly, drag a wire from the NSMovieView to the NSMenu icon and a list of the movie view's outlets will appear. We want to make a connection to the outlet menu. Doing this will make our little menu a contextual menu for the movie view. Congratulations! We have a contextual menu! Notice that we made the connection here between the menu and the movie view. This means that the menu is the contextual menu only for the movie view and nothing else. So if you Control-click outside of the view, no menu will appear, but if you Control-click on the movie view, this menu will appear. By attaching menus to views, Cocoa lets us have contextual menus customized to each view in the application.

Pages: 1, 2, 3

Next Pagearrow