Popups API: Using Popups API

Initialization of the popup list

Basic Initialization

The first thing a developer needs when dealing with popup list is a list (using lists is not a subject of this document, if you want a thorough list usage guide then consult the header link List API document.)

As the list itself needs a parent we cannot initialize the list before creating the popup list. So the proper order is:

  1. Construct the list using the standard leaving new operator.
  2. Create the popup list using its NewL() static function.
  3. Finally initialize the list (Call its ConstructL() ) .

In the code below and hereinafter we will use an imaginary client class called CMyClient.

CMyClient::ShowMyPopupListL()
    {
    // Create a list instance:
    CEikListBox* list = new( ELeave ) CAknSinglePopupMenuStyleListBox;
    CleanupStack::PushL( list );//prevent memory leaks
     
    // Couple the popup with the list:
    // We need to create the popup now as list would need it as a parent.
    CAknPopupList* popup = CAknPopupList::NewL( 
                 list, // passing our list to the popup
                       // ownership is not taken
                 R_AVKON_SOFTKEYS_OK_BACK, // softkey resource id.
                 AknPopupLayouts::EMenuWindow);// popup layout type
    CleanupStack::PushL( popup );
    list->ConstructL( popup,CEikListBox::ELeftDownInViewRect );
    // Finish list initialization:
    list->View()->SetListEmptyTextL( _L( "List is empty" ) );
    list->CreateScrollBarFrameL( ETrue );
    list->ScrollBarFrame()->SetScrollBarVisibilityL(
                    CEikScrollBarFrame::EOff,
                    CEikScrollBarFrame::EAuto);
    // Add items to the list:
    CDesCArrayFlat* items = new(ELeave)CDesCArrayFlat( 1 );
    CleanupStack::PushL( items );
    for ( TInt ii=0; ii<8; ii++ )
        {
        TBuf<80> text;
        text.Format( _L( "Listbox Item %d" ), ii+1 );
        items->AppendL( text );
        }

    CleanupStack::Pop(); // items
    CTextListBoxModel* model=list->Model();
    model->SetItemTextArray( items );
    model->SetOwnershipType( ELbmOwnsItemArray );
    …   
    }

It is important to note that CAknPopupList::NewL() takes an AknPopupLayouts::TAknPopupLayouts parameter which provides the popup with layout info (i.e. how exactly are position and size of the popup and the contained components). To avoid an unwanted look you need find out the right value based on the list type you use. See header AknPopupLayout.h classAknPopupLayouts.

Enabling find box

It is also possible to add a find box to the popup. It is mostly important when the number of items in the list can be high so the user can filter the list items while typing: only the items which match the typed characters are shown. This is how the initialization code needs to be augmented.

CMyClient::ShowMyPopupListL()
    {
    … // code from initialisation section
    popup->EnableFind();
    	
    }

The CAknPopupList EnableFind() call returns a TBool to indicate if construction was successful. Use it if you want to have error handling code for the failure case.

Showing the popup list

After initialization the popup is ready to be displayed. It is fairly simple to do.

CMyClient::ShowMyPopupListL()
    {
    … // code from initialisation section (with or without the optional part
    popup->ExecuteLD();	
    CleanupStack::Pop(); //popup
    CleanupStack::PopAndDestroy(); //list
    }

The code above does not process user input, which is unlikely to be acceptable in a real situation.

Notice CleanupStack::Pop() after ExecuteLD(), that is required as during the initialization the popup was put on the cleanup stack. Removing it from there should be done after ExecuteLD(). ExecuteLD() deletes the popup so PopAndDestoy() is not recommended). This ensures leave-safety. Note if the popup is declared as a member of the class then you would need to set it to NULL after the ExecuteLD() to avoid double deleting in the destructor. Of course in this case the popup must not be pushed on the cleanup stack.

The list object has to be destroyed as the popup does not take care of that. That is done by the final PopAndDestroy().

ExecuteLD() displays the popup on the screen and does not return until the user dismisses it or a CancelPopup() is called in the code. This however is a non-blocking function from the whole application point of view. This means that the application can still receive all kinds of events (e.g. network events, timer events). The technique the popup uses is the same as with dialogs – it nests a new active scheduler loop. Being aware of this is important, another event handling code (i.e. CActive::RunL() ) may still be running while the popup is shown. If you need to access the popup while its ExecuteLD() is running then it should be declared as a member variable.

Retrieving user response

In a usual scenario it is natural to expect that the client can get hold of the user response (let it be the selected item or the marked item). There are two aspects of it:

  1. Did the user dismiss the popup indicating a cancellation of a started operation?
  2. If the user accepted the prompt what was the response?

To find an answer to the first question the return value of ExecuteLD() needs to be checked. The user response on the other hand can be received from reading the list state.

CMyClient::ShowMyPopupListL()
    {
    … // code from initialisation section (with or without the optional part
    if ( popup->ExecuteLD() )
        {
        TInt index = iList->CurrentItemIndex();
        TBuf<50> text;
        text.Format(_L("Item %d selected"), index+1);
        User::InfoPrint(text);
        }
     else
        {
        User::InfoPrint(_L("Listbox Cancelled"));
        }
    CleanupStack::Pop(); //popup
    CleanupStack::PopAndDestroy(); //list
    }

Dismissing the popup list

While the popup is shown all user events are forwarded to it. However it is possible to get other events from the system. Some events would result in a new UI state where the popup is not needed anymore. The developer has the means to dismiss the popup programmatically. To be able to do that the popup has to be accessible through a member variable. We assume that the iPopup member variable points to the popup list object (or NULL if it is dismissed).

CMyClient::DismissPopupListL()
    {
    if ( iPopup )//Checking for NULL is needed because if the popup is dismissed iPopup is set to NULL
        {
        iPopup->CancelPopup();
        iPopup = NULL;
        }
    }

The CancelPopup() call makes the ExecuteLD() call return (in the next active scheduler loop) and its return value is EFalse indicating cancellation.

Note: It is not possible to use delete iPopup instead of iPopup->CancelPopup() because the destructor of CAknPopupList is a protected method.

Customizing popup lists

CAknPopupList may be derived in order to provide a specific type of popup list. That is, for a text-only popup selection list, the NewL() function may be overloaded in order to create a listbox of a specific type, before passing it to the CAknPopupList::NewL() function.

It maybe necessary to override the AttemptExitL() function to save the return value in that (e.g. if you do want to store the return value in pointer passed on construction).

By overriding OfferKeyEventL() it is possible to make the derived popup list react to key events that the base class ignored (e.g. it can delete an item from the list when Clear key is pressed).

ProcessCommandL should be overwritten when new nonstandard commandIDs are attached to the CBA in the resource. By default the following Avkon command ids are handled as a positive reply (OK) to the popup list: EAknSoftkeySelect, EAknSoftkeyYes, EAknSoftkeyOk, EAknSoftkeyDone.

Whereas EAknSoftkeyExit, EAknSoftkeyClose, EAknSoftkeyNo, EAknSoftkeyCancel, EAknSoftkeyBack are handled as a negative answer from the user.

Note: If you want to provide a more specific popup list through derivation do not forget to hide the functions of the base class that you do not intend to expose to the users.

Accessing popup heading

As we said earlier, popup heading is used not only by popup list, but also by other UI components. The heading is implemented by the class CAknPopupHeadingPane.

Typical use-cases for popup heading:

More information about the query dialogs can be found in Queries API documentation.

In case of popup list, the heading cannot be set from resource - it can be set only from code. After setting the title with SetTitleL() with a non empty text, CAknPopupList::Heading() should return the CAknPopupHeadingPane object associated with the heading of the popup:

CMyClient::ShowMyPopupListL()
    {
    … // code from initialisation section
    popup->SetTitleL( _L( "My popup title" ) );
    CAknPopupHeadingPane* heading = popup->Heading();
    …
    }

In case of queries, CAknQueryDialog::QueryHeading() should return the CAknPopupHeadingPane object associated with the heading of the query (see Queries API documentation):

CMyClient::ShowMyMessageQueryL()
    {
    … // initialization of message, heading
    CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL(*message);
    dlg->PrepareLC(R_AVKON_MESSAGE_QUERY_DIALOG);
    dlg->QueryHeading()->SetTextL(*header);
    dlg->RunLD();
    … // releasing message, heading
    }

Setting text to popup heading

In case of queries, heading text is usually defined in the resource (see Queries API documentation), but there is the possibility to set the text from code with the help of the CAknPopupHeadingPane::SetTextL() method.

In case of popup list, it is optional to add a title to the popup during initialization. It will implicitly create a heading object (to which it is possible to get a pointer) in the popup.

CMyClient::ShowMyPopupListL()
    {
    … // code from initialisation section
    popup->SetTitleL( _L( "My popup title" ) );
    …	
    }

Manipulation of the image

We can enhance the look of the popup heading by decorating it with an image.

The following example illustrates the setting of a header image in case of a popup list:

CMyClient::ShowMyPopupListL()
    {
    … // code from initialisation section
    popup->SetTitleL( _L( "My popup title" ) );
    CAknPopupHeadingPane* heading = popup->Heading();
    if ( heading )
        {
        _LIT( KMyImageLocation, "c:\\flower.mbm" );
        CEikImage* img = new (ELeave) CEikImage();
        CleanupStack::PushL( img );
        img->CreatePictureFromFileL( KMyImageLocation, 0, 1 );
        heading->SetHeaderImageL( img );
        CleanupStack::PopAndDestroy();//img
        }
     …
     }

Note: the CAknPopupHeadingPane object is created inside the popup list using a lazy construction method. That is it only is constructed when needed. In this particular case that happens after the popup->SetTitleL() call.

Manipulation of the animation

It is also possible to add an animation to the heading in a similar way. There CAknPopupHeadingPane::SetHeaderAnimationL() needs to be passed the resource ID associated with the animation. The animation is started automatically but can be controlled externally through CAknPopupHeadingPane::StartAnimationL and CancelAnimation() functions.

Error handling

Popups API uses standard Symbian OS error reporting mechanism. It does not define any panic codes of its own. Leaves and system wide error codes as the function return values are used if the error is recoverable. A client application can handle these errors similarly as a normal Symbian platform application.

Memory overhead

Memory consumption of popup list largely depends on the list added to it and the number of list items that are contained in a static list model. A popup list and a popup heading have a very minimal overhead.

Limitations of the API

This API cannot be used by a component without a UI environment (e.g. a Symbian OS server process cannot use the API). The API does not have functionality for a dedicated Options menu to the popup.


Copyright © Nokia Corporation 2001-2008
Back to top