Event Handling

As the user interacts with the user interface, events will be sent to the application that owns the window in which the event occurred. There are several different types of events, but the main ones you will be interested in are key events and redraw events. Key events occur when the user presses, holds or releases a key. Redraw events occur when a control (or part of a control) is revealed on screen and needs to redraw itself.

Key Events

A key event is a system event that is generated whenever a key on the device keypad is pressed, held down or released. Key events are routed to applications by the Window Server by means of the control stack , a structure which maintains information on the order in which key events should be passed to applications. A control is informed of a key event by a call to its OfferKeyEventL() method ”this is a virtual function defined in CCoeControl which a control should override to provide its own key-handling behavior. This process is described in more detail below.

Focus

As far as the Window Server is concerned , only applications, and not windows , have keyboard focus. This means that only the application that currently has focus will receive key events. The application itself is then responsible for distributing these key events to the appropriate control. In order to help with this, the control framework provides the control stack, which supports the distribution of key presses to different controls within an application.

An application can gain or lose focus at any time. This can happen, for example, if the user switches between applications, or if the system brings another application into the foreground. Whenever an application gains or loses focus, the AppUI's HandleForegroundEventL() method will be called, with a TBool parameter indicating whether focus was lost or gained. You do not normally have to redraw controls when your application loses focus, because applications that do not have focus are not visible on the screen. However, it may be useful to perform other activities, such as pausing a game when focus is lost and starting it again when focus is gained . The following code shows how you would achieve this:

 void CExampleAppUi::HandleForegroundEventL(TBool aForeground)    {    if (aForeground)       {       // focus gained, perform appropriate actions here       }    else       {       // focus lost, perform appropriate actions here       }    CAknAppUi::HandleForegroundEventL(aForeground);    } 

Compound controls should handle focus changes within their component controls. It is up to the compound control to call the component control's FocusChanged() method when it changes the component control's focus. It is up to you to implement this in your own compound controls. You give focus to a control by calling its SetFocus() method.

A control's current focus state can be obtained by calling the IsFocused() method. If you change focus from one control to another, you should remember to call SetFocus(EFalse) on the control that is losing focus as well as calling SetFocus(ETrue) on the control that is gaining focus.


Controls may indicate visually whether they are focused ”for example, by adding a border. The system-provided controls will highlight themselves in an appropriate way when their focus changes ”all you need to do is call the SetFocus() method on them. If you write your own controls, it is up to you to make sure that the control redraws itself when focused if necessary.

The Control Stack

The control framework provides a control stack used for routing key events. Each control has a priority that determines its position on the stack. A control's position on the stack determines the order in which it will be offered key events.

The control with the highest priority is placed at the top of the stack, with controls arranged in decreasing order of priority. The relative placement of controls with equal priorities is determined by the order in which they were added, with the most recently added control highest on the stack. Events are offered to controls from the top of the stack downward until they are consumed (that is, handled by a control).

In order for a control to receive key events, it must explicitly be added to the control stack ”by default, controls are not on the stack. A control is added to the stack using the function CAknAppUi::AddToStackL() . In the case of compound controls, only the compound control should be added to the stack ”its component controls should not. Instead, the compound control should be responsible for passing events on to its component controls as required.

Offering Key Events

Key events are passed to a control by a call to its OfferKeyEventL() method. Again, this is a virtual method in CCoeControl which you need to override in your own control to provide appropriate behavior.

A control can decide whether or not it wants to process a key event. If it does process the event, it should return the value EKeyWasConsumed ; otherwise it should return EKeyWasNotConsumed . The event will be passed to each control on the stack in turn until one of the controls returns EKeyWasConsumed or there are no more controls left.

The OfferKeyEventL() method has two arguments: a key event ( const TKeyEvent& aKeyEvent ) and a key type ( TEventCode aType ). The key event is a structure that indicates, among other things, which key has been pressed. The key type is an enumeration that indicates the nature of the key event. There are three different types of key events: EEventKeyDown , EEventKey and EEventKeyUp . An EEventKeyDown event is received when the key is first pressed down, followed by one or more EEventKey events as it is held down, then an EEventKeyUp event when it is released.

The following piece of code shows how a control would handle key up events from the Up and Down arrow keys and discard everything else:

 TKeyResponse CMyControl::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)    {    if (aType == EEventKeyUp)       {       switch (aKeyEvent.iCode) // check the key code          {          case EKeyUpArrow: // Up arrow key             // handle up arrow key press here             return EKeyWasConsumed;          case EKeyDownArrow: // Down arrow key             // handle down arrow key press here             return EKeyWasConsumed;          default:             return EKeyWasNotConsumed;          }       }    return EKeyWasNotConsumed;    } 

A list of all the key code enumerations can be found in the system header file e32keys.h . Uikon.hrh redefines some of these to have Series 60-specific names ”for example, EKeyDevice3 is redefined as EKeyOk .


As mentioned above, a compound control is responsible for offering key events to its component controls. An example of how this would be implemented is shown below:

 TKeyResponse CMyCompoundControl::OfferKeyEventL(    const TKeyEvent& aKeyEvent, TEventCode aType)    {    TKeyResponse response(EKeyWasNotConsumed);    if (iComponentControl1 && iComponentControl1->IsFocused())       {       response = iComponentControl1->OfferKeyEventL(aKeyEvent, aType);       }    else if (iComponentControl2 && iComponentControl2->IsFocused())       {       response = iComponentControl2->OfferKeyEventL(aKeyEvent, aType);       }    return response;    } 

Notice that if there is more than one component control that can handle the event, then the event should be sent to the control that currently has focus.

Redraw Events

Redraw events tell a control that it needs to update itself on the screen. They are generated when a control is first displayed, whenever part or all of it is revealed after being covered by another window, or whenever the application's data changes and the view needs to be refreshed appropriately. A redraw event can occur in one of two different ways:

  • System-Initiated Redraws ” The window server sends the redraw event because a region of the screen has become invalid. This can happen, for example, when a window that was obscuring the control has disappeared.

  • Application-Initiated Redraws ” The application itself sends the redraw event because, for example, some application data has changed and the control needs to be updated to reflect this.

System-initiated redraws result in a call to the Draw() method of every control that intersects the invalid region. In this case, all you have to worry about is implementing the Draw() method of your controls so that they correctly redraw themselves.

Generating an application-initiated redraw is performed by calling either DrawDeferred() or DrawNow() on the appropriate control. The reason for having two draw functions is that drawing involves sending an instruction to the Window Server, and transactions with the Window Server may be buffered to avoid the inefficiency of too many Client/Server calls. DrawDeferred() adds a draw request to the current Window Server buffer, to be sent to the Window Server once the buffer is full. In practice this is often instantaneous, since the nature of Series 60 as a highly graphical environment means that the buffer tends to fill quickly. You should certainly use DrawDeferred() for any non-time -critical updates. DrawNow() does the same as DrawDeferred() , but then forces a flush of the command buffer. You should generally use this only if it is critical that your update happens immediately (for example, in a precise clock control). Overuse of DrawNow() is inefficient and should be avoided.

It is important to note that if you want to redraw a control explicitly, you must call DrawDeferred() , or DrawNow() on it ”you must not call its Draw() method directly. DrawDeferred() and DrawNow() ensure that the Window Server is informed of the control's need to redraw itself, so that the drawing you perform in Draw() will appear on screen. They will also cause a compound control's component controls to be redrawn correctly. Calling Draw() directly does neither of these, and often it will not produce the result you are expecting.

Unlike key events, compound controls do not need to distribute redraw events to their component controls. As you saw earlier in this chapter, the control environment does this using the CountComponentControls() and ComponentControl() methods of the compound control.


Observers

A final point about event handling is that it is possible for a control to send events to another object. This can be useful when dealing with compound controls ”for example, if you need a component control to report events to the compound control which contains it.

Events are passed out of controls by means of a control observer interface. A control observer does not need to be a control itself ”any class can be set up as a control observer by deriving from MCoeControlObserver and setting it as the observer for the control (or controls) it needs to observe. A control's observer is set by calling the control's SetObserver() method, passing a pointer to the observer. An observer can be set to observe multiple controls, but each control can have at most one observer.

A control sends an event to its observer using its ReportEventL() method. This will result in a call to the observer's HandleControlEventL() method (inherited from MCoeControlObserver ). The observer can then process the event in any way it desires. For example:

 void CMyObserver::HandleControlEventL(CCoeControl* aControl, TCoeEvent aEventType)    {    if (aControl == iMyControl1 &&    aEventType == EEventStateChanged)       {       // handle event here       }    } 

Notice that HandleControlEventL() receives two arguments. The first is a pointer to the control from which the event originated. This is useful if an observer is observing multiple controls. (If you are observing only a single control, then you can ignore this parameter.) The second parameter is the event type.

Dangling Pointers

When using control observers, you should be careful to avoid dangling pointers. If the observer owns a pointer to the control, you need to avoid a situation where the control is deleted but the observer still has a dangling pointer to it. This can be avoided by having the control send an appropriate event to the observer just before it is deleted.

Likewise, in an observer's destructor you should ensure that it deregisters itself with any controls it observes, so that they do not try to send it events after it has been deleted. This is performed by calling SetObserver(NULL) on each control.



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