Chapter 25. Sheets

Chapter 25. Sheets

A sheet is simply an NSWindow instance that is attached to another window. The sheet comes down over the window, and the window stops getting events until the sheet is dismissed. Typically, you will compose a sheet as an offscreen window in your nib file.

NSApplication has several methods that make sheets possible:

// Start a sheet
- (void)beginSheet:(NSWindow *)sheet
    modalForWindow:(NSWindow *)docWindow
     modalDelegate:(id)modalDelegate
    didEndSelector:(SEL)didEndSelector
       contextInfo:(void *)contextInfo;

// End the sheet
- (void)endSheet:(NSWindow *)sheet returnCode:(int)returnCode;

Besides the sheet window and the window to which it is attached, you supply a modal delegate, a selector, and a pointer when you start the sheet. The modalDelegate will be sent the didEndSelector, and the sheet, its return code, and the contextInfo will be sent as arguments. Thus, the method triggered by thedidEndSelector should have a signature like this:

- (void)rex:(NSWindow *)sheet
       fido:(int)returnCode
      rover:(void *)contextInfo;

The dog names are used here to indicate that you could name the method anything you wish. Most programmers name the method something more meaningful, such assheetDidEnd:returnCode:contextInfo:.

Adding a Sheet

You are going to add a sheet that will allow the user to adjust the speed of the TypingTutor application. You will bring up the sheet when the user selects the Adjust speed... menu item. You will end the sheet when the user clicks the OK button. The final application will look like Figure 25.1.

Figure 25.1. Completed Application

Your AppController will control the slider and the window, so you will need to add outlets for them. Also, your AppController will be sent a message when the user selects the Adjust speed... menu item or clicks theOK button, so you will need to add two action methods to the AppController.

Figure 25.2 presents the object diagram.

Figure 25.2. Object Diagram


Add Outlets and Actions

Edit AppController.h as follows:

#import <Cocoa/Cocoa.h>
@class BigLetterView;

@interface AppController : NSObject
{
    // Outlets
    IBOutlet BigLetterView *inLetterView;
    IBOutlet BigLetterView *outLetterView;
    IBOutlet NSWindow *speedSheet;
 
 
    // Data
    NSArray *letters;
    int lastIndex;

    // Time
    NSTimer *timer;
    int count;
    int stepSize;
}
- (IBAction)stopGo:(id)sender;
- (IBAction)showSpeedSheet:(id)sender;
- (IBAction)endSpeedSheet:(id)sender;
- (void)incrementCount;
- (void)resetCount;
- (void)showAnotherLetter;
 
 
@end
					  

Save the file.

Lay Out the Interface

Open MainMenu.nib. Add a menu item to the main menu for your application by dragging it out of theLibrary (under Application -> Menus) (Figure 25.3).

Figure 25.3. Add a Menu Item


Change the title of the menu item to Adjust Speed.... Control-drag from the menu item to theAppController. Set the action to be showSpeedSheet: (Figure 25.4).

Figure 25.4. Connect the Menu Item


Create a new window by dragging one out of the Library (under Application -> Windows). Disable resizing for the window; make it not Visible at launch (Figure 25.5)

Figure 25.5. Inspect New Window

Put a slider on the new window. To label the left end of the slider as Slow and the right end as Fast, drop two uneditable text fields onto the window. Add a button and change its title to OK. Inspect the slider, and set its range to be 1 to 10 (Figure 25.6).

Figure 25.6. Inspect Slider


Bind the Value of the slider to the AppController's stepSize, as shown in Figure 25.7.

Figure 25.7. Bind the Slider's Value to stepSize

When the user clicks the OK button, it should send the AppController a message that will end the sheet. Control-drag from the button to the AppController, and choose endSpeedSheet: as the action (Figure 25.8).

Figure 25.8. Set the target of the Button


To raise the window as a sheet, your AppController must have a pointer to it. Control-click on theAppController to get the Connection panel. Connect the speedSheet outlet to the window (Figure 25.9).

Figure 25.9. Connect speedSheet Outlet

Save and close the nib file.

Add Code

In AppController.m, you defined a constant called COUNT_STEP. In the last section, the user went from 0 to 100 in steps of 5. In this section, you will make the step size a variable. If playing Fast, the user will get bigger steps than if playing Slow. The step size is bound to the slider.

In AppController.m, delete the line that says #define COUNT_STEP (5).

In the init method, initialize stepSize to be 5:

- (id)init
{
    [super init];

    // Create an array of letters
    letters = [[NSArray alloc] initWithObjects:@"a", @"s",
                     @"d",@"f", @"j", @"k", @"l", @";",nil];

    // Seed the random number generator
    srandom(time(NULL));
    stepSize = 5;
    return self;
}

In incrementCount, replace COUNT_STEP with stepSize:

- (void)incrementCount
{
    [self willChangeValueForKey:@"count"];
    count = count + stepSize;
    if (count > MAX_COUNT) {
        count = MAX_COUNT;
    }
    [self didChangeValueForKey:@"count"];
}

When the user chooses the Adjust Speed... menu item, the sheet will run. Add the following method toAppController.m:

- (IBAction)showSpeedSheet:(id)sender
{
    [NSApp beginSheet:speedSheet
       modalForWindow:[inLetterView window]
        modalDelegate:nil
       didEndSelector:NULL
          contextInfo:NULL];
}

Note that you are attaching the sheet to the window that the inLetterView is on. Also, when the sheet is dismissed, you will not get any sort of callback.

The sheet will end when the user clicks the OK button. Add the following method to AppController.m:

- (IBAction)endSpeedSheet:(id)sender
{
  // Return to normal event handling
  [NSApp endSheet:speedSheet];

  // Hide the sheet
  [speedSheet orderOut:sender];

}

Build and run your application. Bring up the sheet, adjust the speed, and dismiss the sheet.

For the More Curious: Modal Windows

When a sheet is active, the user is prevented from sending events to the window to which it is attached. When an Alert panel is run, it is modal—that is, the user is prevented from sending events to any other window.

To make a window modal, use the following method of NSApp:

- (int)runModalForWindow:(NSWindow *)aWindow

Only events destined for aWindow will make it through this method. When you are ready to make theaWindow nonmodal, send this message to the NSApplication object:

- (void)stopModalWithCode:(int)returnCode

At that point, runModalForWindow: will end and return returnCode.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值