Form API Specification

Contents

1 Overview

Forms are dialogs that are used to display and/or edit logically related data. Forms are a subset of AVKON dialogs. For detailed information on dialogs in general, as well as other dialog types, see Dialogs API Specification.


API categorypublic
API typec++
Existed sinceLegacy S60 0.9
API librariesavkon.lib
Location/sf/mw/classicui/classicui_pub/form_api
Buildfiles/sf/mw/classicui/classicui_pub/form_api/group/bld.inf


1.1 Description

This document describes how to use Form API to create and use forms. Forms are standard AVKON dialogs, based on the class CAknForm . An appropriate resource and the matching CAknForm based class is needed to use forms.

Form
Form

1.2 Changes

Form API is an SDK API and was first published in S60 release 0.9.

This API is valid for all platforms running on Symbian OS 9.1 or later.

1.3 Use Cases

  • Defining the form resource
  • Launching the form
  • Initializing form data
  • Saving form data
  • Reverting changes
  • Modifying the menu
  • Processing commands
  • Managing fields
  • Adding custom field

1.4 Class Structure

Summary of API classes and header files
ClassesFiles
CAknForm /epoc32/include/mw/AknForm.h

Figure 8 shows Form API classes.

Form API
Form API

1.5 Form modes and formats

1.5.1 Field structure

Field structure
Field structure

The form data items (dialog lines in the form) are called fields. A field contains a label and a control. Labels can contain strings and icons. Controls can have various types, such as editors, pop-up lists, and sliders. Labels and controls can be displayed on one row or on different rows.

1.5.2 Form field layouts

A field is composed of a label and a control. The label and the control can be displayed on one row, which is called single-line display. The label and the control can also be displayed on different rows, and this is called double-line display. The label can contain only a string, only an icon, or both.

The field is in single-line display, and its label contains only a string.

Auto-inserted
Auto-inserted

The field is in single-line display, and its label contains only an icon.

Auto-inserted
Auto-inserted

The field is in single-line display, and its label contains both a string and an icon.

Auto-inserted
Auto-inserted

The field is in double-line display, and its label contains only a string.

Auto-inserted
Auto-inserted

The field is in double-line display, and its label contains only an icon.

Auto-inserted
Auto-inserted

The field is in double-line display, and its label contains both a string and an icon.

Auto-inserted
Auto-inserted

1.5.3 Form modes

A form has two display modes: the view mode and the edit mode (see Figure 2 and Figure 3). In the view mode, the value of each control can be viewed. The edit mode is used to change a control's values or labels, and to add and delete fields.

The form can be switched between the two modes. These modes can also be disabled.

Depending on the field type, the control inside the field may be different in view and edit mode. For example, a text editing field may contain an editor control in edit mode and a label in view mode.

View mode
View mode
Edit mode
Edit mode

Forms have a different default Options menu in the two modes. In the view mode, the default Options menu contains only Edit as shown in Figure 4, but in the edit mode, the default menu contains Add field, Save, Edit label, and Delete field as shown in Figure 5.

View mode Options menu
View mode Options menu
Edit mode Options menu
Edit mode Options menu

Figure 6 shows form modes.

Form modes
Form modes

1.5.4 Multi-page forms

Besides forms that contain one page, there is another type of form that is comprised of multiple pages controlled by tabs as shown in Figure 7. Multi-page forms can be used to group relevant controls. The Arrow keys (left/right) can be used to switch between pages.

Multi-page form
Multi-page form

2 Using The API

To use forms, the dialog resource ( RESOURCE DIALOG) must be defined in the application resource file and a matching CAknForm -based class must be provided.

Example data structure TMyData is used to demonstrate the usage of most typical data fields in forms.

struct TMyData
    {
public:     // data
    TBuf<256> iText;
    TBuf<256> iGlobalText;
    TBuf<256> iRichText;
    TInt iNumber;
    TInt iInteger;
    TReal iFloat;
    TInt iFix;
    TTime iDate;
    TTime iTime;
    TTimeIntervalSeconds iDuration;
    TBuf<4> iNumPwd;
    TBuf<8> iAlphaPwd;
    TInetAddr iIpAddr;
    MAknQueryValue* iPopupVal;
    TInt iPopupTextIndex;
    TInt iSliderVal;
    };

The class CMyForm is used to display and edit the data.

class CMyForm : public CAknForm
    {
public:     // construction
    CMyForm( TMyData& aData );
    virtual ~CMyForm();
public:     // from CAknForm
    void DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane );
    void ProcessCommandL( TInt aCommandId );
    TBool SaveFormDataL();
    void DoNotSaveFormDataL();
    void AddItemL() ;
    void PreLayoutDynInitL();
    MEikDialogPageObserver::TFormControlTypes
        ConvertCustomControlTypeToBaseControlType( TInt aControlType ) const;
private:
    void LoadFormDataL() ;
private:    // data
    TMyData& iData;
    TInt iAddedItemId;
    };

2.1 Defining the form resource

Since a form is a special dialog, its resource definition is within a DIALOG resource, that is, the dialog structure has the LLINK form as a member.

STRUCT DIALOG
    {
    LONG flags = 0;
    LTEXT title = "";
    LLINK pages = 0;
    LLINK buttons = 0;
    STRUCT items();
    LLINK form = 0;
    }

When considering forms, the important members of the DIALOG structure are:

are defined in the eikon.hrh file.

Used only in multi-page forms (see [Form_API_Specification.topic3.1.2 Multi-page form]). For single-page forms, this should not be specified.

described later. Used in single-page forms. For multi-page forms, this should not be specified.

See document S60 3.1 Dialogs API Specification for more information on other DIALOG structure members.

STRUCT FORM
    {
    WORD flags = 0;
    STRUCT items();
    }

The FORM structure member flags can be used to specify the style of the form. The default setting is single-line display, and the predefined values are as follows:

Flag Description
EEikFormUseDoubleSpacedFormat Double-line display.
EEikFormHideEmptyFields Makes empty data fields invisible.
EEikFormShowBitmaps Displays a bitmap on a label.
EEikFormEditModeOnly Displays the form in edit mode only.
EEikFormShowEmptyFields Displays single-line display (default).

Form fields are described with the structure DLG_LINE in the member items of the FORM structure.

STRUCT DLG_LINE
    {
    WORD type;
    LTEXT prompt;
    WORD id = 0;
    LONG itemflags = 0;
    STRUCT control;
    LTEXT trailer = "";
    LTEXT bmpfile = "";
    WORD bmpid = 0xffff;
    WORD bmpmask;
    LTEXT tooltip = "";
    }

The important members of this structure are:

or EAknCtSlider . Types are defined in the eikon.hrh or avkon.hrh files. For details on the resource structures defining individual controls, see document S60 3.1 Editors API Specification.

Within the application, the ID is used to reference the dialog line. The ID must be defined in the application's HRH file. Each dialog line must have a unique ID; otherwise the application panics when the dialog is executed.

are defined in HRH files.

2.1.1 Single-page form

The following resource defines a form for viewing and editing TMyStruct data in a single page.

RESOURCE DIALOG r_my_dialog
    {
    flags = EEikDialogFlagNoBorder | EEikDialogFlagNoDrag  |
            EEikDialogFlagNoTitleBar | EEikDialogFlagFillAppClientRect |
            EEikDialogFlagCbaButtons | EEikDialogFlagWait;
    buttons = R_AVKON_SOFTKEYS_OPTIONS_BACK;
    form = r_my_form;
    }
RESOURCE FORM r_my_form
    {
    flags = EEikFormUseDoubleSpacedFormat;
    items =
        {
        DLG_LINE
            {
            type = EEikCtEdwin;
            prompt = "Text" ;
            id = EMyAppControlIdTextEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = EDWIN
                {
                flags = KMultiLineExpandingEditorFlags |
                        EEikEdwinNoLineOrParaBreaks;
                maxlength = 256;
                width = 6;
                };
            },
        DLG_LINE
            {
            type = EEikCtGlobalTextEditor;
            prompt = "Global text";
            id = EMyAppControlIdGlobalTextEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = GTXTED
                {
                width = 10;
                height = 17;
                textlimit = 256;
                flags = KMultiLineExpandingEditorFlags;
                max_view_height_in_lines = 2;
                };
            },
        DLG_LINE
            {
            type = EEikCtRichTextEditor;
            prompt = "Rich text";
            id = EMyAppControlIdRichTextEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = RTXTED
                {
                width = 10;
                height = 17;
                textlimit = 256;
                flags = KMultiLineExpandingEditorFlags;
                max_view_height_in_lines = 3;
                };
            },
        DLG_LINE
            {
            type = EEikCtNumberEditor;
            prompt = "Number" ;
            id = EMyAppControlIdNumberEd ;
            control = NUMBER_EDITOR
                {
                min = 0;
                max = 999;
                };
            },
        DLG_LINE
            {
            type = EAknCtIntegerEdwin;
            prompt = "Integer edwin" ;
            id = EMyAppControlIdIntegerEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = AVKON_INTEGER_EDWIN
                {
                maxlength = 10;
                min = 0;
                max = 999;
                };
            },
        DLG_LINE
            {
            type = EEikCtFlPtEd;
            prompt = "Floating point" ;
            id = EMyAppControlIdFloatEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = FLPTED
                {
                maxlength = 10;
                min = 0;
                max = 999;
                };
            },
        DLG_LINE
            {
            type=EEikCtFxPtEd;
            prompt = "Fixed point" ;
            id = EMyAppControlIdFixEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = FIXPTED
                {
                min = 0;
                max = 99999;
                decimalplaces = 2;
                };
            },
        DLG_LINE
            {
            type = EEikCtDateEditor;
            prompt = "Date" ;
            id = EMyAppControlIdDateEd ;
            itemflags = EEikDlgItemTakesEnterKey;
            control = DATE_EDITOR
                {
                minDate = DATE { year = 1900; };
                maxDate= DATE { year = 2100; };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EEikCtTimeEditor;
            prompt = "Time";
            id = EMyAppControlIdTimeEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = TIME_EDITOR
                {
                minTime = TIME {};
                maxTime = TIME { second = 59; minute = 59; hour = 23; };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EEikCtDurationEditor;
            prompt = "Duration";
            id = EMyAppControlIdDurationEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = DURATION_EDITOR
                {
                minDuration = DURATION {};
                maxDuration = DURATION { seconds = 3599; };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EAknCtNumericSecretEditor;
            prompt = "Secret number";
            id = EMyAppControlIdNumPwdEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = NUMSECRETED { num_code_chars = 4; };
            },
        DLG_LINE
            {
            type = EEikCtSecretEd;
            prompt = "Secret text";
            id = EMyAppControlIdAlphaPwdEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = SECRETED { num_letters = 8; };
            },
        DLG_LINE
            {
            type = EAknCtIpFieldEditor;
            prompt = "IP address";
            id = EMyAppControlIdIpAddrEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = IP_FIELD_EDITOR
                {
                min_field_values = IP_FIELD
                    {
                    first_field = 0;
                    second_field = 0;
                    third_field = 0;
                    fou?th_field = 0;
                    };
                max_field_values = IP_FIELD
                    {
                    first_field = 255;
                    second_field = 255;
                    third_field = 255;
                    fourth_field = 255;
                    };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EAknCtPopupField;
            prompt = "Popup field";
            id = EMyAppControlIdPopupField;
            itemflags = EEikDlgItemTakesEnterKey;
            control = POPUP_FIELD
                {
                flags = EAknPopupFieldFlagAllowsUserDefinedEntry;
                width = 50;
                other = "Other";
                empty = "No items";
                invalid = "Invalid item";
                };
            },
        DLG_LINE
            {
            type = EAknCtPopupFieldText;
            prompt = "Popup field text";
            id = EMyAppControlIdPopupFieldText;
            itemflags = EEikDlgItemTakesEnterKey;
            control = POPUP_FIELD_TEXT
                {
                textarray = r_my_list_popup_items;
                popupfield = POPUP_FIELD {};
                active = 0;
                };
            },
        DLG_LINE
            {
            type = EAknCtSlider;
            prompt = "Slider";
            id = EMyAppControlIdSlider;
            itemflags = EEikDlgItemTakesEnterKey;
            control = SLIDER
                {
                layout = EAknFormSliderLayout2;
                minvalue = 0;
                maxvalue = 20;
                step = 2;
                valuetype = EAknSliderValueNone;
                minlabel = "few";
                maxlabel = "many";
                valuelabel = "Slider value";
                };
            }
        };
    }
RESOURCE ARRAY r_my_list_popup_items
    {
    items =
        {
        LBUF { txt = "Monday"; },
        LBUF { txt = "Tuesday"; },
        LBUF { txt = "Wednesday"; },
        LBUF { txt = "Thursday"; },
        LBUF { txt = "Friday"; },
        LBUF { txt = "Saturday"; },
        LBUF { txt = "Sunday"; }
        };
    }

2.1.2 Multi-page form

Multi-page forms also use the DIALOG resource structure, but DIALOG structure member pages are needed as a reference to an ARRAY of PAGE . The PAGE structure is as follows:

STRUCT PAGE
    {
    WORD id = 0;
    LTEXT text;
    LTEXT bmpfile = "";
    WORD bmpid = 0xffff;
    WORD bmpmask;
    LLINK lines = 0;
    LLINK form = 0;
    WORD flags = 0;
    }

The following members are concerned with forms in the PAGE structure:

The following resource defines a form for viewing and editing TMyStruct data in a multi-page dialog. The DLG_LINE structures are identical to the single-page example (except that the first page is decorated with icons).

RESOURCE DIALOG r_my_multipage_dialog
    {
    flags = EEikDialogFlagNoBorder | EEikDialogFlagNoDrag  |
            EEikDialogFlagNoTitleBar | EEikDialogFlagFillAppClientRect |
            EEikDialogFlagCbaButtons  | EEikDialogFlagWait;
    buttons = R_AVKON_SOFTKEYS_OPTIONS_BACK ;
    pages = r_my_pages;
    }
RESOURCE ARRAY r_my_pages
    {
    items =
        {
        PAGE { text = "text"; id = EMyAppPage1 ; form = r_my_form_1 ; },
        PAGE { text = "number"; id = EMyAppPage2 ; form = r_my_form_2 ; },
        PAGE { text = "misc"; id = EMyAppPage3 ; form = r_my_form_3 ; }
        };
    }
RESOURCE FORM r_my_form_1
    {
    flags = EEikFormUseDoubleSpacedFormat | EEikFormShowBitmaps;
    items =
        {
        DLG_LINE
            {
            type = EEikCtEdwin;
            prompt = "Text" ;
            id = EMyAppControlIdTextEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = EDWIN
                {
                flags = KMultiLineExpandingEditorFlags |
                        EEikEdwinNoLineOrParaBreaks;
                maxlength = 256;
                width = 6;
                };
            bmpfile = AVKON_ICON_FILE;
            bmpid = EMbmAvkonQgn_prop_folder_small;
            bmpmask = EMbmAvkonQgn_prop_folder_small_mask;
            },
        DLG_LINE
            {
            type = EEikCtGlobalTextEditor;
            prompt = "Global text";
            id = EMyAppControlIdGlobalTextEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = GTXTED
                {
                width = 10;
                height = 17;
                textlimit = 256;
                flags = KMultiLineExpandingEditorFlags;
                max_view_height_in_lines = 2;
                };
            bmpfile = AVKON_ICON_FILE;
            bmpid = EMbmAvkonQgn_prop_folder_small;
            bmpmask = EMbmAvkonQgn_prop_folder_small_mask;
            },
        DLG_LINE
            {
            type = EEikCtRichTextEditor;
            prompt = "Rich text";
            id = EMyAppControlIdRichTextEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = RTXTED
                {
                width = 10;
                height = 17;
                textlimit = 256;
                flags = KMultiLineExpandingEditorFlags;
                max_view_height_in_lines = 3;
                };
            bmpfile = AVKON_ICON_FILE;
            bmpid = EMbmAvkonQgn_prop_folder_small;
            bmpmask = EMbmAvkonQgn_prop_folder_small_mask;
            }
        };
    }
RESOURCE FORM r_my_form_2
    {
    flags = EEikFormUseDoubleSpacedFormat;
    items =
        {
        DLG_LINE
            {
            type = EEikCtNumberEditor;
            prompt = "Number" ;
            id = EMyAppControlIdNumberEd ;
            control = NUMBER_EDITOR
                {
                min = 0;
                max = 999;
                };
            },
        DLG_LINE
            {
            type = EAknCtIntegerEdwin;
            prompt = "Integer edwin" ;
            id = EMyAppControlIdIntegerEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = AVKON_INTEGER_EDWIN
                {
                maxlength = 10;
                min = 0;
                max = 999;
                };
            },
        DLG_LINE
            {
            type = EEikCtFlPtEd;
            prompt = "Floating point" ;
            id = EMyAppControlIdFloatEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = FLPTED
                {
                maxlength = 10;
                min = 0;
                max = 999;
                };
            },
        DLG_LINE
            {
            type=EEikCtFxPtEd;
            prompt = "Fixed point" ;
            id = EMyAppControlIdFixEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = FIXPTED
                {
                min = 0;
                max = 99999;
                decimalplaces = 2;
                };
            },
        DLG_LINE
            {
            type = EEikCtDateEditor;
            prompt = "Date" ;
            id = EMyAppControlIdDateEd ;
            itemflags = EEikDlgItemTakesEnterKey;
            control = DATE_EDITOR
                {
                minDate = DATE { year = 1900; };
                maxDate= DATE { year = 2100; };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EEikCtTimeEditor;
            prompt = "Time";
            id = EMyAppControlIdTimeEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = TIME_EDITOR
                {
                minTime = TIME {};
                maxTime = TIME { second = 59; minute = 59; hour = 23; };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EEikCtDurationEditor;
            prompt = "Duration";
            id = EMyAppControlIdDurationEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = DURATION_EDITOR
                {
                minDuration = DURATION {};
                maxDuration = DURATION { seconds = 3599; };
                flags = 0;
                };
            }
        };
    }
RESOURCE FORM r_my_form_3
    {
    flags = EEikFormUseDoubleSpacedFormat;
    items =
        {
        DLG_LINE
            {
            type = EAknCtNumericSecretEditor;
            prompt = "Secret number";
            id = EMyAppControlIdNumPwdEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = NUMSECRETED { num_code_chars = 4; };
            },
        DLG_LINE
            {
            type = EEikCtSecretEd;
            prompt = "Secret text";
            id = EMyAppControlIdAlphaPwdEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = SECRETED { num_letters = 8; };
            },
        DLG_LINE
            {
            type = EAknCtIpFieldEditor;
            prompt = "IP address";
            id = EMyAppControlIdIpAddrEd;
            itemflags = EEikDlgItemTakesEnterKey;
            control = IP_FIELD_EDITOR
                {
                min_field_values = IP_FIELD
                    {
                    first_field = 0;
                    second_field = 0;
                    third_field = 0;
                    fourth_field = 0;
                    };
                max_field_values = IP_FIELD
                    {
                    first_field = 255;
                    second_field = 255;
                    third_field = 255;
                    fourth_field = 255;
                    };
                flags = 0;
                };
            },
        DLG_LINE
            {
            type = EAknCtPopupField;
            prompt = "Popup field";
            id = EMyAppControlIdPopupField;
            itemflags = EEikDlgItemTakesEnterKey;
            control = POPUP_FIELD
                {
                flags = EAknPopupFieldFlagAllowsUserDefinedEntry;
                width = 50;
                other = "Other";
                empty = "No items";
                invalid = "Invalid item";
                };
            },
        DLG_LINE
            {
            type = EAknCtPopupFieldText;
            prompt = "Popup field text";
            id = EMyAppControlIdPopupFieldText;
            itemflags = EEikDlgItemTakesEnterKey;
            control = POPUP_FIELD_TEXT
                {
                textarray = r_my_list_popup_items;
                popupfield = POPUP_FIELD {};
                active = 0;
                };
            },
        DLG_LINE
            {
            type = EAknCtSlider;
            prompt = "Slider";
            id = EMyAppControlIdSlider;
            itemflags = EEikDlgItemTakesEnterKey;
            control = SLIDER
                {
                layout = EAknFormSliderLayout2;
                minvalue = 0;
                maxvalue = 20;
                step = 2;
                valuetype = EAknSliderValueNone;
                minlabel = "few";
                maxlabel = "many";
                valuelabel = "Slider value";
                };
            }
        };
    }

2.2 Launching the form

The following example code initializes sample data before invoking the form.

// Create example dynamic list for the popup field.
CDesCArray* array = new (ELeave) CDesCArrayFlat( 8 );
CleanupStack::PushL( array );
array->AppendL( _L("January") );
array->AppendL( _L("February") );
array->AppendL( _L("March") );
array->AppendL( _L("April") );
array->AppendL( _L("May") );
array->AppendL( _L("June") );
CAknQueryValueTextArray* textArray = CAknQueryValueTextArray::NewLC();
textArray->SetArray( *array );
CAknQueryValueText* queryVal = CAknQueryValueText::NewLC();
queryVal->SetArrayL( textArray );
queryVal->SetCurrentValueIndex( 0 );
// Initialize example form data.
TMyData myData;
myData.iText = _L("This is a text.");
myData.iGlobalText = _L("This is global text.");
myData.iRichText = _L("This is rich text.");
myData.iNumber = 5;
myData.iInteger = 5;
myData.iFloat = 1.234;
myData.iFix = 12345;
myData.iDate.HomeTime();
myData.iTime.HomeTime();
myData.iDuration = TTimeIntervalSeconds( 1000 );
myData.iNumPwd = _L("1234");
myData.iAlphaPwd = _L("passwd");
myData.iIpAddr = TInetAddr();
myData.iPopupVal = queryVal;
myData.iPopupTextIndex = 2;
myData.iSliderVal = 10;
// Launch the dialog to view/edit data
CAknForm* dlg = new ( ELeave ) CMyForm( myData );
CleanupStack::PushL( dlg );
dlg->ConstructL( 0 ); // default menu items only
CleanupStack::Pop( dlg );
dlg->ExecuteLD( R_MY_DIALOG );
// myData now contains the edited values.
CleanupStack::PopAndDestroy( queryVal );
CleanupStack::PopAndDestroy( textArray );
CleanupStack::PopAndDestroy( array );

2.3 Initializing form data

PreLayoutDynInitL() can be overridden to initialize form controls.

void CMyForm::PreLayoutDynInitL()
    {
    CAknForm::PreLayoutDynInitL();
    LoadFormDataL();
    }
void CMyForm::LoadFormDataL()
    {
    CEikEdwin* textEd =
        (CEikEdwin*)Control( EMyAppControlIdTextEd );
    textEd->SetTextL( &iData.iText );
    CEikGlobalTextEditor* globalTextEd =
        (CEikGlobalTextEditor*)Control( EMyAppControlIdGlobalTextEd );
    globalTextEd->SetTextL( &iData.iGlobalText );
    CEikRichTextEditor* richTextEd =
        (CEikRichTextEditor*)Control( EMyAppControlIdRichTextEd );
    richTextEd->SetTextL( &iData.iRichText );
    CEikNumberEditor* numberEd =
        (CEikNumberEditor*)Control( EMyAppControlIdNumberEd );
    numberEd->SetNumber( iData.iNumber );
    CAknIntegerEdwin* integerEd =
        (CAknIntegerEdwin*)Control( EMyAppControlIdIntegerEd );
    integerEd->SetValueL( iData.iInteger );
    CEikFloatingPointEditor* floatEd =
        (CEikFloatingPointEditor*)Control( EMyAppControlIdFloatEd );
    floatEd->SetValueL( &iData.iFloat );
    CEikFixedPointEditor* fixEd =
        (CEikFixedPointEditor*)Control( EMyAppControlIdFixEd );
    fixEd->SetValueL( &iData.iFix );
    CEikDateEditor* dateEd =
        (CEikDateEditor*)Control( EMyAppControlIdDateEd );
    dateEd->SetDate( iData.iDate );
    CEikTimeEditor* timeEd =
        (CEikTimeEditor*)Control( EMyAppControlIdTimeEd );
    timeEd->SetTime( iData.iTime );
    CEikDurationEditor* durationEd =
        (CEikDurationEditor*)Control( EMyAppControlIdDurationEd );
    durationEd->SetDuration( iData.iDuration );
    CAknNumericSecretEditor* numPwdEd =
        (CAknNumericSecretEditor*)Control( EMyAppControlIdNumPwdEd );
    numPwdEd->SetText( iData.iNumPwd );
    CEikSecretEditor* alphaPwdEd =
        (CEikSecretEditor*)Control( EMyAppControlIdAlphaPwdEd );
    alphaPwdEd->SetText( iData.iAlphaPwd );
    CAknIpFieldEditor* ipAddrEd =
        (CAknIpFieldEditor*)Control( EMyAppControlIdIpAddrEd );
    ipAddrEd->SetAddress( iData.iIpAddr );
    iData.iPopupVal->SetCurrentValueIndex( 0 );
    CAknPopupField* popupField =
        (CAknPopupField*)Control( EMyAppControlIdPopupField );
    popupField->SetQueryValueL( iData.iPopupVal );
    CAknPopupFieldText* popupFieldText =
        (CAknPopupFieldText*)Control( EMyAppControlIdPopupFieldText );
    popupFieldText->SetCurrentValueIndex( iData.iPopupTextIndex );
    CAknSlider* slider =
        (CAknSlider*)Control( EMyAppControlIdSlider );
    slider->SetValueL( iData.iSliderVal );
    }

2.4 Saving form data

Pressing the Back softkey in the edit state causes calls to QuerySaveChangesL() then SaveFormDataL() or DoNotSaveFormDataL() . The following example saves data from form controls to the data structure.

TBool CMyForm::SaveFormDataL()
    {
    CEikEdwin* textEd =
        (CEikEdwin*)Control( EMyAppControlIdTextEd );
    textEd->GetText( iData.iText );
    CEikGlobalTextEditor* globalTextEd =
        (CEikGlobalTextEditor*)Control( EMyAppControlIdGlobalTextEd );
    globalTextEd->GetText( iData.iGlobalText );
    CEikRichTextEditor* richTextEd =
        (CEikRichTextEditor*)Control( EMyAppControlIdRichTextEd );
    richTextEd->GetText( iData.iRichText );
    CEikNumberEditor* numberEd =
        (CEikNumberEditor*)Control( EMyAppControlIdNumberEd );
    iData.iNumber = numberEd->Number();
    CAknIntegerEdwin* integerEd =
        (CAknIntegerEdwin*)Control( EMyAppControlIdIntegerEd );
    (void)integerEd->GetTextAsInteger( iData.iInteger );
    CEikFloatingPointEditor* floatEd =
        (CEikFloatingPointEditor*)Control( EMyAppControlIdFloatEd );
    (void)floatEd->GetValueAsReal( iData.iFloat );
    CEikFixedPointEditor* fixEd =
        (CEikFixedPointEditor*)Control( EMyAppControlIdFixEd );
    (void)fixEd->GetValueAsInteger( iData.iFix );
    CEikDateEditor* dateEd =
        (CEikDateEditor*)Control( EMyAppControlIdDateEd );
    iData.iDate = dateEd->Date();
    CEikTimeEditor* timeEd =
        (CEikTimeEditor*)Control( EMyAppControlIdTimeEd );
    iData.iTime = timeEd->Time();
    CEikDurationEditor* durationEd =
        (CEikDurationEditor*)Control( EMyAppControlIdDurationEd );
    iData.iDuration = durationEd->Duration();
    CAknNumericSecretEditor* numPwdEd =
        (CAknNumericSecretEditor*)Control( EMyAppControlIdNumPwdEd );
    numPwdEd->GetText( iData.iNumPwd );
    CEikSecretEditor* alphaPwdEd =
        (CEikSecretEditor*)Control( EMyAppControlIdAlphaPwdEd );
    alphaPwdEd->GetText( iData.iAlphaPwd );
    CAknIpFieldEditor* ipAddrEd =
        (CAknIpFieldEditor*)Control( EMyAppControlIdIpAddrEd );
    iData.iIpAddr = ipAddrEd->Address();
    iData.iPopupVal->SetCurrentValueIndex( 0 );
    CAknPopupField* popupField =
        (CAknPopupField*)Control( EMyAppControlIdPopupField );
    popupField->SetQueryValueL( iData.iPopupVal );
    CAknPopupFieldText* popupFieldText =
        (CAknPopupFieldText*)Control( EMyAppControlIdPopupFieldText );
    iData.iPopupTextIndex = popupFieldText->CurrentValueIndex();
    CAknSlider* slider =
        (CAknSlider*)Control( EMyAppControlIdSlider );
    iData.iSliderVal = slider->Value();
    return ETrue;
    }

Forms can validate the entered data. SaveFormDataL() should return EFalse if validation failed, this indicates that the data has not been saved. In this case, the form remains in edit state.

2.5 Reverting changes

DoNotSaveFormDataL() is called if the user responds No in QuerySaveChangesL() . The form should restore the original data.

void CMyForm::DoNotSaveFormDataL()
    {
    LoadFormDataL();
    }

2.6 Modifying the menu

CAknForm always uses menu pane R_AVKON_FORM_MENUPANE . This menu pane contains the following commands:

Command Description
EAknFormCmdEdit Switches to edit mode (if allowed).
EAknFormCmdAdd Adds field. Method AddFieldL() is called. Default

implementation is empty.

EAknFormCmdSave Saves and switches to view mode. SaveFormDataL() is

called. Default implementation is empty.

EAknFormCmdLabel Edits field label. Default implementation is provided.
EAknFormCmdDelete Deletes field. DeleteCurrentItemL() is called. Default

implementation is empty.

EAknFormMaxDefault End marker for the enumeration.

CAknForm handles these commands and their associated menu items.

DynInitMenuPaneL() allows modifying the menu. The following example appends the items of a custom menu pane to the form menu:

RESOURCE MENU_PANE r_my_extra_menu
    {
    items =
        {
        MENU_ITEM { command = EMyCommand; txt = "Dynamic menu item"; }
        };
    }
void CMyForm::DynInitMenuPaneL( TInt aResourceId, CEikMenuPane* aMenuPane )
    {
    CAknForm::DynInitMenuPaneL( aResourceId, aMenuPane );
    if ( aResourceId == R_AVKON_FORM_MENUPANE )
        {
        aMenuPane->AddMenuItemsL
            ( R_MY_EXTRA_MENU, EAknFormMaxDefault - 1, ETrue );
        }
    }

The same effect can achieved by passing the ID of a MENU_BAR resource to CAknForm::ConstructL() . Menu items from R_MY_MENUBAR will be appended to R_AVKON_FORM_MENUPANE :

RESOURCE MENU_BAR r_my_menubar
    {
    titles=
        {
        MENU_TITLE { menu_pane = r_my_extra_menu; txt=""; }
        };
    }
// Launch the dialog to view/edit data
CAknForm* dlg = new ( ELeave ) CMyForm( myData );
CleanupStack::PushL( dlg );
dlg->ConstructL( R_MY_MENUBAR );
CleanupStack::Pop( dlg );
dlg->ExecuteLD( R_MY_DIALOG );
// myData now contains edited values.

2.7 Processing commands

ProcessCommandL() can be overridden to handle custom commands. Built-in form commands are handled by CAknForm .

void CMyForm::ProcessCommandL( TInt aCommandId )
    {
    // Form default commands.
    CAknForm::ProcessCommandL( aCommandId );
    // Custom commands.
    switch ( aCommandId )
        {
        case EMyCommand:
            User::InfoPrint( _L("my command") );
            break;
        default:
            break;
        }
    }

2.8 Managing fields

In edit mode, fields can be added or deleted dynamically. CAknForm::AddItemL() and CAknForm::DeleteCurrentItemL() provide default implementation for handling the commands EAknFormCmdAdd and EAknFormCmdDelete , respectively.

The following sample adds an editor control.

void CMyForm::AddItemL()
    {
    _LIT( caption, "Added text" );
    TInt pageId = ActivePageId();
    TInt id = iAddedItemId++; // All controls must have unique id.
    TInt type = EEikCtEdwin;
    TAny* unused=0;
    CEikEdwin* edwin = (CEikEdwin*)CreateLineByTypeL
        ( caption, pageId, id, type, unused );
    edwin->ConstructL
        ( EEikEdwinNoHorizScrolling | EEikEdwinResizable, 10, 100, 1 );
    Line( id )->ActivateL();
    SetChangesPending( ETrue );
    UpdatePageL( ETrue );
    }

Note that all controls in the dialog must have a unique ID. The sample code uses its iAddedItemId member to ensure that IDs are unique, but does not store the IDs of the dynamically created controls. Real-life implementations need the IDs to access field data later.

enum TMyControlIds
    {
    EMyAppControlIdTextEd = 100,
    EMyAppControlIdGlobalTextEd,
    EMyAppControlIdRichTextEd,
    EMyAppControlIdNumberEd,
    EMyAppControlIdIntegerEd,
    EMyAppControlIdFloatEd,
    EMyAppControlIdFixEd,
    EMyAppControlIdDateEd,
    EMyAppControlIdTimeEd,
    EMyAppControlIdDurationEd,
    EMyAppControlIdNumPwdEd,
    EMyAppControlIdAlphaPwdEd,
    EMyAppControlIdIpAddrEd,
    EMyAppControlIdPopupField,
    EMyAppControlIdPopupFieldText,
    EMyAppControlIdSlider,
    EMyAppControlIdFirstAdded   // Dynamically added items
    };
CMyForm::CMyForm( TMyData& aData ) : iData( aData ), iAddedItemId( EMyAppControlIdFirstAdded ) {} // Need unique control ids.

Adding fields dynamically is also useful if the form is used to manipulate data which has a variable structure. In this case, the FORM structure can be left empty in the resource definition, and PreLayoutDynInitL() can be used to add appropriate fields as necessary.

2.9 Adding custom field

Custom controls can be added to dialogs by overriding CreateCustomControlL() , as described in document S60 3.1 Dialogs API Specification.

In order to support laying out the custom control in forms, the method ConvertCustomControlTypeToBaseControlType() must be provided. This method determines the layout class of the custom control.

MEikDialogPageObserver::TFormControlTypes
CMyForm::ConvertCustomControlTypeToBaseControlType( TInt aControlType ) const
    {
    if ( aControlType == EAknCtIpFieldEditor )
        {
        // Help layout of custom control.
        return MEikDialogPageObserver::EMfneDerived;
        }
    return CAknForm::ConvertCustomControlTypeToBaseControlType( aControlType );
    };

2.10 Error handling

Form API uses standard Symbian OS error reporting mechanism and standard error codes.

2.11 Memory and Performance Considerations

Memory consumption of dialogs depends on the contained controls.

3 Glossary

3.1 Abbreviations

Form API abbreviations
API Application Programming Interface
CBA Command Button Area
OS Operating System
SDK Software Development Kit

3.2 Definitions

Form API definitions
Softkey A command button mapped to a hard key on the device.

4 References

Form API references
S60 3.1 Dialogs API Specification
S60 3.1 Editors API Specification