Tab Controls

The tab control provides a convenient way to present information in a multipage format. Figure 14.6 shows two tabs centered horizontally in a window. The content area below a tab is called a pane. Panes are often used to organize settings for a utility program or control panel. When panes are used in combination with tabs, users can see, at a glance, all the categories of settings or features available. Tabs allow users to quickly switch from one pane to another with a single click.

As shown in the figure, you can use other controls, such as push buttons, radio buttons, and text fields, in a tabbed window. The controls can be global—affecting the settings of all panes—or specific to an individual pane. Make it clear through labeling and placement (within or outside of a tab pane’s boundary, for example) whether a control affects one pane or all panes. In the figure shown, the Quit button is outside the pane area, so it’s available regardless of which pane is visible.

A tab control with two tabs

Figure 14-6. A tab control with two tabs

When the user clicks a tab, the pane should switch appropriately. For example, when the user clicks the Itinerary tab, the Travel Time pane should disappear and the Itinerary pane should appear, as shown in Figure 14.7. Although it appears to the user as if the pane and the tab are one, you must implement this illusion in your code, because the tab and the pane operate independently. Each tab must be paired with a pane. When the user clicks a tab, your code must switch the tab view, make the appropriate pane visible, and make sure all other panes are hidden. (You’ll see how to do this in Section 14.3.3.)

The Itinerary pane appears when the user click the Itinerary tab

Figure 14-7. The Itinerary pane appears when the user click the Itinerary tab

Besides coordinating tabs with panes, the other tricky aspect of tab controls is adding items to a pane. When you add items, you need to make sure you are actually adding them to the appropriate pane. It’s easy to either add the items to the wrong pane or simply add an item to the window, but not associate the item with a pane. If you do either of these, when you run your application you’ll see misplaced items or items that persist from pane to pane. We’ll show you how to avoid this in the example that follows.

You’ll add tabs to an interface by doing the following:

  1. Add a tab control to a window

  2. Add controls to a user pane

  3. Write a handler for a tab control and panes

Add a Tab Control to a Window

Adding a tab control using Interface Builder is fairly straightforward. You’ll start with a window and add a tab data view that has two tabs. You can add more if you’d like, but we’ll stick to two for the purpose of showing you how to do it:

  1. Drag a tab control (shown in Figure 14.8) from the DataViews palette in Interface Builder to a window.

    The tab control on the DataViews palette

    Figure 14-8. The tab control on the DataViews palette

  2. Resize the tab control by dragging its corner until it fits the Aqua guides, as shown in Figure 14.9.

    Use the Aqua guides to size the tab control

    Figure 14-9. Use the Aqua guides to size the tab control

  3. Use the Show Info window to set the number of tabs and tab orientation. Click the middle of the tab view, then choose Show Info from the Tools menu. The Tab Info window should open. You’ll keep the default values: 2 as the number of tabs, and North as the tab direction.

  4. Assign the tab control an ID and a signature. The ID must be an 8-bit value; use the application’s creator code as the signature. You’ll need these when you write a handler to switch tabs. Choose Control from the pop-up menu. In the Control ID box, type MTPP for the signature and 128 for the ID.

  5. Double-click the tab labeled One to make the tab and its pane editable. The Info window should now be titled Tab Item Info and you should see a thick line around the pane, as shown in Figure 14.10.

  6. Use the Attributes pane of the Tab Item Info window to name the tabs. For each tab, type the name in the Label text field, as shown in the example for the Travel Time tab in Figure 14.10. Type Travel Time for tab One and Itinerary for tab Two.

    The thick line indicates you are editing the pane and tab shown

    Figure 14-10. The thick line indicates you are editing the pane and tab shown

  7. Assign a User Pane Signature and User Pane ID to each tab item. The User Pane Signature for each tab item should be the same as that assigned to the tab—the application’s creator code. Type MTPP in the User Pane Signature text field. The IDs should be sequentially assigned, using the ID you assigned to the tab (128) as the basis. Type 129 in the User Pane ID field for the Travel Time tab item and 130 for the Itinerary tab item.

Add Controls to a User Pane

The procedures for adding controls to a user pane are the same as those you used in Chapter 5 to add controls to a window. The only difference is that you must make sure the pane to which you want to add controls is in edit mode and is in front of the other panes.

Before you add a control, double-click the tab associated with the pane to which you want to add a control. Make sure the user pane is editable—the tab you clicked should be active and a thick line should appear around the pane. Then, you can drag controls to the pane as you would to a window.

Write a Handler for the Tab Controls and Panes

You need to write a handler that switches the frontmost tab in response to a user click on a tab and then shows the appropriate pane while hiding the others. First, you’ll need to declare the constant that represents the IDs you assigned to the tab control and tab items when you set them up in Interface Builder. First, define constants to represent the tab ID:

#define        TAB_ID       128;

Next, set up an array—a tab list—to specify the number of tabs and the ID of each tab. The first item in the array is 2 because you set up two tab items. Recall you assigned 129 and 130 as the tab item IDs. The variable lastTabIndex is a housekeeping variable you’ll use to keep track of the last tab chosen by the user. You’ll set the starting value at 1:

int         tabList[] = {2, 129, 130}; 
int         lastTabIndex = 1;

You’ll need to declare the tab handler (MyTabEventHandler) and the function (MySwitchItemOfTabControl) that switches from one pane to another. Here are the function declarations for each:

pascal OSStatus MyTabEventHandler (EventHandlerCallRef inHandlerRef, 
                        EventRef inEvent, void *inUserData);
void MySwitchItemOfTabControl (int index, ControlRef tabControl);

In your main function, you install an event handler for the tab control. You’ll use the InstallEventHandler function we discussed in Chapter 6. As you recall, this function requires an event target as its first parameter. The event target is the tab control, but you need to pass a parameter of type EventTargetRef. The Carbon Event Manager has a function, GetControlEventTarget, that takes a control as a parameter and returns an EventTargetRef for that control. But GetControlEventTarget takes a ControlRef as a parameter. You know what the ID and signature of the tab control are, so you’ll need to use those to get the ControlRef associated with our tab control’s ID and signature. The Control Manager has a function, GetControlByID, that will get a ControlRef associated with a window reference and a ControlID data type. A ControlID is a structure that contains a signature and an ID—the two items you assigned to your tab control when you set it up in Interface Builder.

When you put it all together, the code (which should be added to your main function) looks like Example 14.6.

Example 14-6. Code to Install the Tab Control Event Handler

ControlID           controlID;
     controlID.signature  = TAB_SIGNATURE;
    controlID.id         = TAB_ID;
    GetControlByID (MyWindow, &controlID, &tabControl);
    eventTypeSpec       controlSpec = { 

    InstallEventHandler (GetControlEventTarget (tabControl),
                        NewEventHandlerUPP (MyTabEventHandler),
                        2,
                        &controlSpec,
                        0,
                        NULL);

You need to assure that when your application launches, the tab control displays properly. To do so, put the following code in your main function to select the first tab item when the application launches:

MySwitchItemOfTabControl (1,tabControl);

Now, you are ready to add the actual tab handler shown in Example 14.7. The handle switches tabs only if the tab value has changed. If the user clicks the active tab, nothing happens.

Example 14-7. The Tab Event Handler

pascal OSStatus MyTabEventHandler (EventHandlerCallRef inHandlerRef, 
                                    EventRef inEvent, void *inUserData)
{
    ControlRef  tabControl;
    ControlID   controlID;   
    OSStatus    result;
    controlID.signature = TAB_SIGNATURE;
    controlID.id        = TAB_ID;

    GetControlByID (MyWindow, &controlID, &tabControl);                 // 1
    if (GetControlValue (tabControl) == lastTabIndex)                   // 2
    {
                   result = eventNotHandledErr;
    }
    else {                                                              // 3
       MySwitchItemOfTabControl (GetControlValue (tabControl), tabControl);
       result = noErr;
       }
    return result;     
}

Here is what the function does:

  1. You need to get the ControlRef associated with the tab control so you can check its value. As you saw in Chapter 6 the Control Manager function GetControlById will do just that.

  2. You use GetControlValue to get the value of the pane setting and compare it with the last known value to see if the tab value has changed. If it hasn’t changed, you pass back eventNotHandledErr to give the Carbon Event Manager a chance to let another handler take care of the event.

  3. Otherwise, the value has changed, so you need to call your function (MySwitchItemOfTabControl) to switch the pane associated with the tab and then redraw the tab control.

You’ll need to add the function called by your tab handler, as shown in Example 14.8, to switch to the pane associated with the tab.

Example 14-8. A Function to Switch Panes

void MySwitchItemOfTabControl (int currentTabIndex, 
                                ControlRef tabControl)
{
    ControlRef userPane;
    ControlRef selectedPane = NULL;
    ControlID controlID;
    UInt16 i;

    lastTabIndex = currentTabIndex;
    controlID.signature = TAB_SIGNATURE;

    for (i = 1; i < tabList[0] + 1; i++)
    {
        controlID.id = tabList[i];
        GetControlByID (MyWindow, &controlID, &userPane);            // 1
       
        if (i == currentTabIndex)                                    // 2
            selectedPane = userPane;
        else
            SetControlVisibility (userPane,false,true);              // 3
    }
    if (selectedPane)
        SetControlVisibility (selectedPane,true,true);               // 4

    Draw1Control (tabControl);                                       // 5
}

Here is what the function does:

  1. Call the Control Manager function GetControlByID to get the control reference for the pane associated with a tab control.

  2. If the current tab index has the same value as the pane you’re checking, then set the selected pane to the pane you’re checking.

  3. If the selected pane is not the same as the pane you’re checking, then call the Control Manager function SetControlVisibility to set the visibility for the pane to false (don’t show it) and update the display (indicated by true).

  4. If the selected pane is the same as the pane you’re checking, call the function SetControlVisibility to make the pane visible and update the display.

  5. The Control Manager function Draw1Control updates the tab control so the correct tab is active.

Notice that none of the code you’ve added handles controls in the pane. How could you handle them? Let’s say your tabbed window has a pane identical to the Travel Time pane shown earlier, in Figure 14.6. You would use the same window event handler and compute travel time functions you wrote in Chapter 6. You let your tab handler take care of switching the view while your window event handler and compute travel time functions respond to user interaction in the actual pane.

Instead of displaying content in multiple windows, tab controls let your application display the content as a stack of panes in a single window. To use tabs, you must add tab controls to your application and then write a handler that switches from one pane to another when the user clicks a tab. As an exercise, you can modify the Moon Travel Planner application to use multiple panes instead of multiple windows.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.209.131