Cocoa Programming for Mac OS X - Aaron Hillegass [39]
Make the window wider and drag an NSTableView onto the window (Figure 6.8).
Figure 6.8. Drop a Table View on the Window
Select the table view so you can look at its attributes in the Inspector. (This may be a bit challenging. The table view is inside the scroll view, and the table view column is inside the table view. Experiment with clicks and double-clicks. You will know that you have selected the table view when the title of the last section of the jump bar is Table View.
In the Inspector, set the Content Type to Cell Based, make the table view have only one column, and disable column selection (Figure 6.9).
Figure 6.9. Inspect the Table View
Double-click on the header of the column to change the title to Voices.
Note that in this chapter’s exercise, we are using a cell-based table view, as it is much simpler to use for trivial tables like this one. We will use view-based tables in Chapter 11.
Make Connections
First, you will set the dataSource outlet of the NSTableView to be the SpeakLineAppDelegate. Select the NSTableView. Control-click in the table view to bring up the Connections panel. Drag from the dataSource outlet to the SpeakLineAppDelegate (Figure 6.10).
Figure 6.10. Set the NS tableView’s dataSource Outlet
If you do not see dataSource in the Inspector, you have selected NSScrollView, not NSTableView inside it. The scroll view is the object that takes care of scrolling and the scroll bars. You will learn more about scroll views in Chapter 17. For now, just click in the interior of the table view until the title of the Connection panel says NSTableView.
Also, set the SpeakLineAppDelegate to be the delegate of the table view.
Now use the Assistant Editor to create an outlet called tableView on SpeakLineAppDelegate and connect it to the table view. Make sure that you have the table view selected and Control-drag to the class declaration in the header file, as done in Chapter 5.
Edit SpeakLineAppDelegate.m
Implement the data source methods in SpeakLineAppDelegate.m:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
return (NSInteger)[_voices count];
}
- (id)tableView:(NSTableView *)tv
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row
{
NSString *v = [_voices objectAtIndex:row];
return v;
}
The identifer for a voice is a long string such as com.apple.speech.synthesis.voice.Fred. If you want just the name Fred, replace the last method with this one:
- (id)tableView:(NSTableView *)tv
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row
{
NSString *v = [_voices objectAtIndex:row];
NSDictionary *dict = [NSSpeechSynthesizer attributesForVoice:v];
return [dict objectForKey:NSVoiceName];
}
(The screenshots in this chapter assume that you’ve done the pretty version.)
Next, build and run the application. Now you get a list of the possible voices, but selecting a voice doesn’t do anything yet.
Besides having a dataSource outlet, a table view has a delegate outlet. The delegate is informed whenever the selection changes. In SpeakLineAppDelegate.m, implement tableViewSelectionDidChange:. (The class NSNotification will be introduced later in this book. For now, just note that you are passed a notification object as an argument to this delegate method.)
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row = [_tableView selectedRow];
if (row == –1) {
return;
}
NSString *selectedVoice = [_voices objectAtIndex:row];
[_speechSynth setVoice:selectedVoice];
NSLog(@"new voice = %@", selectedVoice);
}
The speech synthesizer will not allow you to change the voice while it is speaking, so you should prevent the user from changing the selected row. The table view should be enabled and disabled with speakButton:
- (IBAction)sayIt:(id)sender
{
NSString *string = [_textField stringValue];
if ([string length] == 0) {
return;
}
[_speechSynth startSpeakingString:string];
NSLog(@"Have started to say: %@", string);
[_stopButton setEnabled:YES];