Using Tab Controls in a Window

About this chapter

This chapter describes how to use Tab controls in your application.

About Tab controls

A Tab control is a container for tab pages that display other controls. One page at a time fills the display area of the Tab control. Each page has a tab like an index card divider. The user can click the tab to switch among the pages:

The Tab control allows you to present many pieces of information in an organized way. You add, resize, and move Tab controls just as you do any control. The Users Guide describes how to add controls to a window or custom visual user object.

Tab terms

You need to know these definitions:

Tab control

A control that you place in a window or user object that contains tab pages. Part of the area in the Tab control is for the tabs associated with the tab pages. Any space that is left is occupied by the tab pages themselves.

Tab page

A user object that contains other controls and is one of several pages within a Tab control. All the tab pages in a Tab control occupy the same area of the control and only one is visible at a time. The active tab page covers the other tab pages.

You can define tab pages right in the Tab control or you can define them in the User Object painter and insert them into the Tab control, either in the painter or during execution.

Tab

The visual handle for a tab page. The tab displays a label for the tab page. When a tab page is hidden, the user clicks its tab to bring it to the front and make the tab page active.

Defining and managing tab pages

A tab page is a user object.

Two methods

There are different ways to approach tab page definition. You can define:

  • An embedded tab page

    In the painter, insert tab pages in the Tab control and add controls to those pages. An embedded tab page is of class UserObject, but is not reusable.

  • An independent user object

    In the User Object painter, create a custom visual user object and add the controls that will display on the tab page. You can use the user object as a tab page in a Tab control, either in the painter or by calling OpenTab in a script. A tab page defined as an independent user object is reusable.

You can mix and match the two methods -- one Tab control can contain both embedded tab pages and independent user objects.

Creating tab pages

When you create a new Tab control, it has one embedded tab page. You can use that tab page or you can delete it.

To create a new tab page within the Tab control:

  1. Right-click in the tab area of the Tab control. Do not click a tab page.

  2. Select Insert TabPage from the pop-up menu.

  3. Add controls to the new page.

To define a tab page independent of a Tab control:

  1. Select Custom Visual on the Object tab in the New dialog box.

  2. In the User Object painter, size the user object to match the size of the display area of the Tab control in which you will use it.

  3. Add the controls that will appear on the tab page to the user object and write scripts for their events.

  4. On the user object's property sheet, click the TabPage tab and fill in information to be used by the tab page.

To add a tab page that exists as an independent user object to a Tab control:

  1. Right-click in the tab area of the Tab control. Do not click a tab page.

  2. Select Insert User Object from the pop-up menu.

  3. Select a user object.

    The tab page is inherited from the user object you select. You can set tab page properties and write scripts for the inherited user object just as you do for tab pages defined within the Tab control.

    Editing the controls on the tab page user object

    You cannot edit the content of the user object within the Tab control. If you want to edit or write scripts for the controls, close the window or user object containing the Tab control and go back to the User Object painter to make changes.

Managing tab pages

You can view, reorder, and delete the tab pages on a Tab control.

To view a different tab page:

  • Click the page's tab.

    The tab page comes to the front and becomes the active tab page. The tabs are rearranged according to the Tab position setting you have chosen.

To reorder the tabs within a Tab control:

  1. Click the Page Order tab on the Tab control's property sheet.

  2. Drag the names of the tab pages to the desired order.

To delete a tab page from a Tab control:

  1. Click the page's tab.

  2. Right-click the tab page and select Cut or Clear from the pop-up menu.

Selecting tab controls and tab pages

As you click on various areas within a tab control, you will notice the Properties view changing to show the properties of the tab control itself, one of the tab pages, or a control on a tab page. Before you select an item such as Cut from the pop-up menu, make sure that you have selected the right object.

Clicking anywhere in the tab area of a tab control selects the tab control. When you click the tab for a specific page, that tab page becomes active, but the selected object is still the tab control. To select the tab page, click its tab to make it active and then click anywhere on the background of the page except on the tab itself.

Controls on tab pages

The real purpose of a Tab control is to display other controls on its pages. You can think of the tab page as a miniature window. You add controls to it just as you do to a window.

When you are working on a Tab control, you can add controls only to a tab page created within the Tab control.

Adding controls to an independent user object tab page

To add controls to an independent user object tab page, open it in the User Object painter.

To add a control to an embedded tab page:

  • Choose a control from the toolbar or the Insert menu and click the tab page, just as you do to add a control to a window.

    When you click inside the tab page, the tab page becomes the control's parent.

To move a control from one tab page to another:

  • Cut or copy the control and paste it on the destination tab page.

    The source and destination tab pages must both be embedded tab pages, not independent user objects.

To move a control between a tab page and the window containing the Tab control:

  • Cut or copy the control and paste it on the destination window or tab page.

    You cannot drag the control out of the Tab control onto the window.

Moving the control between a tab page and the window changes the control's parent, which affects scripts that refer to the control.

Customizing the Tab control

The Tab control has settings for controlling the position and appearance of the tabs. Each tab can have its own label, picture, and background color.

All tabs share the same font settings, which you set on the Tab control's Font property page.

Pop-up menus and property sheets for Tab controls and tab pages

A Tab control has several elements, each with its own pop-up menu and property sheet. To open the property sheet, double-click or select Properties on the pop-up menu.

Where you click determines what element you access.

To access the pop-up menu or property sheet for a

Do this

Tab control

Right-click or double-click in the tab area of the Tab control.

Tab page

Click the tab to make the tab page active, then right-click or double-click somewhere in the tab page but not on a control on the page.

Control on a tab page

Click the tab to make the tab page active and right-click or double-click the control.


Position and size of tabs

The General tab in the Tab control's property sheet has several settings for controlling the position and size of the tabs.

To change

Change the value for

The side(s) of the Tab control on which the tabs appear

Tab Position

The size of the tabs relative to the size of the Tab control

Ragged Right, MultiLine, Fixed Width

The orientation of the text relative to the side of the Tab control (use this setting with caution only TrueType fonts support perpendicular text)

Perpendicular Text


Fixed Width and Ragged Right

When Fixed Width is checked, the tabs are all the same size. This is different from turning Ragged Right off, which stretches the tabs to fill the edge of the Tab control, like justified text. The effect is the same if all the tab labels are short, but if you have a mix of long and short labels, justified labels can be different sizes unless Fixed Width is on.

This figure illustrates the effect of combining some of these settings. Tab Position is Top:

This sample Tab control is set up like an address book. It has tabs that flip between the left and right sides. With the Bold Selected Text setting on and the changing tab positions, it is easy to see which tab is selected:

Tab labels

You can change the appearance of the tab using the property sheets of both the Tab control and the Tab page.

Property sheet

Property page

Setting

Affects

Tab control

General

PictureOnRight, ShowPicture, ShowText

All tabs in the control

Tab page

General

Text,

BackColor

The label on the tab and the background color of the tab page

Tab page

TabPage

PictureName, TabTextColor, TabBackColor, PictureMaskColor

The color of the text and picture on the tab and the background color of the tab itself (not the tab page)


If you are working in the User Object painter on an object you will use as a tab page, you can make the same settings on the TabPage page of the user object's property sheet that you can make in the tab page's property sheet.

This example has a picture and text assigned to each tab page. Each tab has a different background color. The Show Picture and Show Text settings are both on:

Changing tab appearance in scripts

All these settings in the painter have equivalent properties that you can set in a script, allowing you to change the appearance of the Tab control dynamically during execution.

Using Tab controls in scripts

This section provides examples of tabs in scripts:

Referring to tab pages in scripts

Dot notation allows you to refer to individual tab pages and controls on those tab pages:

  • The window or user object containing the Tab control is its parent:

    window.tabcontrol
  • The Tab control is the parent of the tab pages contained in it:

    window.tabcontrol.tabpageuo
  • The tab page is the parent of the control contained in it:

    window.tabcontrol.tabpageuo.controlonpage

For example, this statement refers to the PowerTips property of the Tab control tab_1 within the window w_display:

w_display.tab_1.PowerTips = TRUE

This example sets the PowerTipText property of tab page tabpage_1:

w_display.tab_1.tabpage_1.PowerTipText = &
   "Font settings"

This example enables the CommandButton cb_OK on the tab page tabpage_doit:

w_display.tab_1.tabpage_doit.cb_OK.Enabled = TRUE

Generic coding

You can use the Parent pronoun and GetParent function to make a script more general.

Parent pronoun

In a script for any tab page, you can use the Parent pronoun to refer to the Tab control:

Parent.SelectTab(This)

GetParent function

If you are in an event script for a tab page, you can call the GetParent function to get a reference to the tab page's parent, which is the Tab control, and assign the reference to a variable of type Tab.

In an event script for a user object that is used as a tab page, you can use code like the following to save a reference to the parent Tab control in an instance variable.

This is the declaration of the instance variable. It can hold a reference to any Tab control:

tab itab_settings

This code saves a reference to the tab page's parent in the instance variable:

// Get a reference to the Tab control
// "This" refers to the tab page user object
itab_settings = This.GetParent()

In event scripts for controls on the tab page, you can use GetParent twice to refer to the tab page user object and its Tab control:

tab tab_mytab
userobject tabpage_generic

tabpage_generic = This.GetParent()
tab_mytab = tabpage_generic.GetParent()

tabpage_generic.PowerTipText = &
   "Important property page"
tab_mytab.PowerTips = TRUE

tab_mytab.SelectTab(tabpage_generic)

Generic variables for controls have limitations

The type of these variables is the basic PowerBuilder object type -- a variable of type Tab has no knowledge of the tab pages in a specific Tab control and a variable of type UserObject has no knowledge of the controls on the tab page.

In this script for a tab page event, a local variable is assigned a reference to the parent Tab control. You cannot refer to specific pages in the Tab control because tab_settings does not know about them. You can call Tab control functions and refer to Tab control properties:

tab tab_settings
tab_settings = This.GetParent()
tab_settings.SelectTab(This)

User object variables

If the tab page is an independent user object, you can define a variable whose type is that specific user object. You can now refer to controls defined on the user object, which is the ancestor of the tab page in the control.

In this script for a Tab control's event, the index argument refers to a tab page and is used to get a reference to a user object from the Control property array. The example assumes that all the tab pages are derived from the same user object uo_emprpt_page:

uo_emprpt_page tabpage_current
tabpage_current = This.Control[index]
tabpage_current.dw_emp.Retrieve &
   (tabpage_current.st_name.Text)

The Tab control's Control property

The Control property array contains references to all the tab pages in the control, including both embedded and independent user objects. New tab pages are added to the array when you insert them in the painter and when you open them in a script.

Referring to controls on tab pages

If you are referring to a control on a tab page in another window, you must fully qualify the control's name up to the window level.

The following example shows a fully qualified reference to a static text control:

w_activity_manager.tab_fyi.tabpage_today. &
   st_currlogon_time.Text = ls_current_logon_time

This example from the PowerBuilder Code Examples sets the size of a DataWindow control on the tab page to match the size of another DataWindow control in the window. Because all the tab pages were inserted in the painter, the Control property array corresponds with the tab page index. All the pages are based on the same user object u_tab_dir:

u_tab_dir luo_Tab
luo_Tab = This.Control[newindex]
luo_Tab.dw_dir.Height = dw_list.Height
luo_Tab.dw_dir.Width = dw_list.Width

In scripts and functions for the tab page user object, the user object knows about its own controls. You do not need to qualify references to the controls. This example in a function for the u_tab_dir user object retrieves data for the dw_dir DataWindow control:

IF NOT ib_Retrieved THEN
   dw_dir.SetTransObject(SQLCA)
   dw_dir.Retrieve(as_Parm)
   ib_Retrieved = TRUE
END IF

RETURN dw_dir.RowCount()

Opening, closing, and hiding tab pages

You can open tab pages in a script. You can close tab pages that you opened, but you cannot close tab pages that were inserted in the painter. You can hide any tab page.

This example opens a tab page of type tabpage_listbox and stores the object reference in an instance variable i_tabpage. The value 0 specifies that the tab page becomes the last page in the Tab control. You need to save the reference for closing the tab later.

This is the instance variable declaration for the tab page's object reference:

userobject i_tabpage

This code opens the tab page:

li_rtn = tab_1.OpenTab &
   (i_tabpage, "tabpage_listbox", 0)

This statement closes the tab page:

tab_1.CloseTab(i_tabpage)

Keeping track of tab pages

To refer to the controls on a tab page, you need the user object reference, not just the index of the tab page. You can use the tab page's Control property array to get references to all your tab pages.

Control property for tab pages

The Control property of the Tab control is an array with a reference to each tab page defined in the painter and each tab page added in a script. The index values that are passed to events match the array elements of the Control property.

You can get an object reference for the selected tab using the SelectedTab property:

userobject luo_tabpage
luo_tabpage = tab_1.Control[tab_1.SelectedTab]

In an event for the Tab control, like SelectionChanged, you can use the index value passed to the event to get a reference from the Control property array:

userobject tabpage_generic
tabpage_generic = This.Control[newindex]

Adding a new tab page

When you call OpenTab, the control property array grows by one element. The new element is a reference to the newly opened tab page. For example, the following statement adds a new tab in the second position in the Tab control:

tab_1.OpenTab(uo_newtab, 2)

The second element in the control array for tab_1 now refers to uo_newtab, and the index into the control array for all subsequent tab pages becomes one greater.

Closing a tab page

When you call CloseTab, the size of the array is reduced by one and the reference to the user object or page is destroyed. If the closed tab was not the last element in the array, the index for all subsequent tab pages is reduced by one.

Moving a tab page

The MoveTab function changes the order of the pages in a Tab control and also reorders the elements in the control array to match the new tab order.

Control property array for user objects

The Control property array for controls in a user object works in the same way.

Creating tab pages only when needed

The user might never look at all the tab pages in your Tab control. You can avoid the overhead of creating graphical representations of the controls on all the tab pages by checking Create on Demand on the Tab control's General property page or setting the CreateOnDemand property to TRUE.

The controls on all the tab pages in a Tab control are always instantiated when the Tab control is created. However, when Create on Demand is checked, the Constructor event for controls on tab pages is not triggered and graphical representations of the controls are not created until the user views the tab page.

Constructor events on the selected tab page

Constructor events for controls on the selected tab page are always triggered when the Tab control is created.

Tradeoffs for Create on Demand

A window will open more quickly if the creation of graphical representations is delayed for tab pages with many controls. However, scripts cannot refer to a control on a tab page until the control's Constructor event has run and a graphical representation of the control has been created. When Create on Demand is checked, scripts cannot reference controls on tab pages that the user has not viewed.

Whether a tab page has been created

You can check whether a tab page has been created with the PageCreated function. Then, if it has not been created, you can trigger the constructor event for the tab page using the CreatePage function:

IF tab_1.tabpage_3.PageCreated() = FALSE THEN
      tab_1.tabpage_3.CreatePage()
END IF

You can check whether a control on a tab page has been created by checking whether the control's handle is nonzero. If so, the control has been created.

IF Handle(tab_1.tabpage_3.dw_list) > 0 THEN ...

Changing CreateOnDemand during execution

If you change the CreateOnDemand property to FALSE in a script, graphical representations of any tab pages that have not been created are created immediately.

It does not do any good to change CreateOnDemand to TRUE during execution, because graphical representations of all the tab pages have already been created.

Creating tab pages dynamically

If CreateOnDemand is FALSE, you can set the label for a dynamically created tab page in its Constructor event, using the argument to OpenTabWithParm that is passed to the Message object. If CreateOnDemand is TRUE, you need to set the label when the tab page is instantiated, because the Constructor event is not triggered until the tab is selected. The following script in a user event that is posted from a window's open event opens five tab pages and sets the label for each tab as it is instantiated:

int li_ctr
string is_title
THIS.setredraw(false)

FOR li_ctr = 1 to 5
   is_title = "Tab#" + string(li_ctr)
   tab_test.opentabwithparm(iuo_tabpage[li_ctr], &
      is_title, 0)
iuo_tabpage[li_ctr].text = is_title //set tab label
NEXT

THIS.setredraw(true)
RETURN 1

Events for the parts of the Tab control

With so many overlapping pieces in a Tab control, you need to know where to code scripts for events.

To respond to actions in the

Write a script for events belonging to

Tab area of the Tab control, including clicks or drag actions on tabs

The Tab control

Tab page (but not the tab)

The tab page (for embedded tab pages) or the user object (for independent tab pages)

Control on a tab page

That control


For example, if the user drags to a tab and you want to do something to the tab page associated with the tab, you need to code the DragDrop event for the Tab control, not the tab page.

Examples

This code in the DragDrop event of the tab_1 control selects the tab page when the user drops something onto its tab. The index of the tab that is the drop target is an argument for the DragDrop event:

This.SelectTab( index )

The following code in the DragDrop event for the Tab control lets the user drag DataWindow information to a tab and then inserts the dragged information in a list on the tab page associated with the tab.

A user object of type tabpage_listbox that contains a ListBox control, lb_list, has been defined in the User Object painter. The Tab control contains several independent tab pages of type tabpage_listbox.

You can use the index argument for the DragDrop event to get a tab page reference from the Tab control's Control property array. The user object reference lets the script access the controls on the tab page.

The Parent pronoun in this script for the Tab control refers to the window:

long ll_row
string ls_name
tabpage_listbox luo_tabpage

IF TypeOf(source) = DataWindow! THEN
   l_row = Parent.dw_2.GetRow()
   ls_name = Parent.dw_2.Object.lname.Primary[ll_row]

   // Get a reference from the Control property array
   luo_tabpage = This.Control[index]

   // Make the tab page the selected tab page
   This.SelectTab(index)

   // Insert the dragged information
   luo_tabpage.lb_list.InsertItem(ls_name, 0)

END IF

If the tab page has not been created

If the CreateOnDemand property for the Tab control is TRUE, the Constructor events for a tab page and its controls are not triggered until the tab page is selected. In the previous example, making the tab page the selected tab page triggers the Constructor events. You could also use the CreatePage function to trigger them:

IF luo_tabpage.PageCreated() = FALSE THEN &
luo_tabpage.CreatePage()