|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <concept id="GUID-2161BD64-889B-5EAB-B023-1162FE9619DB" xml:lang="en"><title>How |
|
13 to use multiple active objects</title><shortdesc>This document illustrates how to use one active object to control |
|
14 another.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
15 <p>The following example code fragments show how to construct a program with |
|
16 two active objects, where one controls the initiation and cancellation of |
|
17 the other.</p> |
|
18 <p>In these examples:</p> |
|
19 <p><codeph>CActiveConsole</codeph> is an active object and contains a pointer |
|
20 to a <codeph>CConsoleBase</codeph> object which is a service provider. Through |
|
21 this service provider, the active object provides the facility to request |
|
22 a character from the keyboard.</p> |
|
23 <p><codeph>RunL()</codeph> delegates the handling of completed requests to |
|
24 the pure virtual function <codeph>ProcessKeyPress()</codeph>, which must be |
|
25 provided by a derived class.</p> |
|
26 <p><codeph>CMessageKeyProcessor</codeph> is further derived from <codeph>CActiveConsole</codeph> and |
|
27 contains a pointer to another active object <codeph>CExampleActiveObject</codeph>, |
|
28 which requires input from the keyboard.</p> |
|
29 <p>Depending on the input character, the <codeph>CMessageKeyProcessor</codeph> active |
|
30 object does one of the following:</p> |
|
31 <ul> |
|
32 <li id="GUID-9151F698-3D4F-5C3D-A758-194018FC053C"><p>issues a request to |
|
33 the <codeph>CExampleActiveObject</codeph> active object</p> </li> |
|
34 <li id="GUID-FBF8743F-0147-502B-BBE8-824DB727F791"><p>cancels any outstanding |
|
35 request to the <codeph>CExampleActiveObject</codeph> active object</p> </li> |
|
36 <li id="GUID-2E714DE6-AAE1-5926-8026-9B6E1C09C5C7"><p>does nothing</p> </li> |
|
37 </ul> |
|
38 <p>The implementation of the <codeph>CExampleActiveObject</codeph> active |
|
39 object is not relevant to the example and is not shown.</p> |
|
40 <p>The following diagram shows the relationship between the classes.</p> |
|
41 <fig id="GUID-AF998428-D142-56F8-8967-AF66AF9119F8"> |
|
42 <image href="GUID-BEDF6765-4BF4-532F-A2C7-F052FE8A9CA2_d0e208130_href.png" placement="inline"/> |
|
43 </fig> |
|
44 <section id="GUID-5E2A6378-546D-46C5-8081-6425A96FAAFF"><title>Encapsulating the service provider</title> <p>The class <codeph>CActiveConsole</codeph> encapsulates |
|
45 the provision of basic keyboard services. Its <codeph>iConsole</codeph> data |
|
46 member is a pointer to the service provider, the <codeph>CConsoleBase</codeph> object.</p> <p>The |
|
47 active object class is defined as:</p> <codeblock id="GUID-DC98E432-1927-55F5-94A3-68D2493B75E8" xml:space="preserve">class CActiveConsole : public CActive |
|
48 { |
|
49 public: |
|
50 CActiveConsole(CConsoleBase* aConsole); |
|
51 void ConstructL(); |
|
52 ~CActiveConsole(); |
|
53 void RequestCharacter(); |
|
54 void RunL(); |
|
55 void DoCancel(); |
|
56 virtual void ProcessKeyPress(TChar aChar)=0; |
|
57 protected: |
|
58 CConsoleBase* iConsole; |
|
59 };</codeblock> <p>The class constructor takes a pointer to a <codeph>CConsoleBase</codeph> object |
|
60 as its single argument and initializes its <codeph>iConsole</codeph> data |
|
61 member to this value:</p> <codeblock id="GUID-2C5C49DB-AE88-5F84-82D7-BA5680A286C8" xml:space="preserve">CActiveConsole::CActiveConsole(CConsoleBase* aConsole) |
|
62 : iConsole(aConsole) |
|
63 {}</codeblock> <p>The <codeph>ConstructL()</codeph> function adds the |
|
64 active object to the active scheduler:</p> <codeblock id="GUID-CE947B19-9664-5774-ABFB-17E79A112131" xml:space="preserve">void CActiveConsole::ConstructL() |
|
65 { |
|
66 CActiveScheduler::Add(this); |
|
67 }</codeblock> <p>The destructor cancels any outstanding request before |
|
68 destroying the active object:</p> <codeblock id="GUID-0120EE92-2BD8-5B2E-841A-DC366B3BED12" xml:space="preserve">CActiveConsole::~CActiveConsole() |
|
69 { |
|
70 Cancel(); |
|
71 }</codeblock> <p><codeph>DoCancel()</codeph> is implemented to cancel |
|
72 the request to <codeph>iConsole</codeph>.</p> <p>The <codeph>RequestCharacter()</codeph> function |
|
73 makes a request for a key press to the service provider by calling <codeph>iConsole->Read(iStatus)</codeph> and |
|
74 setting the active request flag:</p> <codeblock id="GUID-EF731B8D-7001-503F-8167-7A10697D5202" xml:space="preserve">void CActiveConsole::RequestCharacter() |
|
75 { |
|
76 iConsole->Read(iStatus); |
|
77 SetActive(); |
|
78 }</codeblock> <p>The <codeph>RunL()</codeph> function makes a call to |
|
79 the <codeph>ProcessKeyPress()</codeph> function. This is a pure virtual function |
|
80 that derived classes must implement to handle the key press and to reissue |
|
81 the request:</p> <codeblock id="GUID-DF9F07BB-2099-5310-8921-3A290580B4AF" xml:space="preserve">void CActiveConsole::RunL() |
|
82 { |
|
83 ProcessKeyPress(TChar(iConsole->KeyCode())); |
|
84 }</codeblock> </section> |
|
85 <section id="GUID-FFD3321F-3A46-4C40-A779-39C142DC79C3"><title>Further deriving from the active object</title> <p>The class <codeph>CMessageKeyProcessor</codeph> is |
|
86 a concrete class, derived from <codeph>CActiveConsole</codeph>. It provides |
|
87 an implementation for the<codeph>ProcessKeyPress()</codeph> function and can |
|
88 issue or cancel requests to a<codeph>CExampleActiveObject</codeph> active |
|
89 object.</p> <p>This active object class is defined as:</p> <codeblock id="GUID-C5F51E0D-517C-523D-BADA-4B3CDCA53073" xml:space="preserve">class CMessageKeyProcessor : public CActiveConsole |
|
90 { |
|
91 public: |
|
92 ... |
|
93 CMessageKeyProcessor(CConsoleBase* aConsole, CExampleActiveObject* iExampleObject); |
|
94 void ProcessKeyPress(TChar aChar); |
|
95 private: |
|
96 CExampleActiveObject* iExampleObject; |
|
97 };</codeblock> <p><b>Notes</b> </p> <ul> |
|
98 <li id="GUID-2341BA65-3806-5354-9F9D-EB1A8FD3FD61"><p>The first constructor |
|
99 parameter specifies a <codeph>CConsoleBase</codeph> which will be used to |
|
100 provide asynchronous keyboard input.</p> </li> |
|
101 <li id="GUID-E9CAAF35-C404-5418-9720-F560C4CED53D"><p>the second constructor |
|
102 parameter specifies a <codeph>CExampleActiveObject</codeph> which will be |
|
103 controlled by this <codeph>CMessageKeyProcessor</codeph>.</p> </li> |
|
104 </ul> <p>The behaviour of the <codeph>ProcessKeyPress()</codeph> function |
|
105 depends on the key code value:</p> <codeblock id="GUID-8081A453-4D44-5F2B-BAF3-7A43A1417BEF" xml:space="preserve">void CMessageKeyProcessor::ProcessKeyPress(TChar aChar) |
|
106 { |
|
107 if (aChar == 'm' || aChar == 'M') |
|
108 { |
|
109 iExampleObject->Cancel(); |
|
110 iExampleObject->IssueRequest(); |
|
111 } |
|
112 if (aChar == 'c' || aChar == 'C') |
|
113 { |
|
114 iExampleObject->Cancel(); |
|
115 } |
|
116 if (aChar != EKeyEscape) |
|
117 { |
|
118 RequestCharacter(); |
|
119 } |
|
120 else |
|
121 { |
|
122 iExampleObject->Cancel(); |
|
123 CActiveScheduler::Stop(); |
|
124 } |
|
125 }</codeblock> </section> |
|
126 <section id="GUID-91B9EF85-A595-479D-8D57-40CC427C19E7"><title>Enhanced framework</title> <p>In the code fragment below, |
|
127 an active scheduler is created to which both a <codeph>CMessageKeyProcessor</codeph> active |
|
128 object and a<codeph>CExampleActiveObject</codeph> active object are added:</p> <codeblock id="GUID-830AA24C-7781-505A-9DD1-4A042040688D" xml:space="preserve">LOCAL_C void doExampleL() |
|
129 { |
|
130 CActiveScheduler* exampleScheduler=new (ELeave) CActiveScheduler; |
|
131 CleanupStack::PushL(exampleScheduler); |
|
132 CActiveScheduler::Install(exampleScheduler); |
|
133 |
|
134 CExampleActiveObject* iExampleObject = |
|
135 CExampleActiveObject::NewLC(); |
|
136 CMessageKeyProcessor* keyProcessor= |
|
137 CMessageKeyProcessor::NewLC(console, iExampleObject); |
|
138 |
|
139 keyProcessor->RequestCharacter(); |
|
140 CActiveScheduler::Start(); |
|
141 CleanupStack::PopAndDestroy(3); |
|
142 }</codeblock> <p><b>Notes</b> </p> <ul> |
|
143 <li id="GUID-1FB2DB58-C282-5B21-A070-DEC020E98059"><p>An instance of the active |
|
144 scheduler, <codeph>exampleScheduler</codeph> is pushed onto the cleanup stack |
|
145 and installed as the current active scheduler.</p> </li> |
|
146 <li id="GUID-3404475D-4044-5DB4-BEDF-5A308B2521CA"><p>An instance of the <codeph>CExampleActiveObject</codeph> active |
|
147 object is created.</p> </li> |
|
148 <li id="GUID-F7C3C84D-66E5-5F8D-8213-8DC3864D659D"><p>An instance of the <codeph>CMessageKeyProcessor</codeph> active |
|
149 object is created and this is in control.</p> </li> |
|
150 <li id="GUID-DA61DFD2-B057-50C9-8FD1-C53E884A4A0E"><p><codeph>keyProcessor->RequestCharacter()</codeph> issues |
|
151 a request for keyboard input.</p> </li> |
|
152 <li id="GUID-5BFAEEED-051C-5741-BAA0-96AFC3EA5A02"><p><codeph>CActiveScheduler::Start()</codeph> starts |
|
153 the active scheduler. At least one outstanding request is necessary before |
|
154 the wait loop is started, otherwise the thread hangs. All further request |
|
155 issuing and servicing occurs within this function. The wait loop continues |
|
156 until one of the active objects’ <codeph>RunL()</codeph> calls<codeph>CActiveScheduler::Stop()</codeph>.</p> </li> |
|
157 <li id="GUID-E3FB7738-DC6C-5472-8CBF-FAAD47C440D5"><p>The active objects and |
|
158 the active scheduler are popped from the cleanup stack and destroyed.</p> </li> |
|
159 </ul> </section> |
|
160 </conbody></concept> |