Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.
The preferences window is a standard window, and it is modeless. An application’s preferences window should not be modal because the user may need to use other application windows alongside it in order to understand what settings to enter. Alerts and dialogs can be document-modal sheets or application-modal freestanding panels, but in both cases the user’s access to some features of the application is blocked while the panel is open. You create and use a modeless preferences window just as you’d create and use any standard window.
1. | Leave the archived Recipe 9 project folder in the zip file where it is, and open the working Vermont Recipes subfolder. Increment the version in the Properties pane of the Vermont Recipes target’s information window from 9 to 10 so that the application’s version is displayed in the About window as 2.0.0 (10). |
2. | Use Interface Builder to design and build the user interface of the preferences window. Like most windows, the preferences window should have its own nib file, which you can create from the Xcode File menu. This helps to encapsulate the design of the preferences window, and it makes for more efficient memory use because the application won’t have to load the preferences window if the user doesn’t open it. In Xcode, choose File > New. In the New File dialog, select User Interface in the source list, select Window XIB in the upper-right pane, and click Next. In the next dialog, name the file PreferencesWindow.xib. Make sure that both the Vermont Recipes and Vermont Recipes SL targets are selected, and then click Finish. If necessary, move the new PreferencesWindow.xib file to the Resources group in the Groups & Files pane of the project window, below DiaryPrintPanelAccessoryView.xib. |
3. | Double-click the PreferencesWindow.xib file in Xcode to open it in Interface Builder. Then choose Window > Document Info. In the PreferencesWindow.xib Info window, set the Deployment Target to Mac OS X 10.5 and set the Development Target to Default – Interface Builder 3.2. |
4. | The “Preferences Windows” section of the Apple Human Interface Guidelines (HIG) describes a preferences window as a modeless dialog. It must not be resizable, and its zoom and minimize buttons should be disabled. If it contains a toolbar, the toolbar should not be customizable. The window’s title in the title bar should be the name of the currently selected pane or, if there is only one pane, the name of the application followed by “Preferences.” When the preferences window is closed and reopened, it should reopen to the same pane that was selected when the user closed it, at least while the application remains running. The menu command to open the preferences window must be named Preferences, it must be in the application menu, and it must have a Command-comma keyboard shortcut. When the user makes changes to settings in the preferences window, the changes should take effect immediately, without requiring the user to click an OK or Apply button and without waiting for the user to close the window. You can implement some of these requirements in Interface Builder. In the Window Attributes inspector, deselect the Resize and Minimize checkboxes in the Controls section and the Shows Toolbar Button checkbox in the Appearance section. |
5. | The HIG notes that many applications separate the contents of their preferences windows into separate panes, each representing a functional category selectable by clicking a button in a toolbar. The HIG does not mandate use of a toolbar, however. According to the “Tab Views” section of the HIG, a tab view or a segmented control is acceptable. They allow the same separation into separate panes as a toolbar, but without requiring you to hire an artist to design toolbar items. Furthermore, a tab view or a segmented control looks better than a half-empty toolbar when there are only two or three separate panes. Even if there are many panes, the HIG reluctantly allows you to avoid a toolbar and instead to use a pop-up menu. You use a tab view in Vermont Recipes. In Interface Builder, drag a Tab View object from the Layout Views subsection of the Cocoa Views & Cells section of the Library and drop it in the design surface. Then adjust all four sides so that the edges (including the top edge of the tabs) coincide with the guides that appear as you drag. The HIG allows you to extend the left, bottom, and right edges of a tab view to the edges of the design surface, if you prefer, but you must then leave a margin of at least 20 pixels between the user interface elements in the tab view and the edges of the design surface. The tab view comes with two tabs, but you need three tabs. Select the tab view, and in the Tab View Attributes inspector, change the Tabs field from 2 to 3. Double-click each tab in turn to edit the titles, and name them General, Recipes, and Chef’s Diary, from left to right. Select the tab view, and in the Tab View Connections inspector, drag from the little circle to the right of the delegate outlet to the File’s Owner proxy in the nib file’s document window. You will use an NSTabView delegate method in the next step. |
6. | For the moment, the only user interface elements required in the General pane are two checkboxes to turn on or off the alerts that appear when the user attempts to scale a printed document above 100% or when the application restores an autosaved document. In Recipe 7, you alerted the user when an autosaved Chef’s Diary document was restored. In Recipe 9, you disallowed scaling above 100% when the user prints the Chef’s Diary document, and you alerted the user when an attempt to do that is made. You included the suppression checkbox in both alerts. You will do the same in the similar alerts that you have yet to write for the recipes document. The same principles apply to both documents, so it makes sense to turn all four of these alerts on or off using checkboxes in the application-wide General preferences pane. Some of the panes in the preferences window will have multiple controls relating to differing topics, so take this into account when adding these checkboxes by making it a discrete section of the pane. Start by providing a title for this section. Select the General tab view, and drag a label object from the Inputs & Values subsection of the Library and drop it in the tab view’s content view, positioning it near the left and top edges based on the guides. You can verify that you dropped it in the correct view by clicking it while holding down Shift and Control. You should see a list showing, from top to bottom, the window, its content view, the top tab view, another view, and the new label field. Double-click the label to select it for editing, and enter Alerts. Select the text, and press Command-B to make it bold. Next, drag a checkbox object from the Inputs & Values subsection of the Library and drop it in the tab view’s content view, positioning it below the Alerts label based on the guides. In the Button Attributes inspector, deselect the State checkbox in the Visual section to indicate that, by default, the alert will not be suppressed. Double-click the checkbox to select its text for editing, and name it Don’t show alert when attempting to print larger than 100%. Option-drag the checkbox downward to position a copy and rename it Don’t show alert when restoring from autosaved document (Figure 10.1). Figure 10.1. The General pane of the preferences window.
Leave the section label left aligned in its tab pane, but center the two checkboxes. |
7. | You haven’t done much with the recipes document yet, but in Recipe 7 you did set its standard size. Make the standard size a settable preference for the recipes document now. Select the Recipes tab. Add a label near the top and name it Recipes Window using the same technique you used to add the Alerts label to the General pane. Drag another label below it and name it Standard size:. Drag two text fields and two stepper controls, and lay them out to the right of the Standard size label, arranged on the model of the width and height fields in the Window Size inspector. Drag two more labels and center them immediately below the two text fields, naming them Width and Height, respectively. Finally, drag a push button, name it Use Current Size, and position it below the Width field. You should install a number formatter in the width and height fields to limit the user’s options to reasonable values. Drag number formatter objects from the Formatters subsection of the Library, and drop one in each field. Configure them almost identically. In the Behavior section at the top of the Number Formatter Attributes inspector, choose Mac OS X 10.4+ Custom. Select the Grouping Separator checkbox so that separators (commas in the United States) appear if the user sets the width or height to a really large number. Deselect the Allows Floats checkbox so that the user cannot enter fractional pixels. In the Constraints scrolling view at the bottom of the inspector, set the Maximum to 10000 because the window server limits window sizes to 10,000 pixels in each dimension. The one difference in formatter settings as between the two fields is the Minimum constraint. Set the Minimum to 700 for the Width field and 350 for the Height field. These are the minimum dimensions that you set for the recipes window in Recipe 7. It’s easier to enforce this constraint in the nib file than in code. When the user attempts to enter a value that is less than the minimum, the application will beep when the user attempts to commit the value. Select the Width and Height fields in turn, and in the Text Field Attributes inspector, select the right-aligned button. Select each of the steppers in turn, and in the Stepper Attributes inspector, set the Maximum value to 10000.00 and the Increment to 10.00. Although a stepper doesn’t display a value, it does contain a value, and a stepper increments or decrements its value every time the user clicks the top or bottom arrow. You will use the values of these two steppers in Step 2 to change the values of the corresponding text fields. You will see that it is important to keep the value of each stepper synchronized with its corresponding text field. You set the increment to 10.00 instead of the default 1.00 to speed up the response when the user holds down a stepper arrow for continuous change. Also set the Minimum value in each stepper to the minimum value in the number formatter attached to the associated text field, 700 for width and 350 for height. Leave the section label left aligned, but center the user interface element group (Figure 10.2). Figure 10.2. The Recipes pane of the preferences window.
|
8. | You have done a lot of work with the Chef’s Diary document, so there are several preferences settings to add to the Chef’s Diary pane. Start by setting up a Chef’s Diary Window section that is identical to the Recipes Window section you just set up for the Recipes pane, except for its section label. You can do this by dragging to select all of the user interface elements you just added to the Recipes pane, choosing the Chef’s Diary pane, clicking repeatedly until the view within the top tab view is selected, and then pasting. Reposition the group using the guides, and rename the section label Chef’s Diary Window. Check the values in the number formatters and in the steppers to be sure they are correct, and change the Minimum width and height in the diary window number formatters to 550 and 550, respectively, as you set them in Recipe 7. Also set the Minimum value in each stepper to the minimum value in the number formatter attached to the associated text field, 550 for width and 550 for height. Next, drag a horizontal line object from the Layout Views subsection of the Library, position it below the Chef’s Diary Window section’s user interface elements, and extend its ends to the margins. Below that, add a section label and name it Printing. The settings for this section should be identical to those in the All Print Jobs section of the diary document’s accessory print view. Open the DiaryPrintPanelAccessoryView nib file. Drag to select the two checkbox objects, the radio button object, and the two labels in the All Print Jobs section. Copy them to the clipboard, and then return to the Chef’s Diary pane of the PreferencesWindow nib file and paste them below the section title. Add another horizontal line object; then add a new section label and name it Autosaving. Add a label and a pop-up button from the Inputs & Values subsection of the Library. Enter Autosave documents: for the label. Double-click the pop-up button to open it, and name the first three menu items Every 15 seconds, Every 30 seconds, and Every minute. Option-drag the third menu item twice to create two more menu items, and name them Every 5 minutes and Never. Choose “Every 30 seconds” as the default. This pop-up button is identical to that in the New Document pane of TextEdit’s preferences window. Finally, add a section to the Chef’s Diary pane to select the current Chef’s Diary. If you need to make the preferences window larger, drag its resize control as appropriate; then select the tab view and Command-drag its bottom and right edges as appropriate. Add a horizontal line, and a section label reading Document. Add a label named Current Chef’s Diary: and a text field to its right. You could use a path control here instead of a text field, but I’m old fashioned. Leave the labels and dividers left aligned, but center the user interface elements within the window in accordance with the HIG (Figure 10.3). Figure 10.3. The Chef’s Diary pane of the preferences window.
|
9. | The user interface elements in the preferences window don’t require help tags because their wording and labels are clear. However, you should connect the accessibility titles as appropriate. For the width field at the top of the Recipes pane, for example, Control-drag from the text field to the Width label beneath it and select “accessibility title” in the HUD, and then Control-drag from the width label to the “Standard size” label and repeat the process. Repeat the process with each of the other settings elements that has a title. |
10. | Configure the preferences window’s initial first responder and its key view loop. You learned about the initial first responder and the key view loop in Step 1 of Recipe 4. Remember that you should connect all user interface elements, not just text fields, in the key view loop, in case the user sets Full Keyboard Access to “All controls” in the Keyboard Shortcuts tab of the Keyboard pane in System Preferences. Some conceptual complexity results from the presence of the tab view in the preferences window. Because the tab view is at the top of the window, it should be the window’s first responder. You can’t connect a tab view item to another tab view item as next key view, because you use the arrow keys instead of the tab key to move from one tab view item to another, and Cocoa handles this automatically. However, you should set an initial first responder for each tab view item. The key view loop should form a complete circle among the user interface items within the tab view item, excluding the tab. After the user selects one of the tabs, tabbing within that tab view item then starts with the initial first responder, cycles through all the other user interface items within the tab view item, and returns to the tab before starting the circle again. Start by setting the window’s initial first responder, which should be the tab view. Select the window in Interface Builder by clicking its title bar; then go to the Window Connections inspector. Drag from the little circle beside the initialFirstResponder outlet to any of the tabs in the design surface. The tab view is now the window’s first responder. If you pause a moment while holding the pointer over one of the tabs, that tab view item becomes selected, but the tab view itself is still designated as the window’s first responder. Select the General tab view item by clicking it twice. Go to the Tab View Item Connections inspector and drag from the circle beside the initialFirstReponder outlet to the top checkbox. Then create a complete circle of nextKeyView connections from the top checkbox to the bottom checkbox and from the bottom checkbox back to the top checkbox. Perform the same tasks in the Recipes and Chef’s Diary tab view items, and you’re done. You actually could have skipped the initial first responder and the key view loop entirely, because you laid out the preferences window logically with a strict top-to-bottom and left-to-right orientation, and Cocoa got the key view loop right automatically. You should at least remember to test every window’s key view loop with “All controls” turned on to make sure you’re happy with it. |
11. | |
12. | Select the General tab view, and then save a snapshot. Name it Recipe 10 Step 1, and add a comment saying Created Preferences Window in Interface Builder. |