Menus

Menus

A menu is a window that presents a list of commands to the user. A menu is arranged into lines, known as menu items, each of which contains a text label. When a user selects a menu item, the appropriate command is invoked. Figure 5-6 shows an example menu from a game application.

Figure 5-6. Example menu.


Series 60 applications usually group commands together on the Options menu, which appears when the Options soft key is pressed. Applications can also display context-sensitive menus, activated when a particular keyfor example, the Selection keyis pressed. You would use this type of menu when there is no single intuitive function that could occur when a particular key is pressed. For example, you might be writing an application that displays a list of text itemsyou must decide what the user would expect to happen when they press a particular key on a focused item. In some applications, it would be obvious that the item should open, in which case there would be no need for a context-sensitive menu. In other applications, it might be appropriate to either open or delete the itemin this case, you could use a context-sensitive menu to give the user both options.

You can add menus to the main application screen, its views, dialogs, and some of its other controls. They appear in a pop-up window just above the left soft key. As you can see in Figure 5-6, once the menu is displayed, the soft key labels change, so that the user can select a menu item with the left ( Select ) soft key and close the menu with the right ( Cancel ) soft key. Pressing the Selection key also opens the focused menu item.

Submenus

A menu item can contain a submenu. A submenu groups a further set of commands, which are relevant to a menu item. For example, a two-player card game might have an additional menu item to play a two-player game, which has a submenu offering to play via IR, or via SMS, as shown in Figure 5-7.

Figure 5-7. A submenu.


You can open the submenu by focusing the item and pressing the left ( Select ) soft key, Selection key, or right direction key. You close it by pressing the right ( Cancel ) soft key (which closes the entire menu) or the left direction key (which closes just the submenu).

It is only possible to have one level of submenumenu items in submenus may not themselves have submenus.


To make a menu as usable as possible, you should try to keep the number of items on a submenu small. You should also ensure that a submenu never contains an item that is available at the previous level.

Menu Basics

This subsection looks at the SimpleMenu example application, which makes basic use of menus. The application illustrates how to:

  • Define a menu using resources.

  • Define a submenu using resources.

  • Use a menu in a control.

  • Handle menu commands.

  • Handle submenu commands.

The SimpleMenu example displays a blank screen and has Options and Back soft keys. The Options soft key displays the Options menu, and this has two menu items: New Game and Exit , as shown in Figure 5-8.

Figure 5-8. SimpleMenu Options menu.


Exit closes the application. (Note that you can also close the application by selecting the right soft key, which is set to Back on the main screen, but is also often set to Exit in many other applications.) New Game has a submenu with items allowing you to choose a connection method for playing a multiplayer game, as shown in Figure 5-9.

Figure 5-9. SimpleMenu New Game submenu.


Defining a Menu Using Resources

You define the menu in a MENU_BAR resource, as shown in SimpleMenu.rss :

 RESOURCE MENU_BAR r_simplemenu_menu_bar    {    titles =       {       MENU_TITLE          {          txt = ""; // the text is not used in Series 60          menu_pane = r_simplemenu_menu_pane;          }       };    } 

A MENU_BAR usually contains a single MENU_TITLE , contained within the titles array. This specifies the title of the menu, and a menu pane containing its menu items. Series 60 does not use the menu title's txt field, so you can set it to blank. It is sometimes helpful to provide a label, however, as a reminder of the menu function, and to increase portability to other Symbian OS platforms which require it.

The MENU_PANE resource referenced from the MENU_BAR resource contains the menu items, each represented by a MENU_ITEM resource:

 RESOURCE MENU_PANE r_simplemenu_menu_pane    {    items =       {       MENU_ITEM          {          command = ESimpleMenuCmdNewGame;          txt = NEW_GAME_TEXT;          cascade = r_simplemenu_game_submenu_menu_pane;          },       MENU_ITEM          {          command = EAknCmdExit;          txt = EXIT_TEXT;          }       };    } 

In this case, there are two menu items: one to play a new game and one to exit the application. As a minimum, each MENU_ITEM has the following fields: a text field for the menu item caption ( txt ) and the ID of a command that will be invoked when the menu item is selected ( command ). A command ID is an enumerated value which is unique within the application. Command IDs are defined in a separate header file with an .hrh extension. System .hrh filesfor example, uikon.hrh and avkon.hrh provide common command IDs. .hrh files can be included in both resource files and C++ source files, providing a link between the menu definitions in resources and the command-handler functions in the C++ code.

Typically, command names are of the format E <AppName> Cmd <CommandName> for example, EAknCmdHelp is the Help command for Series 60 applications. If you want to use your own application-specific commands, you need to define an enumeration in your own .hrh file. In the SimpleMenu example, an application-specific command, ESimpleMenuCmdNewGame , is defined in SimpleMenu.hrh :

 enum    {    ESimpleMenuCmdNewGame = 0x6000,    ...    } 

In addition, the cascade item can optionally be used to specify a submenu that will be displayed when this item is selected. This should just give the name of another MENU_PANE resource, which is defined in exactly the same way as this one (with the one exception that it cannot itself reference any submenus).

You should start the enumeration from 0x6000 to prevent clashes with system commands.


The MENU_TITLE and MENU_PANE resource STRUCT s have a number of fields which Series 60 ignores, such as bmpfile , bmpid and bmpmask . These are ignored because Series 60 menus cannot contain bitmaps. The MENU_TITLE , MENU_PANE and MENU_ITEM STRUCT s also specify an extension field, which you should not change. The MENU_ITEM has an exTRatext field, which Series 60 also ignores.

Using a Menu in a Control

You need to add the menu bar to the screen on which you want it to be available. In the SimpleMenu example, there is only one screen, so the options menu is going to belong to the AppUI. You refer to the menu in the menubar field of the appropriate resource and ensure that you have appropriate soft keys to access the menu. In the SimpleMenu example, the menubar and cba in EIK_APP_INFO are set to achieve this:

 RESOURCE EIK_APP_INFO    {    menubar = r_simplemenu_menu_bar;    cba = R_AVKON_SOFTKEYS_OPTIONS_BACK;    } 

UI components , which can have a menu, have a menubar field in their resource STRUCT for example, the view ( R_AVKON_VIEW ) and dialog ( R_AVKON_DIALOG ) components. Specifying a menubar for these components allows you to make menus specific to individual screens in an application.


Handling Menu Commands

In order for the menu to be useful, you need to handle its commands. Where you handle commands depends on the type of object containing the menu. In a CAknAppUi - or CAknView -derived class, you use the HandleCommandL() method. In CAknDialog -derived classes, you use the ProcessCommandL() method.

Objects that handle commands inherit from the MEikCommandObserver mixin. This defines a pure virtual method ProcessCommandL() . When you select a menu item, the framework calls ProcessCommandL() . CAknAppUi and CAknView provide a default implementation of ProcessCommandL() , which calls HandleCommandL() .


As the SimpleMenu example uses the menu in the AppUi, the HandleCommandL() method is overridden in the SimpleMenuAppUi class:

 void CSimpleMenuAppUi::HandleCommandL(TInt aCommand)    {    switch (aCommand)       {       case ESimpleMenuCmdViaIR:          iAppContainer->PlayNewGameVia(aCommand);          break;       case ESimpleMenuCmdViaBluetooth:          iAppContainer->PlayNewGameVia(aCommand);          break;       case ESimpleMenuCmdViaSMS:          iAppContainer->PlayNewGameVia(aCommand);          break;       case EAknSoftkeyBack:       case EEikCmdExit:          Exit();          break;       default:          break;       }    } 

This code shows a standard way of handling commandsa switch statement handles each command ID on a case-by-case basis. In the SimpleMenu example application, handling must be provided for the commands in the submenu and the exit command. The new game command does not involve extra handling codethe framework takes care of this, popping up the submenu when you select the New Game item.

You should handle the exit command by calling the Exit() method, which closes the application. You should handle the Back soft key in the same way. You may have noticed that the Exit command handled above ( EEikCmdExit ) is not the command associated with the Exit menu item ( EAknCmdExit ). There are two predefined commands for exiting an application: EAknCmdExit (in avkon.hrh ), and EEikCmdExit (in uikon.hrh ).

When defining exit menu items in the application resource file, you should use the EAknCmdExit version. For example:

 MENU_ITEM    {    command = EAknCmdExit;    txt = EXIT_TEXT;    } 

However, when handling the command in ProcessCommandL() , or HandleCommandL() , you should always handle EEikCmdExit . For example:

 void CSimpleMenuAppUi::HandleCommandL(TInt aCommand)    {    switch (aCommand)       {       case EAknSoftkeyBack:       case EEikCmdExit:          {          Exit();          break;          }    ... 

This is because, when EAknCmdExit activates, the application framework needs to close the current application and any related applications. The term " related applications" refers to situations where another application either embeds the current application or contains embedded applications. All closeable applications are required to handle the EEikCmdExit command by calling CEikAppUi::Exit() , which closes the application. To ensure that all related applications are closed, the framework sends an EEikCmdExit to each of the related applications, and expects them to handle the command by calling the Exit() method.

Note that the EEikCmdExit command is reserved for system use (such as Out-Of-Memory watchdogs ), and so must call Exit() without querying the user. This is covered in more detail in the Good Application Behavior section of Chapter 4.

The Back soft key will always activate the EAknSoftkeyBack command. The behavior invoked by the Back soft key depends on the screen currently being displayed. Screens that are not at the top level should handle the back command by returning to the previous screen.

The top-level screen should handle the back command by exiting the application in the same way as the exit command does. You can see this in the HandleCommandL() code above, which handles both the EAknSoftKeyBack and EEikCmdExit commands in the same way.

When you configure the soft keys such that the right key is Exit rather than Back ( R_AVKON_SOFTKEYS_EXIT ), the command that should be specified and handled is EAknSoftkeyExit .


Dynamic Menus

Menus are dynamicthe number of items displayed in them can vary throughout their lifetime. If the number of menu items in a menu is too great to fit on one screen, the framework automatically provides scroll adjusters so that you can scroll through them.

You can control the number of menu items in a menu by hiding and revealing them programmatically. This is useful in order to prevent users from accessing commands at inappropriate times (you would want to hide a "Check Spelling" menu option in a word processor application, for example, if the user had not yet opened a document).

It is not always desirable to hide menu items. This can be confusing to users, as they may be left wondering where a menu item has gone, or may find it difficult to recall where to locate particular menu items. If you feel that this may be an issue, consider leaving all menu items visible and displaying an informational message when the menu item is selected instead. See the Notes section in Chapter 6 for details of displaying informational messages.


All components that can have menus inherit from the MEikMenuObserver mixin class. This class defines the virtual method DynInitMenuPaneL() , which you can override in order to dynamically change the menu items. For example:

 void CMyAppUi::DynInitMenuPaneL(    TInt aResourceId, CEikMenuPane* aMenuPane)    {    if (aResourceId == R_MY_NEW_GAME_SUBMENU_MENU_PANE)       {       aMenuPane->SetItemDimmed(          EMyCmdViaBluetooth, DimBluetooth());       }    } 

The DynInitMenuPaneL() method has two parameters, which identify the currently active menu pane. You should check that the aResourceId argument specifies the menu pane you wish to alter. If it does, then use the aMenuPane argument to alter it. You can set the visibility of items using the menu pane's SetDimmed() method, passing it the required menu item's command ID, along with Etrue to make it invisible, or EFalse to make it visible again.

The SDK documentation for CEikMenuPane::SetItemDimmed() suggests that this method will dim (gray out) the menu item rather than hide it. As you have seen in this step, this is not the case in Series 60, but it is in other Symbian OS platforms, such as Series 80.


Context-Sensitive Menus

Context-sensitive menus are secondary menus that are typically launched by pressing the Selection key (as opposed to the primary Options menu accessed via the left soft key). These menus are sensitive to the currently displayed view, and furthermore can be sensitive to the internal state of that view. For example, a view that constitutes a list box may invoke different menus, depending on the currently selected list item.

This subsection looks at the example application ContextMenu , which shows you how to define a context-sensitive menu in a resource, and how to display a context-sensitive menu. The example displays a list of saved games , as shown in Figure 5-10.

Figure 5-10. ContextMenu screen.


The Options menu has only one item, which allows you to exit the application. However, when you press the Selection key, a context-sensitive menu is displayed for the focused item, allowing you to play or delete the saved game, as shown in Figure 5-11.

Figure 5-11. ContextMenu context-sensitive menu.


Actual game-playing code has been omitted; however, an empty method called PlaySelectedGame() is provided to indicate where such code would reside. Lists are explained in detail in Chapter 7.

OK Options Menus is another name used for context-sensitive menus invoked by the Selection key, so called because the Selection key is labeled OK on the Series 60 emulator.


Defining a Context-Sensitive Menu Using Resources

You define a context-sensitive menu in the same way you define any other application menuthat is, by defining a MENU_BAR and associated resources. This has already been covered in "Menu Basics." In the ContextMenu example, a menu is defined with two items: one to Play , and one to Delete a selected game.

Displaying a Context-Sensitive Menu

A context-sensitive menu displays when you press a particular key, typically the Selection key. Therefore, you should override the OfferKeyEventL() method to handle the key press and display the menu at that point. In the ContextMenu example, the container class overrides this method:

[View full width]
 
[View full width]
TKeyResponse CContextMenuContainer::OfferKeyEventL( const TKeyEvent& aKeyEvent, TEventCode aType) { TBool selectKeyPressed = (aType == EEventKey) && (aKeyEvent.iCode == EKeyOK); TBool savedGameListNotEmpty = (iSavedGamesListBox) && (iSavedGamesListBox->Model ()->NumberOfItems() > 0); if (selectKeyPressed && savedGameListNotEmpty) { CEikMenuBar* parentMenuBar = iEikonEnv->AppUiFactory()->MenuBar(); parentMenuBar->SetMenuTitleResourceId(R_CONTEXTMENU_SAVED_GAMES_MENU_BAR); if (parentMenuBar) { parentMenuBar->TryDisplayMenuBarL(); } parentMenuBar->SetMenuTitleResourceId(R_CONTEXTMENU_MENU_BAR); return EKeyWasConsumed; } else return iSavedGamesListBox->OfferKeyEventL(aKeyEvent, aType); }

The Selection key could also have been handled by registering the container as an observer of the list, and handling its events. This is covered in more detail in the Chapter 7.


In order to display the context-sensitive menu, you need to:

  • Check that the key that should activate the menu has been pressed. You need to check the TKeyEvent and TEventCode arguments supplied. The ContextMenu example checks that they are EEventKey and EKeyOk , respectively. Event codes are defined in the TKeyCode enum in E32Keys.h . The event code EKeyOK is defined in uikon.hrh and is simply a #define of EKeyDevice3 .

  • Get a handle on the menu bar. If the key is appropriate, then you can get a handle to the menu bar of the container's parent. In this case, the menu bar for the application is accessed by using the AppUiFactory() method of iEikonEnv to get a handle on the AppUi, and then calling the MenuBar() method to get the menu bar. Other parents of containers have similar methods for accessing the menu bar; for example, CAknView has a MenuBar() method. Please refer to the SDK documentation for further details.

  • Change the menu bar's resource to use the context-sensitive menu. Once you have a handle on the menu bar, you can change its resource using the SetMenuTitleResourceId() method. You pass in the MENU_BAR resource you defined for the context-sensitive menu in a previous step.

  • Display the context-sensitive menu by calling CEikMenuBar::TryDisplayMenuBarL() .

  • Set the menu bar back to its original form. When you changed the menu bar's resource using SetMenuTitleResourceId() , the change was permanent. This means that the left soft key will always display that menu until you reset it. The last thing you must do, therefore, is to set it back to the original menu bar by calling the method again, this time passing in the original menu bar value.

The ContextMenu example code also verifies that the list of games is not empty to ensure that the context-sensitive menu displays only if an item on the list is focused. This code is necessary only for context-sensitive menus displayed for lists. See Chapter 7 for further details of list methods and usage.




Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net