|
1 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
|
2 <html lang="en" xml:lang="en"> |
|
3 <head> |
|
4 <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> |
|
5 <meta name="copyright" content="(C) Copyright 2005" /> |
|
6 <meta name="DC.rights.owner" content="(C) Copyright 2005" /> |
|
7 <meta content="concept" name="DC.Type" /> |
|
8 <meta name="DC.Title" content="Creating the Hello World widget" /> |
|
9 <meta scheme="URI" name="DC.Relation" content="WRTKit_Hello_World_Tutorial-GUID-67e0a561-48ac-4938-8f1b-852422b71380.html" /> |
|
10 <meta content="XHTML" name="DC.Format" /> |
|
11 <meta content="GUID-D638159A-D12B-476C-A74C-99055672B7BE" name="DC.Identifier" /> |
|
12 <meta content="en" name="DC.Language" /> |
|
13 <link href="commonltr.css" type="text/css" rel="stylesheet" /> |
|
14 <title> |
|
15 Creating the Hello World widget</title> |
|
16 </head> |
|
17 <body id="GUID-D638159A-D12B-476C-A74C-99055672B7BE"><a name="GUID-D638159A-D12B-476C-A74C-99055672B7BE"><!-- --></a> |
|
18 |
|
19 |
|
20 |
|
21 <h1 class="topictitle1"> |
|
22 Creating the Hello World widget</h1> |
|
23 |
|
24 <div> |
|
25 |
|
26 <div class="section"><h2 class="sectiontitle"> |
|
27 What goes in the widget?</h2> |
|
28 |
|
29 |
|
30 <p> |
|
31 |
|
32 One of the main reasons why Hello World is a good example to start with is |
|
33 because it is a minimal widget and shows the minimal set of steps that you |
|
34 would go through to create a widget that uses the WRTKit for its user interface. |
|
35 We will create just two files, an HTML file called HelloWorld.html and a JavaScript |
|
36 file called HelloWorld.js and both will be very short. |
|
37 </p> |
|
38 |
|
39 <p> |
|
40 |
|
41 Before we'll start writing code let's talk about what exactly it is that we want |
|
42 to build. A typical Hello World application simply displays the text Hello World |
|
43 with the minimal amount of code. But because using the WRTKit is so simple, we'll |
|
44 go one step further and make it a bit fancier. |
|
45 </p> |
|
46 |
|
47 <p> |
|
48 |
|
49 WRTKit user interfaces are composed of views and controls. A view is one logical |
|
50 group of stuff that you can see on the screen. A view can be longer than what fits |
|
51 on the screen at once in which case the user has to scroll, but it's still one view. |
|
52 For example in a web browser application you might have one view for the bookmarks, |
|
53 another for settings and a third view for viewing actual web pages. Controls are |
|
54 user interface elements like buttons, text fields, checkboxes, etc. that either |
|
55 let the user perform some kind of interactive action or simply shows some information. |
|
56 When you create a user interface with the WRTKit you create one or more controls, |
|
57 one or more views, and place the controls on the views. After this, all you have to |
|
58 do is ask one of the views to be displayed and the rest happens automatically. |
|
59 </p> |
|
60 |
|
61 <p> |
|
62 |
|
63 Since this is a very simple widget we will just have one view and we'll call it |
|
64 the "main view". Instead of just saying "Hello World" we will let the user input |
|
65 their name and then click a button to popup a dialog that says hello to the user |
|
66 by name. E.g. if the user enters "John" we will popup "Hello John!". But we will |
|
67 also create some error handling so that if the user doesn't input a name we will |
|
68 popup a warning dialog that says "Please enter your name!" instead. |
|
69 </p> |
|
70 |
|
71 </div> |
|
72 |
|
73 <div class="section"><h2 class="sectiontitle"> |
|
74 The HelloWorld.html file</h2> |
|
75 |
|
76 |
|
77 <p> |
|
78 |
|
79 As mentioned earlier, you create user interfaces using JavaScript rather than |
|
80 HTML when you use the WRTKit. Because of this it's perhaps not so surprising |
|
81 that the HTML file is extremely short. What might come as a surprise however is |
|
82 that it's extremely short and nearly identical no matter what kind of widget |
|
83 you are building if you are using the WRTKit. In fact it typically only has |
|
84 about 10 lines of code, including the DOCTYPE declaration! Here's what it looks |
|
85 like: |
|
86 </p> |
|
87 |
|
88 <pre> |
|
89 |
|
90 <?xml version="1.0" encoding="UTF-8"?> |
|
91 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
|
92 <html xmlns="http://www.w3.org/1999/xhtml"> |
|
93 <head> |
|
94 <title></title> |
|
95 <script type="text/javascript" src="WRTKit/WRTKit.js"></script> |
|
96 <script type="text/javascript" src="HelloWorld.js"></script> |
|
97 </head> |
|
98 <body onload="init()"> |
|
99 </body> |
|
100 </html> |
|
101 </pre> |
|
102 |
|
103 <p> |
|
104 |
|
105 We're using XHTML 1.0 so the DOCTYPE declaration is for XHTML 1.0 Strict. And |
|
106 because this is XHTML we also have the normal XML declaration (<?xml...). |
|
107 After that the content should be familiar even if you've used previously only |
|
108 used HTML rather than XHTML. We have a normal html root level tag with a head |
|
109 and body. Note that in XHTML tags are case sensitive and should be in lowercase |
|
110 as in the example above. The xmlns attribute is a name space declaration that |
|
111 states that all the tags used here are part of the XHTML standard. |
|
112 </p> |
|
113 |
|
114 <p> |
|
115 |
|
116 Because we're creating a widget and not a web page we don't need to have a title. If you |
|
117 want you can define one here but you won't see it anywhere. Next comes an important |
|
118 bit: <samp class="codeph"> |
|
119 <script type="text/javascript" src="WRTKit/WRTKit.js"></script>.</samp> |
|
120 That piece of code instructs the Web Runtime to load a JavaScript file called WRTKit.js |
|
121 from a directory called WRTKit. The WRTKit.js file takes care of loading the WRTKit and |
|
122 including all the files that are needed by it. Those files are all inside the WRTKit |
|
123 directory and you don't need to concern yourself with them at this point. In fact |
|
124 all you need to do to use the WRTKit in a widget is to copy the WRTKit directory into |
|
125 your own widget's root directory and then include the XHTML script tag presented above |
|
126 that loads the WRTKit/WRTKit.js JavaScript file. If you are creating a widget of your own |
|
127 you can find the WRTKit directory in the Library directory in the WRTKit SDK. But for your |
|
128 convenience it has already been copied to the Hello World example. |
|
129 </p> |
|
130 |
|
131 <p> |
|
132 |
|
133 Notice that there's another script tag too, this one loading a file called HelloWorld.js. |
|
134 This is where we'll put all the JavaScript code that implements our Hello World widget. |
|
135 We could have just written the JavaScript code inline between a <script> and |
|
136 </script> tag in the HelloWorld.html file but the HTML file is less cluttered if |
|
137 we move all JavaScript to a separate file. |
|
138 </p> |
|
139 |
|
140 <p> |
|
141 |
|
142 Finally let's look at the body tag. There are two things of interest here. First of all |
|
143 there's no content between <body> and </body>. That's because all of the |
|
144 content will be created by the WRTKit using JavaScript. And that leads us to the other |
|
145 point of interest in the body: the <samp class="codeph"> |
|
146 onload="init()"</samp> attribute of the |
|
147 body tag. This sets up an event handler that gets called after the widget has loaded |
|
148 all of its content. The event handler calls a JavaScript function called init(). This |
|
149 is the point where we jump from the HTML to JavaScript. From this point on everything |
|
150 will be JavaScript and the place where it all starts is the init() function that gets |
|
151 called thanks to this little onload event handler for the body tag. |
|
152 </p> |
|
153 |
|
154 </div> |
|
155 |
|
156 <div class="section"><h2 class="sectiontitle"> |
|
157 The HelloWorld.js file</h2> |
|
158 |
|
159 |
|
160 <p> |
|
161 |
|
162 The HTML file that we created above set things up so that there is a function call |
|
163 to a function named "init()" when the widget is done loading. No such function exists |
|
164 a this point so we have to create it. The init() function is the entry point to our |
|
165 JavaScript and this is also where we will start the implementation. |
|
166 </p> |
|
167 |
|
168 <p> |
|
169 |
|
170 The S60 Web Runtime supports two kinds of user interface interaction: tab and |
|
171 pointer. The WRTKit supports but methods but usually the tab interaction method |
|
172 (also known as "navigation mode") is preferred. Unfortunately the pointer based |
|
173 navigation mode is the default so we'll have to disable it and switch to the tab |
|
174 navigation mode. Also by default the softkey bar is hidden, which we don't want |
|
175 because we want to give the user a clue about how to exit the widget. The good news |
|
176 is that these two tweaks are easy to do and only requires two simple method calls. |
|
177 The bad news is that those method calls are done through objects that only exist |
|
178 in the Web Runtime but not in a PC web browser. Due to this, we'll create the |
|
179 init() function as follows: |
|
180 </p> |
|
181 |
|
182 <pre> |
|
183 |
|
184 // Called from the onload event handler to initialize the widget. |
|
185 function init() { |
|
186 // set tab-navigation mode and show softkeys |
|
187 // (only if we are in the WRT environment) |
|
188 if (window.widget) { |
|
189 widget.setNavigationEnabled(false); |
|
190 menu.showSoftkeys(); |
|
191 } |
|
192 } |
|
193 </pre> |
|
194 |
|
195 <p> |
|
196 |
|
197 We wrapped the calls to disable the pointer navigation and show the softkeys |
|
198 in an if-clause that checks if there's such an object available as window.widget. |
|
199 This will evaluate to false on a PC web browser but true in the S60 Web Runtime. |
|
200 </p> |
|
201 |
|
202 <p> |
|
203 |
|
204 Now that we've tuned the Web Runtime to our liking we can create the actual |
|
205 user interface. We'll create four things: the so-called "user interface manager" |
|
206 that is in charge of managing views and other user interface resources, the main |
|
207 view for the widget, a text field where users can enter their name, and finally |
|
208 a button that they can click on to popup a notification dialog that says "Hello" |
|
209 Notice that we don't have to create the notification dialog because this is done |
|
210 for us by the user interface manager. |
|
211 </p> |
|
212 |
|
213 <p> |
|
214 |
|
215 Before we create those four objects we will declare four global variables so that |
|
216 we can access those objects elsewhere in the widget. So let's add the following |
|
217 to the top of the file (outside the init() function): |
|
218 </p> |
|
219 |
|
220 <pre> |
|
221 |
|
222 // References to the WRTKit user interface manager and main view. |
|
223 var uiManager; |
|
224 var mainView; |
|
225 |
|
226 // References to controls in the main view. |
|
227 var helloButton; |
|
228 var nameField; |
|
229 </pre> |
|
230 |
|
231 <p> |
|
232 |
|
233 Now that we have some variables that can track the objects we are about to create |
|
234 we can actually craete those objects. We'll create the objects inside the init() |
|
235 function so that the user interface gets created right after the widget has loaded. |
|
236 </p> |
|
237 |
|
238 <p> |
|
239 |
|
240 The first thing we create is the user interface manager. This is quite simple and |
|
241 requires only a single line of code: |
|
242 </p> |
|
243 |
|
244 <pre> |
|
245 |
|
246 // create UI manager |
|
247 uiManager = new UIManager(); |
|
248 </pre> |
|
249 |
|
250 <p> |
|
251 |
|
252 Next we'll create the main view. The WRTKit allows all kinds of views to be created |
|
253 if one has special needs for how user interface controls should be laid out. However |
|
254 in the vast majority of cases the ListView class will be sufficient and that's what |
|
255 we'll create this time too: |
|
256 </p> |
|
257 |
|
258 <pre> |
|
259 |
|
260 // create main view |
|
261 mainView = new ListView(null, "Hello World"); |
|
262 </pre> |
|
263 |
|
264 <p> |
|
265 |
|
266 The first argument to the ListView constructor is a unique identifier for the view. |
|
267 All user interface elements in the WRTKit can have a unique identifier. The identifier |
|
268 is helpful if you want to specifically target a view or control with some CSS style |
|
269 rule or if you want to identify the source of an event in an event listener callback, |
|
270 etc. However we don't need it here so we don't bother giving our main view a unique |
|
271 id and just pass a null identifier value instead. The second argument is a caption for |
|
272 the view. We'll just call our view "Hello World". The caption will be displayed at the |
|
273 very top of the screen when we display the main view. But before we do that, let's |
|
274 create the rest of the user interface. |
|
275 </p> |
|
276 |
|
277 <p> |
|
278 |
|
279 The widget should have a text field to let users enter their name and a button to |
|
280 trigger the greeting popup. Both the text field and the button are WRTKit controls |
|
281 and will be created and added to the main view that we just created. There are two |
|
282 kinds of buttons in the WRTKit though, form buttons and navigation buttons. Form |
|
283 buttons are meant to trigger actions whereas navigation buttons are meant for |
|
284 situations where clicking it would result in moving from one view to another. Clearly |
|
285 therefore, we want a form button in this case. |
|
286 </p> |
|
287 |
|
288 <p> |
|
289 |
|
290 Creating the textfield and form button is done as follows: |
|
291 </p> |
|
292 |
|
293 <pre> |
|
294 |
|
295 // add a text field to the view |
|
296 nameField = new TextField(null, "Enter your name"); |
|
297 mainView.addControl(nameField); |
|
298 |
|
299 // add a button to the view |
|
300 helloButton = new FormButton(null, "Say Hello!"); |
|
301 mainView.addControl(helloButton); |
|
302 </pre> |
|
303 |
|
304 <p> |
|
305 |
|
306 The first argument for both the textfield and button is the same as for the view: |
|
307 an optional unique identifier. We won't need it here either so rather than scratching |
|
308 our heads trying to come up with a unique identifier that we'll end up ignoring we'll |
|
309 just define it as null. The second argument for the textfield constructor is a caption. |
|
310 All controls except buttons have captions and this is the second argument in all |
|
311 constructors for controls with captions. The caption is displayed above the control |
|
312 and tells the user what the control does. In our case we want to have a textfield where |
|
313 the user should enter the name so we'll use "Enter your name" as the control caption. |
|
314 The second argument for the button constructor is the text for the button. The button |
|
315 text for form buttons should be a verb or other descriptive text that lets the user know |
|
316 what happens if the button is pressed. We'll put "Say Hello!" on our button. |
|
317 </p> |
|
318 |
|
319 <p> |
|
320 |
|
321 After we have created a control we can add it to a view. Custom views can have their |
|
322 own ways to do so but in the case of the default ListView that you'll use in most cases |
|
323 you add a control by calling the addControl() method. |
|
324 </p> |
|
325 |
|
326 <p> |
|
327 |
|
328 The user interface for the main view is now ready and we can show it. Showing a view |
|
329 is done by calling setView() in the user interface manager. So we'll add one more line |
|
330 of code to the end of the init() function: |
|
331 </p> |
|
332 |
|
333 <pre> |
|
334 |
|
335 // display the main view |
|
336 uiManager.setView(mainView); |
|
337 </pre> |
|
338 |
|
339 <p> |
|
340 |
|
341 If you zipped up the widget directory, renamed it HelloWorld.wgz and installed the |
|
342 widget on an emulator or handset, or just simply ran it in a PC web browser, you'd |
|
343 notice that the user interface seems to work. There's just one problem. Clicking on |
|
344 the button doesn't do anything! But don't worry, we're about to fix that. |
|
345 </p> |
|
346 |
|
347 </div> |
|
348 |
|
349 <div class="section"><h2 class="sectiontitle"> |
|
350 Handling events</h2> |
|
351 |
|
352 |
|
353 <p> |
|
354 |
|
355 The thing that is missing is that we have no way of knowing when the button was |
|
356 pressed. And without knowing when it's pressed we can't react to the press and |
|
357 show a greeting. A user interface action such as pressing a button is called an |
|
358 "event". In the WRTKit events are reported to "listener" functions that developers |
|
359 can register to controls. The way this is done is by creating a function that you |
|
360 want to get called when an event occurrs, and then calling addEventListener() on |
|
361 the control whose events you are interested in, passing the function to that method. |
|
362 However there are many types of events and you are almost surely not interested in |
|
363 all of them. Because of this you can specify the type of event that you want to get |
|
364 notified about by giving the event type name to the addEventListener() method. The |
|
365 event types and their names are described in the |
|
366 <a href="WRTKit_API_Reference-GUID-00e47c27-0a1a-443f-ae85-cf3381635170.html"> |
|
367 WRTKit API Reference</a> |
|
368 for each control. Note that because controls inherit from other classes they also |
|
369 inherit event types. |
|
370 </p> |
|
371 |
|
372 <p> |
|
373 |
|
374 The event type that we're interested in here is "ActionPerformed". That event is |
|
375 fired by form buttons whenever a user clicks on them. In order to get notified |
|
376 of this event we'll need two things: create a function that will get called when |
|
377 the event occurs and register that function as an event listener to our button. |
|
378 Let's create the function first but leave the implementation empty for now: |
|
379 </p> |
|
380 |
|
381 <pre> |
|
382 |
|
383 // Called when the hello-button is clicked. |
|
384 function helloButtonClicked(event) {} |
|
385 </pre> |
|
386 |
|
387 <p> |
|
388 |
|
389 Now that we have the event handler callback function we can add the event listener |
|
390 registration code. Let's put that right after where we create the button in |
|
391 the init() function: |
|
392 </p> |
|
393 |
|
394 <pre> |
|
395 |
|
396 helloButton.addEventListener("ActionPerformed", helloButtonClicked); |
|
397 </pre> |
|
398 |
|
399 <p> |
|
400 |
|
401 Now our helloButtonClicked() function will get called whenever the button is |
|
402 clicked. Notice that the function has an argument called event. This argument |
|
403 will receive an event object that describes the event that occurred. This can |
|
404 be useful if you have an event handler function that handles many different |
|
405 events. The event object contains three properties that you can examine to |
|
406 decide on what to do: a property called "source" that points back to the control |
|
407 or view from where the event was fired, a property called "type" that contains |
|
408 the event type name for this event, and a property called "value" that has |
|
409 helpful additional info that depends on the event type. You'll find more detailed |
|
410 information about this in the API Reference. |
|
411 </p> |
|
412 |
|
413 </div> |
|
414 |
|
415 <div class="section"><h2 class="sectiontitle"> |
|
416 Notification popup dialogs</h2> |
|
417 |
|
418 |
|
419 <p> |
|
420 |
|
421 All that remains now is to write the code that shows the greeting popup dialog |
|
422 when the button is pressed. This code will naturally go in the helloButtonClicked() |
|
423 function. |
|
424 </p> |
|
425 |
|
426 <p> |
|
427 |
|
428 Using notification popup dialogs is very easy with the WRTKit. The user interface |
|
429 manager has two methods: showNotification() and hideNotification() that are used |
|
430 to show and hide notification popup dialogs. The showNotification() method takes |
|
431 four arguments: displayTime, type, text and progress. The displayTime argument is |
|
432 used to supply a time (in milliseconds) for how long the notification popup should |
|
433 be shown for. We want our greeting to be visible for 3 seconds so we'll pass 3000 |
|
434 to this argument. The type argument is a string that tells the method what kind of |
|
435 popup to show, which determines the visual style of the popup. We'll be using two types: |
|
436 "info" and "warning". The "info" type for when we show the greeting and "warning" if |
|
437 the user didn't enter a name and we want to show a notification dialog that complains |
|
438 about this. The text argument is simply the text to show in the notification dialog. |
|
439 And finally the progess argument is a decimal number between 0.0 and 1.0 that is |
|
440 used in progress dialogs to display how far along a process is. |
|
441 </p> |
|
442 |
|
443 <p> |
|
444 |
|
445 A progress of 0.0 means "0% progress" and 1.0 means "100% progress". So for example |
|
446 if some process is 25% completed, you'd pass 0.25 to this argument. If you don't know |
|
447 how long a process will take you can pass a negative number. This will result in an |
|
448 animated progress bar that has a visual style that indicates that the progress is |
|
449 unknown. Typically you'd use the "wait" notification type is you want to show a |
|
450 progress dialog. If you don't want to show any progress information in the dialog, |
|
451 such as in our case, you can omit the progress argument or pass a null to it. |
|
452 </p> |
|
453 |
|
454 <p> |
|
455 |
|
456 Before we can write our code we need one more thing. We need to know what the user |
|
457 wrote in the name textfield. This value can be retrieved by calling the getText() |
|
458 method for the textfield. We're now ready to write the code for the helloButtonClicked() |
|
459 function: |
|
460 </p> |
|
461 |
|
462 <pre> |
|
463 |
|
464 var name = nameField.getText(); |
|
465 if (name.length == "") { |
|
466 uiManager.showNotification(3000, "warning", "Please enter your name!"); |
|
467 } else { |
|
468 uiManager.showNotification(3000, "info", "Hello " + name + "!"); |
|
469 } |
|
470 </pre> |
|
471 |
|
472 <div class="fignone" id="GUID-D638159A-D12B-476C-A74C-99055672B7BE__GUID-A2B73DB1-6494-4806-A11E-2E7F9BB1B3E7"><a name="GUID-D638159A-D12B-476C-A74C-99055672B7BE__GUID-A2B73DB1-6494-4806-A11E-2E7F9BB1B3E7"><!-- --></a><span class="figcap">Figure 1. |
|
473 The Hello World widget</span> |
|
474 |
|
475 |
|
476 <br /><img src="Hello_World_Screenshot_1.png" /><br /> |
|
477 </div> |
|
478 |
|
479 </div> |
|
480 |
|
481 <div class="section"><h2 class="sectiontitle"> |
|
482 Wrapping up</h2> |
|
483 |
|
484 |
|
485 <p> |
|
486 |
|
487 The Hello World widget is now done and you can zip it up, rename it to HelloWorld.wgz |
|
488 and deploy it on a handset or emulator. But before that, let's try it in a normal PC |
|
489 browser. Testing in a PC browser is useful because it allows you to use deubugging tools |
|
490 (like the Firebug JavaScript debugger for Firefox) in case something isn't working. Using |
|
491 a PC browser to test is also very fast because you don't have to install the widget to |
|
492 the emulator or handset. Just hit reload in the web browser when you make a change and |
|
493 you can see the results immediately. Of course there are features that will be missing |
|
494 in a web browser, such as that you won't have access to the Options menu or any other |
|
495 advanced widget functionality. But for the purpose of rapidly testing user interfaces |
|
496 it can be very helpful. |
|
497 </p> |
|
498 |
|
499 <p> |
|
500 |
|
501 There are a couple of points that are good to note now that the widget is ready. |
|
502 First of all, your widget now works with both the pointer and tab navigation modes. If |
|
503 you comment out the <samp class="codeph"> |
|
504 widget.setNavigationEnabled(false)</samp> call in the init() |
|
505 function you can try this out. Second, your widget works resolution independently. |
|
506 You can try this either by resizing the PC browser window or by trying the widget out |
|
507 with different resolutions in the S60 emulator. Third, the widget correctly handles |
|
508 screen rotations and other resizes, e.g. if the softkey bar is hidden / shown. Fourth, |
|
509 the widget looks can be customized without needing to touch any code - simply by changing |
|
510 the UI.css and image files that you can find in the WRTKit/Resources directory. |
|
511 </p> |
|
512 |
|
513 <p> |
|
514 |
|
515 But perhaps more important than any of the above is the fact that the WRTKit simplifies |
|
516 the separation of user interface code from data and logic code. That's not something |
|
517 that is apparent in a simple widget like this one, but it becomes very important as |
|
518 you create something more complex and especially if the user interface contains elements |
|
519 that are created dynamically for example based on data that has been fetched from the |
|
520 Internet using AJAX. |
|
521 </p> |
|
522 |
|
523 </div> |
|
524 |
|
525 </div> |
|
526 |
|
527 <div> |
|
528 <div class="familylinks"> |
|
529 <div class="parentlink"><strong>Parent topic:</strong> <a href="WRTKit_Hello_World_Tutorial-GUID-67e0a561-48ac-4938-8f1b-852422b71380.html">Hello World</a></div> |
|
530 </div> |
|
531 </div> |
|
532 |
|
533 </body> |
|
534 </html> |