|
|
|
This guide explains the UIQ control Horizontal Option Button List (CEikHorOptionButtonList). Option Buttons are always grouped together, two or more, in a Horizontal Option Button List. An Option Button List is either a vertical or horizontal list containing two or more selectable items where one option must always be selected. This control is normally used in a Container Pop-out. This document focuses on the Horizontal Option Button List.
The following functionality can be used by the application developer:
Add an Option Button to the list with a specified text for the Label of the Option Button. This text can be changed afterwards,
Toggle between dimmed state and the normal state of the Horizontal Option Button List,
Set the space between the Option Buttons,
Set the placement of the text of the Option Buttons to left or right side of the bullets,
Set an Option Button to be selected.
Examples of Option Button graphics
|
Examples of Horizontal Option Button List graphics
|
See the API documentation for Horizontal Option Button List CEikHorOptionButtonList.
The Horizontal Option Button List control is related to the Option Button control and the Label control. There is also a control for a vertical arrangement of Option Buttons, the Vertical Option Button List. See the How To guides for Label and Vertical Option Button List.
See even the API documentation for Option Button (CEikOptionButton), Vertical Option Button List (CQikVertOptionButtonList) and Label (CEikLabel).
This chapter explains how the control is constructed, used and destroyed. Source code examples are used and explained to illustrate how the Horizontal Option Button List control is used.
Use the following #include directive:
#include <eikhopbt.h>
Use the following LIBRARY directive in the project's mmp-file:
LIBRARY EikCtl.lib
Resource files can be used to construct the Horizontal Option Button List. The resource to use is defined by the HOROPBUT structure, defined in Eikon.rh. The structure looks like this:
STRUCT HOROPBUT
{
WORD buttonSpacing = 10;
WORD textOnRight = 1;
LLINK array_id = 0;
}
The values given in the structure definition are default values. The structure contains the following:
buttonSpacing sets the space, in pixels, between the buttons,
textOnRight specifies whether the text is located to the right or left of the buttons. A default value of 1 indicates text to the right, and 0 indicates text to the left,
array_id the ID of a resource, of type ARRAY, listing items associated with each button.
The Horizontal Option Button List does not have any flags.
This section discusses four different ways of constructing controls. The first three ways describe how to construct and add a control to the view of an application. The view framework is used in all three cases but in three different ways. The fourth way describes how to construct and launch a dialog from an application. The dialog framework constructs the control and adds it into the dialog.
A common way to construct controls is to specify them in the resource files and let the framework construct them from there. Specifying the controls in resource files is the preferred way of constructing controls since it allows for easier modifications compared to creating them entirely from source code.
This section covers different ways of constructing a Horizontal Option Button List.
The example below describes how to construct a Horizontal Option Button List using the view framework.
The reason the example seems to be rather complex is because it demonstrates how to construct a complete view containing a Scrollable Container and a Layout Manager. It also encapsulates the Horizontal Option Button List in a Building Block. The view supports both pen and softkey styles; support of both styles in a view is optional.
1) Declare an enumeration for the controls to be used in the view in a *.hrh file. Hrh files are files to be included both in resource files (*.rss) and C++ files:
/* Declare the control's ID in a *.hrh file for use both in resource and cpp */
enum TMyViewControls
{
EMyViewScrollableContainer,
EMyViewBuildingBlock,
EMyViewHorizontalOptionButtonList,
EMyViewOptionButton1,
EMyViewOptionButton2,
EMyViewNumberOfControls
};
2) Declare the controls to be used in the view in your resource (*.rss) file:
/* Declare the set of controls to be used in the view */
RESOURCE QIK_CONTROL_COLLECTION r_my_horizontal_option_button_list_view_controls
{
items =
{
QIK_CONTROL
{
unique_handle = EMyViewScrollableContainer;
type = EQikCtScrollableContainer;
control = r_my_horizontal_option_button_list_scroll_pane;
},
QIK_CONTROL
{
unique_handle = EMyViewHorizontalOptionButtonList;
type = EEikCtHorOptionButList;
control = r_my_horizontal_option_button_list;
},
QIK_CONTROL
{
unique_handle = EMyViewBuildingBlock;
type = EQikCtCaptionedTwolineBuildingBlock;
control = r_my_horizontal_option_button_list_building_block;
}
};
}
3) Define the view and its contents in your resource file:
/* The view */
RESOURCE QIK_VIEW r_my_horizontal_option_button_list_view
{
pages = r_my_horizontal_option_button_list_viewpages;
}
/* The view page */
RESOURCE QIK_VIEW_PAGES r_my_horizontal_option_button_list_viewpages
{
pages =
{
QIK_VIEW_PAGE
{
container_unique_handle = EMyViewScrollableContainer;
page_content = r_my_horizontal_option_button_list_view_container_details;
}
};
}
4) Define the resource for the Scrollable Container used in the view:
/* The scrollable container used in the view */
RESOURCE QIK_SCROLLABLE_CONTAINER r_my_horizontal_option_button_list_scroll_pane
{
}
5) Declare the contents and properties for the Scrollable Container used in the view:
/* Contents of the Scrollable Container used in the view */
RESOURCE QIK_SCROLLABLE_CONTAINER_SETTINGS r_my_horizontal_option_button_list_view_container_details
{
controls =
{
QIK_CONTAINER_ITEM
{
unique_handle = EMyViewBuildingBlock;
}
};
}
6) Define the control resource structure used in the view:
/* The Horizontal Option Button List used in the view */
RESOURCE HOROPBUT r_my_horizontal_option_button_list
{
buttonSpacing = 3;
textOnRight = 1;
array_id = r_my_horizontal_option_button_list_buttons;
}
7) Define the array resource to be used in the Horizontal Option Button List:
RESOURCE ARRAY r_my_horizontal_option_button_list_buttons
{
items=
{
OPBUT {id = EMyViewOptionButton1; text = "One";},
OPBUT {id = EMyViewOptionButton2; text = "Two";}
};
}
8) Define the settings for the Building Block containing the control:
/* Settings for the EQikCtCaptionedTwolineBuildingBlock containing the Horizontal Option Button List */
RESOURCE QIK_SYSTEM_BUILDING_BLOCK r_my_horizontal_option_button_list_building_block
{
content =
{
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot1;
caption = "Choose:";
},
QIK_SLOT_CONTENT
{
slot_id = EQikItemSlot2;
unique_handle = EMyViewHorizontalOptionButtonList;
}
};
}
9) The configurations of the view:
RESOURCE QIK_VIEW_CONFIGURATIONS r_my_horizontal_option_button_list_ui_configurations
{
configurations=
{
QIK_VIEW_CONFIGURATION
{
ui_config_mode=KQikSoftkeyStylePortrait;
view=r_my_horizontal_option_button_list_view;
command_list=r_my_horizontal_option_button_list_commands;
},
QIK_VIEW_CONFIGURATION
{
ui_config_mode=KQikPenStyleTouchPortrait;
view=r_my_horizontal_option_button_list_view;
command_list=r_my_horizontal_option_button_list_commands;
}
};
}
10) The command list for the view:
RESOURCE QIK_COMMAND_LIST r_my_horizontal_option_button_list_commands
{
items =
{
// This command shall only be visible in debug mode because it is only
// used to find memory leaks during development of the application.
QIK_COMMAND
{
id = EEikCmdExit;
type = EQikCommandTypeScreen;
// Indicate that this command will only be visible in debug
stateFlags = EQikCmdFlagDebugOnly;
text = "Close (debug)";
}
};
}
11) The view framework constructs the view described in this example with this code:
void CMySinglePageView::ViewConstructL()
{
ViewConstructFromResourceL(R_MY_HORIZONTAL_OPTION_BUTTON_LIST_UI_CONFIGURATIONS, R_MY_HORIZONTAL_OPTION_BUTTON_LIST_VIEW_CONTROLS);
}
12) The result should look something like this:
The example below describes how to construct a Horizontal Option Button List from resource with your own C++ code.
The reason the example seems to be rather complex is because it demonstrates how to construct a complete view containing a Scrollable Container and a Layout Manager. It also encapsulates the Horizontal Option Button List in a Building Block.
This example uses the resource structures from the previous example. The following code creates the Horizontal Option Button List:
#include <Eikhopbt.h>
#include <QikRowLayoutManager.h>
#include <QikGridLayoutManager.h>
#include <QikBuildingBlock.h>
void CMySinglePageView::ViewConstructL()
{
// Give a layout manager to the view
CQikGridLayoutManager* gl = CQikGridLayoutManager::NewLC();
SetLayoutManagerL(gl);
CleanupStack::Pop(gl);
// Create a container and give it to the view
ControlProvider()->ControlInfos().AddFromResourceL(R_MY_HORIZONTAL_OPTION_BUTTON_LIST_VIEW_CONTROLS);
CQikContainerBase* container = static_cast<CQikContainerBase*>(ControlProvider()->ControlConstructIfNeededL(EMyViewScrollableContainer, *this));
ASSERT(container);
Controls().AppendLC(container);
CleanupStack::Pop(container);
// Create a layout manager to be used inside the container
CQikRowLayoutManager* rowlayout = CQikRowLayoutManager::NewLC();
container->SetLayoutManagerL(rowlayout);
CleanupStack::Pop(rowlayout);
// Create the building block (containing a Horizontal Option Button List) and
// add it to the container
CQikBuildingBlock* block = CQikBuildingBlock::CreateSystemBuildingBlockL(EQikCtCaptionedTwolineBuildingBlock);
container->AddControlLC(block, EMyViewBuildingBlock);
TResourceReader blockReader;
iCoeEnv->CreateResourceReaderLC(blockReader, R_MY_HORIZONTAL_OPTION_BUTTON_LIST_BUILDING_BLOCK);
block->ConstructFromResourceL(blockReader, *ControlProvider());
CleanupStack::PopAndDestroy(); //blockReader
CleanupStack::Pop(block);
}
What the code does
1) Initializes the Command Manager with an empty Command List. The controls placed in the view add their commands to the Command List when they receive focus.
2) Creates a Layout Manager for the view. The Grid Layout Manager fills the view with its only control in this example, the Scrollable Container.
3) Loads the control collection R_MY_VIEW_CONTROLS into the Control Provider. Then the Control Provider is asked to create the Scrollable Container.
4) Uses the MopGetObjectNoChaining function to determine whether the control that was created really is a class of the type CQikContainerBase before it is added to the view.
5) Creates a Layout Manager to control the layout inside the container. Adds the Layout Manager to the container.
6) Constructs the Building Block containing the Horizontal Option Button List from the resource R_MY_BUILDING_BLOCK. Adds the Building Block to the container.
The Horizontal Option Button List can also be created without a Building Block. In that case, replace the last section in the code above, from the "Create building block..." comment, with the following code.
Since a pointer to the control is declared here, Eikhopbt.h needs to be included in the cpp-file and EikCtl.lib in the mmp-file.
// Create the Horizontal Option Button List and add it to the container
TResourceReader reader;
iEikonEnv->CreateResourceReaderLC(reader, R_MY_HORIZONTAL_OPTION_BUTTON_LIST);
CEikHorOptionButtonList* opbtnl = new (ELeave) CEikHorOptionButtonList();
container->AddControlLC(opbtnl, EMyViewHorizontalOptionButtonList);
opbtnl->ConstructFromResourceL(reader);
opbtnl->SetUniqueHandle(EMyViewHorizontalOptionButtonList);
CleanupStack::Pop(opbtnl);
CleanupStack::PopAndDestroy(); //reader
Use AddControlLC to add controls to a Scrollable Container.
Add the controls as soon as they are created. Do not push them onto the
Cleanup Stack before they are added. Do not pop them from the Cleanup Stack
until they are fully constructed. A TCleanupItem created in AddControlLC will make sure that
the control is both cleaned up and removed from the Components Array if a leave
occurs before the control is fully constructed.
The example below describes how to construct a Horizontal Option Button List solely from C++ code.
The reason the example seems to be rather complex is because it demonstrates how to construct a complete view containing a Scrollable Container and a Layout Manager.
The following source code constructs a Horizontal Option Button List:
#include <Eikhopbt.h>
#include <QikScrollableContainer.h>
#include <QikRowLayoutManager.h>
#include <QikGridLayoutManager.h>
#include <QikBuildingBlock.h>
void CMySinglePageView::ViewConstructL()
{
// Give a layout manager to the view
CQikGridLayoutManager* gridlayout = CQikGridLayoutManager::NewLC();
SetLayoutManagerL(gridlayout);
CleanupStack::Pop(gridlayout);
// Create a container and add it to the view
CQikScrollableContainer* container = new (ELeave) CQikScrollableContainer();
Controls().AppendLC(container);
container->ConstructL(EFalse);
CleanupStack::Pop(container);
// Create a layout manager to be used inside the container
CQikRowLayoutManager* rowlayout = CQikRowLayoutManager::NewLC();
container->SetLayoutManagerL(rowlayout);
CleanupStack::Pop(rowlayout);
CEikHorOptionButtonList* opbtnl = new (ELeave) CEikHorOptionButtonList();
container->AddControlLC(opbtnl, EMyViewHorizontalOptionButtonList);
opbtnl->ConstructL();
_LIT(KOptionButton1, "One");
_LIT(KOptionButton2, "Two");
opbtnl->AddOptionButtonL(EMyViewOptionButton1, KOptionButton1);
opbtnl->AddOptionButtonL(EMyViewOptionButton2, KOptionButton2);
opbtnl->SetUniqueHandle(EMyViewHorizontalOptionButtonList);
opbtnl->SetObserver(this);
CleanupStack::Pop(opbtnl);
}
What the code does
1) Initializes the Command Manager with an empty Command List. The controls placed in the view add their commands to the Command List when they receive focus.
2) Creates a Layout Manager for the view. The Grid Layout Manager fills the view with its only control in this example, the Scrollable Container.
3) Instantiates a container and adds it to the view.
4) Creates a Layout Manager and adds it to the container.
5) Creates the Horizontal Option Button List control from C++ code. Sets the view, this, to be an observer
of the Horizontal Option Button List. The view's base class CQikViewBase handles focus changes in its
method HandleControlEventL. For more details see the section How to be Notified with Control Events.
The Horizontal Option Button List can be constructed from resource files in dialogs as well. To construct a dialog from resource, a valid resource definition of that dialog must be in one of the project's resource files.
An example of a dialog resource containing the control is given below.
For more information about the dialog class and its resource structure see CEikDialog
and DIALOG in the API documentation.
1) Declare a dialog resource containing the Horizontal Option Button List control:
RESOURCE DIALOG r_hoptionbuttonlist_test_dialog
{
title = "H Option Button List Test";
flags = EEikDialogFlagWait;
items =
{
DLG_LINE
{
type = EEikCtHorOptionButList;
prompt = "H Option Button List";
control = HOROPBUT
{
array_id = r_my_horizontal_option_button_list_buttons;
};
}
};
}
RESOURCE ARRAY r_my_horizontal_option_button_list_buttons
{
items=
{
OPBUT {id = EMyViewOptionButton1; text = "One";},
OPBUT {id = EMyViewOptionButton2; text = "Two";}
};
}
The resource properties inside the Control Block are the same as the ones described in the previous section.
2) Launch the dialog using the following source code. The dialog resource ID is passed as an argument:
CEikDialog* dlg = new (ELeave) CEikDialog();
dlg->ExecuteLD(R_HOPTIONBUTTONLIST_TEST_DIALOG);
The function returns immediately if EEikDialogFlagWait has not been specified in the dialog resource. If EEikDialogFlagWait is specified, it returns when the dialog exits. The dialog framework will in both situations delete the dialog appropriately as indicated by the D suffix of the ExcecuteLD function name.
This section covers the most common functions used for interacting with the control.
When constructing the control with resource data, no reference to the control is available in the view class. When constructing the control with code, the preferred way might be to not save a reference to the control. In both these cases, the LocateControlByUniqueHandle function is used to get a pointer to the control, by supplying the control's unique handle. When constructing the view and the control from code you must explicitly set this unique handle by calling the method SetUniqueHandle. See the code examples below.
Note that the function will return NULL if the control could not be found. Always check the pointer before using it!
// Set the unique handle
opbtnl->SetUniqueHandle(EMyViewHorizontalOptionButtonList);
// Get a pointer to the Horizontal Option Button List control
CEikHorOptionButtonList* commandbutton = LocateControlByUniqueHandle<CEikHorOptionButtonList>(EMyViewHOptionButtonList);
To find out which button is set use the following method:
// Get the ID of the button which is set
TInt buttonId = opbtnl->LabeledButtonId();
To find out the state of a specific Option Button in the Horizontal Option Button List a pointer to the button is fetched using the button's ID. Then the state of the button can then be retrieved.
// Get a pointer to the Option Button by use of its ID
CEikOptionButton* opbtn = static_cast<CEikOptionButton*>(commandbutton->ComponentControl(aButtonId));
//Get the state of the Option Button
CEikCommandButton::TState state = opbtn->State();
In order to be notified when the Horizontal Option Button List changes state you
must add an observer to the Horizontal Option Button List. An observer is an object of the type
MCoeControlObserver. The observer receives a function call to its function
HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType) when the Horizontal Option Button List changes state.
The view base class, CQikViewBase, implements the
MCoeControlObserver. The HandleControlEventL function must be overloaded in the
view class, because the view inherits from CQikViewBase.
The following source code example shows how to add an object as an observer and how to receive events from the Horizontal Option Button List:
void CMySinglePageView::ViewConstructL()
{
// Construction code
…
// Adding this object as an observer
opbtnl->SetObserver(this);
}
void CMySinglePageView::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)
{
// Call base class to handle focus management
CQikViewBase::HandleControlEventL(aControl, aEventType);
CEikHorOptionButtonList* commandbutton = LocateControlByUniqueHandle<CEikHorOptionButtonList>(EMyViewHOptionButtonList);
if(aControl == opbtnl)
{
switch(aEventType)
{
case EEventStateChanged:
// The internal state of the Horizontal Option Button was changed,
// for example, due to another item being selected.
break;
case EEventRequestExit:
break;
case EEventRequestCancel:
break;
case EEventRequestFocus:
// The Horizontal Option Button List received a pointer down event
break;
case EEventPrepareFocusTransition:
// A focus change is about to appear
break;
case EEventInteractionRefused:
// The Horizontal Option Button List is dimmed and received a
// pointer down event.
break;
default:
break;
}
}
}
The reason for calling the base class's HandleControlEventL function is
that the view base class, CQikViewBase, handles focus management between controls in the view.
If the control's observer is not a class which derives from CQikViewBase, focus management must be resolved by the observer itself. If a control requests
focus and does not get it from the observer, it will generate a panic in some cases if the observer does not leave.
For more details on the TCoeEvent
type, see class MCoeControlObserver in the API documentation.
When using a Horizontal Option Button List dialog you need to use an CAsyncCallBack, here iAsyncExitDialog, to close the dialog, otherwise you can never be sure that the control reporting the EEventControlStateChanged has finished executing when the dialog is deleted. To do that, use the code below:
void CMySinglePageView::HandleControlEventL(CCoeControl* aControl,TCoeEvent aEventType)
{
CEikHorOptionButtonList* commandbutton = LocateControlByUniqueHandle<CEikHorOptionButtonList>(EMyViewHOptionButtonList);
if (aEventType == EEventStateChanged && (opbtnl == aControl))
{
//The constructor takes a callback and a priority value
TCallBack asyncExitDialog(AsyncExitDialogL, this);
iAsyncExitDialog.Set(asyncExitDialog);
iAsyncExitDialog.CallBack();
}
}
//The function encapsulated by the callback which is called when this active object is scheduled to run.
TInt CMySinglePageView::AsyncExitDialogL(TAny* aThis)
{
CMySinglePageView* self = static_cast<CMySinglePageView*>(aThis);
TRAPD(err, self->TryExitL(EEikBidOk));
if (err != KErrNone)
{
if(err != KErrCancel && err != KLeaveExit)
CEikonEnv::Static()->HandleError(err);
}
return err;
}
Destroying the control is just a matter of invoking operator delete on the Horizontal Option Button List object. The only thing to think about is whether or not the Horizontal Option Button List owns the item array. If it does, the control will delete the array, and its objects, in its destructor. If it does not, someone else must take care of it.
Subclassing Horizontal Option Button List is not recommended.