|
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-0C814ED6-3F64-4E0E-9C47-654AEDADBA90" xml:lang="en"><title>Going |
|
13 Beyond Hello: A Tutorial for Symbian C++ Applications</title><shortdesc>This tutorial shows how you can extend that basic example to create |
|
14 a small paint application, along the way learning more about the application |
|
15 frameworks (e.g. defining menus, how to handle touch-screen events, drawing |
|
16 to the screen etc.).</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
17 <p>In the <xref href="GUID-301E5FAA-A1C3-4FD7-9D84-DAA61C66981B.dita">Symbian C++ |
|
18 Quick Start</xref> you learned how to create a basic example application using |
|
19 Carbide.c++, and how to build and run it on the Windows emulator and on a |
|
20 device. </p> |
|
21 <p><b>Comes with Code</b>: <xref href="http://developer.symbian.org/wiki/images/e/eb/HelloSymbianWorld_Example_Code.zip.dita">File: |
|
22 HelloSymbianWorld Example Code.zip</xref></p> |
|
23 <section id="GUID-14C6D367-D806-45F8-BC44-C5DBC78096D9"> <title> Application |
|
24 Structure</title> <p>Carbide.c++ offers two ways of exploring your project. |
|
25 The traditional <b>Project Explorer</b> window, which can also be found in |
|
26 Eclipse, lists the files belonging to the project in the same directory structure |
|
27 as in the file system. </p><p>The <b>Symbian Project Navigator</b> contains |
|
28 the same contents, but displays them in a logical hierarchy according to <xref href="http://developer.symbian.org/wiki/index.php/Coding_Standards_and_Conventions.dita">Symbian |
|
29 Conventions</xref>. </p><p> You might wonder why a basic "Hello World" application |
|
30 contains so many files. The answer is straightforward - a much simpler Hello |
|
31 World wouldn’t be a very good starting point for real-world applications. |
|
32 </p><p>Instead the wizard generates the project for a complete and readily |
|
33 extensible application. The project separates code and data, and uses a form |
|
34 of the <xref href="http://wiki.forum.nokia.com/index.php/Design_Patterns_in_Symbian.dita#http://wiki.forum.nokia.com/index.php/Design_Patterns_in_Symbian/Model-View-Control_Pattern">model |
|
35 view controller pattern</xref> for structuring your code. The application |
|
36 already reacts to system events and contains everything that is required for |
|
37 localization. </p><p/><p><b>What are the directories of a project?</b><fig id="GUID-898488F8-5CF9-4A01-95F8-45E2C5D2E501"> |
|
38 <image href="GUID-FFC6F01E-15AB-43E6-90E8-0E42DA297AE9_d0e3849_href.png" placement="inline"/> |
|
39 </fig></p><p/><b>\group</b><ul> |
|
40 <li><p><b>bld.inf</b>: Component-definition file. This specifies the <codeph>mmp</codeph> files |
|
41 that belong to your component, any shared header files that it exports, and |
|
42 the default build targets (e.g. GCCE, WINSCW).</p><ul> |
|
43 <li><p><codeph>Bld.inf</codeph> is used to generate the makefiles and <codeph>abld.bat</codeph> used |
|
44 to build for the command-line (see <xref href="GUID-301E5FAA-A1C3-4FD7-9D84-DAA61C66981B.dita">Symbian |
|
45 C++ Quick Start</xref>). </p></li> |
|
46 <li><p>This file is the starting point when you want to import a Symbian C++ |
|
47 project into Carbide.c++, because it contains references to all executables |
|
48 in your project (see the section on Importing Other Examples). </p></li> |
|
49 </ul></li> |
|
50 <li><p><b>HelloWorld.mmp</b>: Project-definition file. This specifies how |
|
51 to build an executable (in this case <codeph>HelloWorld.exe</codeph>) in a |
|
52 platform- and compiler-independent way. It contains information such as resource |
|
53 files to be compiled, source files to include when compiling, and the libraries |
|
54 to include when linking. </p></li> |
|
55 <li><p><b>Icons_aif_scalable_dc.mk</b>: Makefile used to create the application's |
|
56 icon from the <codeph>*.svg</codeph> file in the <codeph>/gfx</codeph> folder. </p></li> |
|
57 </ul><p> </p><p><b>\src</b></p><ul> |
|
58 <li><p> <b>HelloWorldApplication.cpp</b>: This file contains the entry point |
|
59 for the EXE file (<codeph>E32Main()</codeph>) as well as the implementation |
|
60 of the Application class (which provides some basic functionality for the |
|
61 GUI framework). Normally this is "boilerplate" code and you do not need to |
|
62 make any changes. </p></li> |
|
63 <li><p><b>HelloWorldDocument.cpp</b>: This class is supposed to take care |
|
64 of the persistent data model of your application and therefore provides some |
|
65 functions to load and save <codeph>.ini</codeph> files. This mechanism is |
|
66 disabled by default - for most applications you may treat this as "boilerplate" |
|
67 code. </p></li> |
|
68 <li><p><b>HelloWorldAppUi.cpp</b>: This is the main controller of your application. |
|
69 It contains the logic for handling application-wide events (so you don’t have |
|
70 to handle, for example, the exit event in every view). It owns all the views |
|
71 that you use. </p></li> |
|
72 <li><p><b>HelloWorldContainerView.cpp</b>: This is a kind of controller, which |
|
73 is responsible for handling events and the UI elements of the currently visible |
|
74 view. It’s not visible itself, but owns and manages the <i>Container</i> (below), |
|
75 which corresponds to the view in the traditional model view controller pattern.</p></li> |
|
76 <li><p><b>HelloWorldContainer.cpp</b>: Contains the UI elements that should |
|
77 be displayed by the view. Therefore, the ContainerView and the Container usually |
|
78 have a very strong relationship. </p></li> |
|
79 </ul><p>During start-up, one class instance creates the next:</p><fig id="GUID-2A3EE3C2-3515-4217-BCB3-182A01936898"> |
|
80 <image href="GUID-AC3F5010-ECA6-4257-98B5-77FB26B4987F_d0e3955_href.png" placement="inline"/> |
|
81 </fig><p/><p><b>\inc</b></p><ul> |
|
82 <li><p><b>HelloWorldApplication.h</b>, <b>HelloWorldDocument.h</b>, <b>HelloWorldAppUi.h</b>, <b>HelloWorldContainerView.h</b>, <b>HelloWorldContainer.h</b>: Header files corresponding to each of the main source files above. </p></li> |
|
83 <li><p><b>HelloWorld.hrh</b>: UIDs/identifiers for UI elements including views. |
|
84 These are shared between the resource file definitions for UI elements and |
|
85 the source code command handlers.</p></li> |
|
86 <li><p><b>HelloWorld.pan</b>: Panic code and method definitions.</p></li> |
|
87 </ul><p/><p><b>\data</b></p><ul> |
|
88 <li><p><b>HelloWorld_reg.rss</b>: Contains registration information about |
|
89 the application, such as its title.</p></li> |
|
90 <li><p><b>HelloWorld.rss</b>: Main resource file. Contains additional information |
|
91 about the application, as well as user interface and text resource definitions. |
|
92 </p></li> |
|
93 <li><p><b>HelloWorld.loc</b>, <b>HelloWorld.l01</b>: Localization files. Strings |
|
94 used by UI are defined in separate localization resource files. Each file |
|
95 has the format <codeph>.lxx</codeph>, where <i>xx</i> is a language specific |
|
96 numeric file extension - e.g. UK English is ‘01’, French ‘02’ and German ‘03’. |
|
97 The <codeph>.loc</codeph> file is a kind of junction that <codeph>#includes</codeph> the |
|
98 language specific files. The languages are compiled into separate resource |
|
99 files (extension <codeph>.rxx</codeph>; the resource file for the current |
|
100 language is loaded by the UI framework at runtime</p></li> |
|
101 </ul><p/><p><b>\gfx</b></p><ul> |
|
102 <li><p><b>list_icon.bmp</b>, <b>list_icon_mask.bmp</b>, <b>mark_icon.bmp</b>, <b>mark_icon_mask.bmp</b>: |
|
103 Bitmap and bitmap masks. These are compiled into the MultiBitMap (<codeph>mbm</codeph>) |
|
104 format for display in the application.</p></li> |
|
105 <li><p> <b>qgn_menu_HelloWorld.svg</b>: SVG-T image that gets compiled into |
|
106 the <codeph>HelloWorld_aif.mif</codeph> MultiImageFile (<codeph>mif</codeph>) |
|
107 used for the application icon.</p></li> |
|
108 </ul><p/><p><b>\sis</b></p><ul> |
|
109 <li><p><b>HelloWorld.pkg</b>: Defines the contents that should be packaged |
|
110 into the installable <codeph>.sis</codeph> file for the device. This includes |
|
111 the executable as well as all resources required by the application (graphics |
|
112 and so on).</p></li> |
|
113 <li><p><b>HelloWorld.sis</b>: Compressed and self-contained installation file |
|
114 for the device. Compiled based on the package file. </p></li> |
|
115 <li><p><b>HelloWorld.sisx</b>: <codeph>.sis</codeph> file which has been signed |
|
116 with a certificate (in this case self-signed).</p></li> |
|
117 </ul> </section> |
|
118 <section id="GUID-65BEDD17-334B-4C42-8D89-DAB355F97F51"><title> Extending |
|
119 Hello World – Drawing</title><p>To make our application a little bit more |
|
120 interactive, we are going to implement a simple paint tool, allowing the user |
|
121 to draw lines by touching the screen. </p><p>We could draw the lines directly |
|
122 on the screen, but then everything would get lost when something caused our |
|
123 application to redraw the screen – for example, a telephone call that came |
|
124 through while our application was running. Therefore, we have to draw the |
|
125 lines to a bitmap, which is simply copied to the screen whenever required. |
|
126 </p><p>Another solution (more difficult but also more flexible!) would be |
|
127 to store all lines in a list and to iterate over the list each time the application |
|
128 needs to draw the contents of the screen. </p></section> |
|
129 <section id="GUID-217EFA6E-9B5F-4B65-8B99-E056CC26156D"><title> Using the |
|
130 SDK Documentation</title><p>The class that can handle bitmap data is called <codeph>CFbsBitmap</codeph>. |
|
131 Let’s take a look at the documentation for this class to find out more about |
|
132 the required header files, libraries and available methods. </p><p><xref href="http://developer.symbian.org/search/search_results.php?txtSearch=CFbsBitmap&site=sdl_collection.dita">Search</xref> the |
|
133 online documentation for the class you're interested in, in this case <codeph>CFbsBitmap</codeph>. <xref href="http://developer.symbian.org/main/documentation/reference/s%5E2/doc_source/reference/tb91sf-PP/fontandbitmapserver/index.html.dita">CFbsBitmap |
|
134 in Os Font_and_Bitmap_Server</xref> should be (one of the) first topics you |
|
135 find. </p><p/><note>If you're working offline you can also search for documentation |
|
136 in the SDK. <b>Start</b> menu: <b>Start - S60 Developer Tools - 5th Edition |
|
137 SDK, v<i>1.0</i> - SDK Documentation</b></note><p>Right at the top of the |
|
138 reference page you will see that the header file we need to use is <codeph>FBS.H</codeph> and |
|
139 the library we need to link against is called <codeph>fbscli.lib</codeph>. </p><fig id="GUID-23B3B7CF-E676-4FBC-8B26-E7B88764781C"> |
|
140 <image href="GUID-0B0EF90E-45A4-467F-8CD9-33FBC612B3BD_d0e4153_href.png" placement="inline"/> |
|
141 </fig><p>This class is capable of storing a bitmap. It's also possible to |
|
142 get direct access to the bitmap data. However for more convenient methods |
|
143 of drawing we will work through a drawing device and context. </p><p>To |
|
144 find out more about bitmaps, contexts and drawing functions, <xref href="http://developer.symbian.org/search/search_results.php?txtSearch=bitmaps&site=sdl_collection.dita">Search for ‘bitmaps’</xref> in the documentation, and go to the page <b>Bitmaps |
|
145 in Using Bitmaps</b>, or <b>Using Bitmaps in Using Graphics Device Interfaces</b>. |
|
146 Symbian provides several different device and context classes. For our |
|
147 application we’re going to use <codeph>CFbsBitmapDevice</codeph> (header file: <codeph>bitdev.h</codeph>, |
|
148 library: <codeph>bitgdi.lib</codeph>) and <codeph>CFbsBitGc</codeph> (header |
|
149 file: <codeph>bitstd.h</codeph>, library: <codeph>bitgdi.lib</codeph>). </p></section> |
|
150 <section id="GUID-D9C51891-11DE-4042-AE32-CC7EA362C32A"><title> Adding Libraries |
|
151 To a Project</title><p>In the previous step, we determined that we need two |
|
152 libraries in order to use all three bitmap-related classes: <codeph>fbscli.lib</codeph> and <codeph>bitgdi.lib</codeph>. |
|
153 To add them to our project, open the <codeph>HelloWorld.mmp</codeph> project |
|
154 file (in the <codeph>/group/</codeph> folder if you’re using the <b>Project |
|
155 Explorer</b> window). Switch to the <b>Libraries</b> tab. At the top of |
|
156 this page, you will see a list of included libraries. <codeph>fbscli.lib</codeph> is |
|
157 already in the list, so we don’t need to add it. However <codeph>bitgdi.lib</codeph> is |
|
158 missing. </p><note>There are more libraries in the list than are used by our |
|
159 project (added by the wizard!). These cause no harm so we choose not to remove |
|
160 them.</note><p>Click on the <b>Add</b> button. Search for <codeph>bitgdi.lib</codeph> in |
|
161 the list and add it to the <b>Libraries</b> list. </p><fig id="GUID-7D1E15B4-5157-4F48-9084-6DDBD6EE0208"> |
|
162 <image href="GUID-E5FB2D04-D57E-4EEA-850F-40F813C75D8C_d0e4231_href.png" placement="inline"/> |
|
163 </fig><p>When you’re finished, make sure that both libraries are in the <b>Libraries</b> list. |
|
164 </p><p>When you compile your application again, Carbide.c++ will detect |
|
165 the changes in the .mmp file and ask you what to do. Click on <b>Compile and |
|
166 Link</b> to update the project with the changes we have made to the <codeph>.mmp</codeph> file. <fig id="GUID-77F781CD-A2EF-4489-BAE2-EB283057670E"> |
|
167 <image href="GUID-10540A35-7E8E-40F0-BF93-CBC01884550C_d0e4248_href.png" placement="inline"/> |
|
168 </fig></p></section> |
|
169 <section id="GUID-F2A4FC0F-8C67-4151-8BD2-808FCEDD121F"><title> Creating Bitmaps</title><p>Now |
|
170 the libraries have been added, we can use the bitmap classes in our project. |
|
171 Open the file <codeph>HelloWorldContainer.h</codeph> and add the following |
|
172 include statements: </p><codeblock xml:space="preserve">#include <fbs.h> |
|
173 #include <bitdev.h> |
|
174 #include <bitstd.h> |
|
175 </codeblock><p>We also need to store the bitmap objects as instance (member) |
|
176 variables. Add the following definitions to a private section of the <codeph>CHelloWorldContainer</codeph> class. |
|
177 Be careful not to write anything into areas managed by the UI designer, because |
|
178 your changes could be overwritten. These areas are marked by comments. |
|
179 </p><codeblock xml:space="preserve">private: |
|
180 CFbsBitmap* iBitmap; |
|
181 CFbsBitmapDevice* iBmpDevice; |
|
182 CFbsBitGc* iBmpGc; </codeblock><p>Symbian C++ uses some <xref href="http://developer.symbian.org/wiki/index.php/Coding_Standards_and_Conventions.dita#http://developer.symbian.org/wiki/index.php/Coding_Standards_and_Conventions/Naming_Conventions">naming conventions</xref>. Instance variables should have a lowercase <codeph>i</codeph> at |
|
183 the beginning of the variable name (<codeph>iBitmap</codeph>). Arguments should |
|
184 be marked by an a (<codeph>aBitmap</codeph>). Normal local variables that |
|
185 you create inside a function do not need any prefix. That way, you instantly |
|
186 know where the variable is coming from – this is very important when deleting |
|
187 objects. Next, we want to create the bitmap. Define and implement a new |
|
188 method: </p><codeph>void CHelloWorldContainer::CreateBitmapsL()</codeph><p>Let’s |
|
189 go line by line through the required code for this method: First, we have |
|
190 to make sure that any previous objects are deleted if they already exist. |
|
191 This would be required (for example) if the running application needs to re-create |
|
192 the bitmap because the screen layout changes. You don’t need to add an if |
|
193 statement to check if the pointer is NULL beforehand – the C++ <codeph>delete</codeph> statement |
|
194 only deletes the object if the pointer is not NULL. You do however need to |
|
195 ensure that the objects are set to NULL after deletion to avoid possible "double |
|
196 deletion" in the destructor. </p><codeblock xml:space="preserve">delete iBitmap; iBitmap = NULL; |
|
197 delete iBmpDevice; iBmpDevice = NULL; |
|
198 delete iBmpGc; iBmpGc = NULL;</codeblock><p>This following line of code should |
|
199 look familiar – it simply creates an instance of the <codeph>CFbsBitmap</codeph> class: |
|
200 </p><p><codeph> iBitmap = new (ELeave) CFbsBitmap();</codeph> </p><p>The |
|
201 (<codeph>ELeave</codeph>) parameter is Symbian C++ specific. This causes a <xref href="http://developer.symbian.org/wiki/index.php/Leaves_%26_The_Cleanup_Stack_(Fundamentals_of_Symbian_C%2B%2B).dita"> leave</xref> (the |
|
202 Symbian C++ equivalent of standard exceptions) if allocating the object fails |
|
203 – for example, because there is not enough free memory. With the (<codeph>ELeave</codeph>), |
|
204 you don’t have to manually check if the pointer is actually pointing to a |
|
205 valid object after creating the object instance. You can find out more about |
|
206 leaves in <xref href="http://developer.symbian.org/wiki/index.php/Fundamentals_of_Symbian_C%2B%2B.dita">Fundamentals |
|
207 of C++</xref>. </p><p>We do not handle the potential leave here; that’s |
|
208 why the method name (<codeph>CreateBitmapL()</codeph>) has a trailing L to |
|
209 show that it can also leave. More on this topic in a moment. </p><p>Now, |
|
210 it’s time to let the <codeph>CFbsBitmap</codeph> class allocate the memory |
|
211 for the bitmap it is going to manage. The available drawing size for our container |
|
212 can be queried by the method <codeph>Size()</codeph> from its base class. <codeph>EColor16MU</codeph> specifies |
|
213 the color depth – in this case, it’s a true color display mode with 32 bits |
|
214 per pixel; the top byte is unused. The color mode <codeph>EColor16MA</codeph> would |
|
215 use the top byte for the alpha channel, several other modes are available |
|
216 as well. </p><p><codeph>iBitmap->Create(Size(), EColor16MU);</codeph> |
|
217 </p><p>The next line creates a graphics device based on the bitmap. A graphics |
|
218 device represents the medium being drawn to and is needed to create a graphics |
|
219 context. The use of a <codeph>NewL()</codeph> method is common in Symbian |
|
220 C++; it is a static factory function which returns a fully constructed object |
|
221 of the desired type. </p><p><codeph> iBmpDevice = CFbsBitmapDevice::NewL(iBitmap);</codeph> |
|
222 </p><p>A graphics context provides a large number of drawing operations, |
|
223 along with state settings defining how the drawing is performed. The bitmap |
|
224 graphics context used here is a specialization of the generic graphics context |
|
225 and adds some methods that can be used for bitmaps only – such as clearing |
|
226 and copying rectangular areas. </p><p><codeph>iBmpDevice->CreateContext(iBmpGc);</codeph> |
|
227 </p><p>Whenever you create objects, it’s best to think about where and when |
|
228 they are going to be deleted right away. Memory leaks are a serious issue |
|
229 on a mobile device where no virtual memory is available and the main memory |
|
230 is limited to 30-80 MB. Therefore, go to the destructor of <codeph>CHelloWorldContainer</codeph> and |
|
231 add the required statements for deleting the three objects: </p><p> <codeblock xml:space="preserve">delete iBmpGc; |
|
232 delete iBmpDevice; |
|
233 delete iBitmap;</codeblock> </p><p>The next step addresses the remaining |
|
234 question: where to call the <codeph>CreateBitmapsL()</codeph> method. Of course, |
|
235 you could do this from the construction methods of the class. But what if, |
|
236 while your application is running, the user physically turns the phone, causing |
|
237 it to switch from portrait to landscape mode? Because the bitmap was created |
|
238 with the portrait size in mind, the user would no longer be able to use the |
|
239 full screen for drawing. </p><p>Therefore, we have to react to events that |
|
240 inform us when the screen size is changed. In those situations, <codeph>SizeChanged()</codeph> is |
|
241 executed. When the container is first constructed, its size changes as well. |
|
242 Because of this, we can simply call our <codeph>CreateBitmapsL()</codeph> method |
|
243 from within <codeph>SizeChanged()</codeph>: </p><p><codeblock xml:space="preserve">void CHelloWorldContainer::SizeChanged() |
|
244 { |
|
245 CCoeControl::SizeChanged(); |
|
246 LayoutControls(); |
|
247 // [[[ begin generated region: do not modify [Generated Contents] |
|
248 // ]]] end generated region [Generated Contents] |
|
249 if (!iBitmap || (iBitmap && iBitmap->SizeInPixels() != Size())) |
|
250 { |
|
251 TRAPD(err, CreateBitmapsL()); |
|
252 } |
|
253 }</codeblock> </p><p>In the source code above, an additional check ensures |
|
254 that the bitmap is only re-created if the size available for the container |
|
255 is really different to the existing bitmap size – the <codeph>SizeChanged()</codeph> method |
|
256 is also called, for example, when the option menu obscures part of our view. |
|
257 This does not affect the available space for our drawing area and therefore |
|
258 should not lead to re-creating the bitmap. </p><p>But what is the <codeph>TRAPD()</codeph> statement |
|
259 doing here? Let’s use this to take a closer look at the concept of leaves. </p><p/><p><b>Leaves</b></p><p>When |
|
260 programming using Symbian C++, an L is appended to the name of methods that |
|
261 can leave (usually because it contains other methods that can leave and does |
|
262 not choose to "TRAP" them). Note: this is a helpful convention, but is not |
|
263 checked or required by the compiler. </p><p>Our <codeph>CreateBitmapsL()</codeph> method |
|
264 contains two methods that can leave: the (<codeph>ELeave</codeph>) parameter |
|
265 causes a leave if there is not enough memory to allocate the object. The <codeph>NewL()</codeph> method |
|
266 from the graphics device also has a trailing <codeph>L</codeph> – meaning |
|
267 that this method can also leave. We did not catch any (all) of those leaves |
|
268 in the <codeph>CreateBitmapsL()</codeph> method so it was named with a trailing <codeph>L</codeph>. |
|
269 </p><p>Any leaves are passed up in the call stack until caught by a <codeph>TRAPD</codeph> macro. |
|
270 The <codeph>SizeChanged()</codeph> method traps any leaves from <codeph>CreateBitmapsL()</codeph> and |
|
271 consequently does <b>not</b> need to have a trailing <codeph>L</codeph>. |
|
272 </p><p>The error code of the leave is stored in the err variable, which |
|
273 is declared as a normal integer by this macro. It would be a good idea to |
|
274 take a look at the contents of this variable and to handle errors instead |
|
275 of ignoring them as we’re doing here. But for the sake of simplicity, we do |
|
276 not handle any errors that might occur in this situation. </p><p/><p><b>Tip</b></p><p>A |
|
277 good way to automatically check your code for potential problems is to use |
|
278 the <i>CodeScanner</i> tool that comes with Carbide.c++. It is a static code-analysis |
|
279 tool looking at Symbian coding rules and standards. Find out more at: <xref href="http://carbidehelp.nokia.com/help/topic/com.nokia.carbide.cpp.codescanner/html/codescanner.htm.dita">http://carbidehelp.nokia.com/help/topic/com.nokia.carbide.cpp.codescanner/html/codescanner.htm</xref></p></section> |
|
280 <section id="GUID-7E4A9491-8F22-4D68-9890-95332D31412B"><title> Handling Touch |
|
281 Events</title><p>Before we start handling the touch events, we need one more |
|
282 instance variable in our code. To draw a line from one touch position to the |
|
283 next, it’s necessary to save the first position. Therefore, add the following |
|
284 private instance variable to <codeph>CHelloWorldContainer</codeph>: <codeblock xml:space="preserve">TPoint iLastPos;</codeblock></p><p><codeph>TPoint</codeph> is |
|
285 a convenience class that stores two integers that can be used as co-ordinates. |
|
286 Additionally, it provides some methods to modify the point. We do not need |
|
287 to initialize the variable in the constructor of the <codeph>CHelloWorldContainer</codeph> class |
|
288 – the container class is indirectly derived from the class <codeph>CBase</codeph>, |
|
289 which automatically zero-initializes all member variables. Touch events |
|
290 are delivered to the container class, which is responsible for managing the |
|
291 visible UI content in the main pane of your application. To handle the events |
|
292 ourselves, we have to override the following method in <codeph>CHelloWorldContainer</codeph>: </p><p><codeph>void |
|
293 CHelloWorldContainer::HandlePointerEventL(const TPointerEvent& aPointerEvent)</codeph></p><p>Define |
|
294 this method in the header file (can be private or protected) and add its implementation |
|
295 in the <codeph>.cpp</codeph> file. The information about the new event |
|
296 is sent through the argument <codeph>aPointerEvent</codeph>. We are interested |
|
297 in the up event for the first button (there is only one in current touch devices; |
|
298 you can’t click with a right button as you would with a mouse). Whenever the |
|
299 user releases the stylus or finger from the touch screen, we want to draw |
|
300 a line to this position. Put the following code into this if statement: <codeblock xml:space="preserve">if (aPointerEvent.iType == TPointerEvent::EButton1Up) |
|
301 { |
|
302 }</codeblock></p><p>Drawing the line itself is rather simple. First, define |
|
303 the color and style that should be used for drawing, then call the function |
|
304 for drawing the line. Note that the settings concerning the color and style |
|
305 stay active until they are changed again in this graphics context – you do |
|
306 not need to set them every time when executing consecutive drawing operations. </p><codeblock xml:space="preserve">iBmpGc->SetPenColor(KRgbRed); |
|
307 iBmpGc->SetPenSize(TSize(2,2)); |
|
308 iBmpGc->DrawLine(iLastPos, aPointerEvent.iPosition);</codeblock><p>Next, we |
|
309 have to save the new position, because it will be required as the starting |
|
310 point for the next line. </p><codeph>iLastPos = aPointerEvent.iPosition;</codeph><p>Finally, |
|
311 issue a request to the framework to redraw the screen. Otherwise, the user |
|
312 won’t see the new line! </p><codeph>DrawDeferred();</codeph><p>At the end |
|
313 of the method, also call the <codeph>HandlePointerEventL()</codeph> method |
|
314 of the base class (the container is derived from <codeph>CCoeControl</codeph>, |
|
315 because it is a normal UI control by itself): </p><codeph>CCoeControl::HandlePointerEventL(aPointerEvent);</codeph><p>To |
|
316 sum it up, this is the final code for the <codeph>HandlePointerEvent()</codeph> method: </p><codeblock xml:space="preserve">void CHelloWorldContainer::HandlePointerEventL(const TPointerEvent& aPointerEvent) |
|
317 { |
|
318 if (aPointerEvent.iType == TPointerEvent::EButton1Up) |
|
319 { |
|
320 iBmpGc->SetPenColor(KRgbRed); |
|
321 iBmpGc->SetPenSize(TSize(2,2)); |
|
322 iBmpGc->DrawLine(iLastPos, aPointerEvent.iPosition); |
|
323 iLastPos = aPointerEvent.iPosition; |
|
324 DrawDeferred(); |
|
325 } |
|
326 CCoeControl::HandlePointerEventL(aPointerEvent); |
|
327 }</codeblock><p>We’ve already added all the code required for drawing |
|
328 to the bitmap, but this bitmap still has to be transferred to the screen. |
|
329 The <codeph>CHelloWorldContainer::Draw()</codeph> method is called when the |
|
330 system wants the contents of the container to be redrawn. Therefore, we need |
|
331 to add the following line of code to the end of the <codeph>Draw()</codeph> method, |
|
332 which copies the bitmap to the top left of the graphics context of the screen: </p><codeph>gc.BitBlt(TPoint(0, |
|
333 0), iBitmap);</codeph><p>Now compile the project. It should already work – |
|
334 you can draw red lines by just clicking inside the main pane of the emulator! </p><fig id="GUID-CFD29EE4-464B-498C-80F5-493847DE0AEE"> |
|
335 <image href="GUID-700CD2E2-DBB7-40BD-BC6D-9BC79C5A0BBF_d0e4528_href.png" placement="inline"/> |
|
336 </fig></section> |
|
337 <section id="GUID-8DC096A0-807D-437C-9A96-ABAFE2AF7F26"><title> Defining |
|
338 a Menu </title><p>The application would be improved if the user could clear |
|
339 the drawing during use, rather than having to restart it. This section shows |
|
340 how you add and handle menu items to provide this functionality, and to exit |
|
341 the application Open the <codeph>HelloWorldContainer.uidesign</codeph> document. |
|
342 You can find it in the root folder of your project in the <b>Project Explorer</b> or |
|
343 in the <b>UI Designs</b> folder of the Symbian Project Navigator. </p><p>Click |
|
344 on the <b>Options</b> menu item below the UI design to reveal the menu. As |
|
345 indicated, you simply need to click on the empty menu item and start typing. </p><fig id="GUID-96D944A2-87C5-4530-AB0C-580C3277285D"> |
|
346 <image href="GUID-20FEEF54-23CB-4D30-B846-11B4ACE8E772_d0e4552_href.png" placement="inline"/> |
|
347 </fig><p>Add two menu items – <b>Clear</b> (for clearing the image) and <b>Exit</b> (for |
|
348 closing the application). </p><p>Then click once on the Exit menu item |
|
349 to select it. Go to the <b>Behavior</b> group of the <b>Properties</b> window |
|
350 and change the command ID to <codeph>EAknCmdExit</codeph> (this is available |
|
351 in the drop-down list). This command will also be sent to your application |
|
352 if the operating system wants to shut it down, for example, when the phone |
|
353 does not have enough memory left. Therefore, it is necessary that every application |
|
354 always responds to this event and instantly shuts the application down. It |
|
355 is already handled by the basic application that the Carbide.c++ wizard generated |
|
356 for you; you don’t need to implement the command handling for this event yourself. </p><fig id="GUID-8FD2973F-23FF-4734-AE16-CA39C02C7DE5"> |
|
357 <image href="GUID-D7F000F0-019A-486E-BB0C-C0065D08C5F6_d0e4575_href.png" placement="inline"/> |
|
358 </fig><p>If you try your application now, you will see that the Exit menu |
|
359 item already works. </p><p/><p><b>Tip</b></p><p> When testing the application, |
|
360 always quit your application using the <b>Exit</b> command (rather than just |
|
361 closing the emulator). The application environment will then automatically |
|
362 check for memory leaks. If you just shut down the emulator you may not discover |
|
363 the leak until much later, making it a lot more difficult to find the cause.</p></section> |
|
364 <section id="GUID-0090F731-A243-44C7-96ED-1EC5DB172F8D"><title> Clearing the |
|
365 Drawing </title><p>Whenever the <b>Clear</b> menu item is selected the view |
|
366 class method <codeph>CHelloWorldContainerView::HandleCommandL()</codeph> is |
|
367 called with the command ID of the menu item as a parameter. </p><p> If we |
|
368 want to handle the menu item, the UI designer can create the necessary code |
|
369 for us. Right-click on the menu item and choose <b>Handle ‘selected’ Event</b>. |
|
370 The UI designer will ask you to save the design – choose <b>Yes</b>. The code |
|
371 will then be generated and you will jump into the code view to a new method |
|
372 called <codeph>HandleClearMenuItemSelectedL()</codeph> – a more convenient |
|
373 place to put your command-handling code than directly in a big <codeph>HandleCommandL()</codeph> method |
|
374 that receives all commands. The auto-generated source code therefore calls |
|
375 the new extra method from within <codeph>HandleCommandL()</codeph> (take a |
|
376 look at that method to see what really happens). </p><fig id="GUID-8E944FEE-EFDF-4AFE-BEB8-F3B216B91A98"> |
|
377 <image href="GUID-881C353C-6482-4DFE-9D43-CFB80DEB77A5_d0e4619_href.png" placement="inline"/> |
|
378 </fig><p>Now, we only need to tell the container that it should clear its |
|
379 bitmap buffer. To do this, create a new public method in the container: </p><codeblock xml:space="preserve">void CHelloWorldContainer::ClearDrawing() |
|
380 { |
|
381 iBmpGc->Clear(); |
|
382 DrawDeferred(); |
|
383 }</codeblock><p>Now, call this method from the menu item handler method. |
|
384 As explained in the section about the application architecture, the view class |
|
385 (<codeph>CHelloWorldContainerView</codeph>) is the controller and owner for/of |
|
386 the container class (<codeph>CHelloWorldContainer</codeph>). Therefore, this |
|
387 class has a pointer to the container as an instance variable, which you can |
|
388 use to clear the drawing. </p><codeblock xml:space="preserve">TBool CHelloWorldContainerView::HandleClearMenuItemSelectedL(TInt aCommand) |
|
389 { |
|
390 iHelloWorldContainer->ClearDrawing(); |
|
391 return ETrue; |
|
392 }</codeblock><p>The menu command should now clear the image. </p><p>Congratulations, |
|
393 you have completed the tutorial and have created your own small mobile painting |
|
394 application! </p></section> |
|
395 <section id="GUID-2BD775FF-BD36-4550-A388-48A3B1832D9E"><title> Further Exercises</title><p>As |
|
396 an exercise, it’s a good idea to extend the application by yourself – for |
|
397 example, you could add some menu items that allow the end user to change the |
|
398 color of the pen. </p><p/><p><b>Tip</b></p><p> It’s a good idea to learn |
|
399 keyboard shortcuts as early as possible, because they can significantly increase |
|
400 the efficiency of your work. For example, you can press <b>Ctrl + B</b> to |
|
401 build the project, instead of using the icon or the menu commands. Also very |
|
402 helpful: <b>Ctrl + Shift + F</b> automatically formats and indents your code. |
|
403 You can get a full list of commands by pressing <b>Ctrl + 3</b>. A hot keys |
|
404 list appears when you press <b>Ctrl + Shift + L</b>.</p><p/><p> <b>Importing |
|
405 Other Examples</b></p><p>The S60 SDK itself installs many examples; additional |
|
406 applications can be downloaded from the developer.symbian.org and Forum Nokia |
|
407 (see the Related Info section for more information). To import ready-made |
|
408 applications in Carbide.c++, go to <b>File | Import</b>. In the following |
|
409 dialog, select <b>Symbian OS Bld.inf file</b> and click <b>Next</b>. </p><fig id="GUID-8E8F4507-70E7-496C-AE4D-16DAD8146ABA"> |
|
410 <image href="GUID-631E27DB-97A7-47E2-8FC1-856198435FFF_d0e4681_href.png" placement="inline"/> |
|
411 </fig><p/><p>Now, click <b>Browse</b> and navigate to the <codeph>bld.inf</codeph> file |
|
412 of the project you want to import. It’s usually stored in the <codeph>/group/</codeph> subfolder |
|
413 of the project. </p><fig id="GUID-B682943D-10EE-4DC8-B510-7C2D54C536EE"> |
|
414 <image href="GUID-C588B869-6940-42B2-84F9-71467F6A4306_d0e4697_href.png" placement="inline"/> |
|
415 </fig><p>In the following step, select which SDKs you would like to use. The |
|
416 same considerations as those explained when creating your Hello World application |
|
417 apply. </p><fig id="GUID-5A381CA4-CCE0-4359-8F02-697AEDA72BDE"> |
|
418 <image href="GUID-D492CF6C-F889-4299-AC75-951EF343AC9F_d0e4703_href.png" placement="inline"/> |
|
419 </fig><p>You can usually accept the default values for the next step and let |
|
420 the wizard import everything. </p><p>In the last step, you have to define |
|
421 the <b>Project Properties</b>. In most cases, you can leave the default values. </p><fig id="GUID-1AB6D789-9407-4AB0-8F52-B1138DE063BD"> |
|
422 <image href="GUID-F18A6C91-136D-450E-90F0-7C2B9263777C_d0e4714_href.png" placement="inline"/> |
|
423 </fig><p>Afterwards, the project is imported and you can start working. The |
|
424 project contents will not be copied to the current Carbide.c++ workspace, |
|
425 so you will work directly on the original directory and the original files. |
|
426 Copy the project to a different directory first if you want to keep the original |
|
427 project or example in its original state – for example, into the workspace |
|
428 directory. </p><p><b>Troubleshooting</b>: If <keyword>importing</keyword> the |
|
429 project fails, take special care of the last step of the import process: the |
|
430 root directory should be set correctly to the root directory of the project |
|
431 and not one level above it. Also, the project name should be the same as the |
|
432 last part of the root directory. From time to time, the default values are |
|
433 not configured properly, causing problems in the import process. </p><p/><p><b>Warning</b> </p><p>Do |
|
434 not use the standard (Eclipse) project import! The reason is that this import |
|
435 method would also import all build configuration settings, including references |
|
436 to installed SDKs and paths on the original system. Therefore, if you import |
|
437 a project from somebody else but don’t have the SDK installed in exactly the |
|
438 same directory, the build configurations will no longer work. The <codeph>bld.inf</codeph> import |
|
439 method recreates the SDK bindings and only imports the real contents of the |
|
440 project.</p></section> |
|
441 <section id="GUID-191D5D9D-00FB-47F0-B88B-8B87588A20C8"><title> Summary</title><p>This |
|
442 part of the tutorial has shown how we can extend the basic skeleton from the <xref href="GUID-301E5FAA-A1C3-4FD7-9D84-DAA61C66981B.dita">Symbian C++ Quick Start</xref> to |
|
443 create a small paint application. The tutorial explains the application framework, |
|
444 including how you define menus, how to handle touch-screen events, drawing |
|
445 to the screen etc. </p></section> |
|
446 <section id="GUID-8B6E602D-CA6B-41DD-B3DC-4C3BC9A04154"><title> Related Info</title><ul> |
|
447 <li><p><xref href="GUID-301E5FAA-A1C3-4FD7-9D84-DAA61C66981B.dita">Symbian C++ |
|
448 Quick Start</xref></p></li> |
|
449 <li><p><xref href="http://developer.symbian.org/wiki/index.php/Getting_Started_with_Debugging_on_the_Device.dita">Getting |
|
450 Started with Debugging on the Device</xref></p></li> |
|
451 <li><p><xref href="http://developer.symbian.org/wiki/images/e/eb/HelloSymbianWorld_Example_Code.zip.dita">File: |
|
452 HelloSymbianWorld Example Code.zip</xref> (code example associated with this |
|
453 article)</p></li> |
|
454 </ul></section> |
|
455 </conbody></concept> |