org.symbian.tools.wrttools.doc.WRTKit/html/WRTKit_Creating_the_Hello_World_widget-GUID-d638159a-d12b-476c-a74c-99055672b7be.html
<?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">
<html lang="en" xml:lang="en">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<meta name="copyright" content="(C) Copyright 2005" />
<meta name="DC.rights.owner" content="(C) Copyright 2005" />
<meta content="concept" name="DC.Type" />
<meta name="DC.Title" content="Creating the Hello World widget" />
<meta scheme="URI" name="DC.Relation" content="WRTKit_Hello_World_Tutorial-GUID-67e0a561-48ac-4938-8f1b-852422b71380.html" />
<meta content="XHTML" name="DC.Format" />
<meta content="GUID-D638159A-D12B-476C-A74C-99055672B7BE" name="DC.Identifier" />
<meta content="en" name="DC.Language" />
<link href="commonltr.css" type="text/css" rel="stylesheet" />
<title>
Creating the Hello World widget</title>
</head>
<body id="GUID-D638159A-D12B-476C-A74C-99055672B7BE"><a name="GUID-D638159A-D12B-476C-A74C-99055672B7BE"><!-- --></a>
<h1 class="topictitle1">
Creating the Hello World widget</h1>
<div>
<div class="section"><h2 class="sectiontitle">
What goes in the widget?</h2>
<p>
One of the main reasons why Hello World is a good example to start with is
because it is a minimal widget and shows the minimal set of steps that you
would go through to create a widget that uses the WRTKit for its user interface.
We will create just two files, an HTML file called HelloWorld.html and a JavaScript
file called HelloWorld.js and both will be very short.
</p>
<p>
Before we'll start writing code let's talk about what exactly it is that we want
to build. A typical Hello World application simply displays the text Hello World
with the minimal amount of code. But because using the WRTKit is so simple, we'll
go one step further and make it a bit fancier.
</p>
<p>
WRTKit user interfaces are composed of views and controls. A view is one logical
group of stuff that you can see on the screen. A view can be longer than what fits
on the screen at once in which case the user has to scroll, but it's still one view.
For example in a web browser application you might have one view for the bookmarks,
another for settings and a third view for viewing actual web pages. Controls are
user interface elements like buttons, text fields, checkboxes, etc. that either
let the user perform some kind of interactive action or simply shows some information.
When you create a user interface with the WRTKit you create one or more controls,
one or more views, and place the controls on the views. After this, all you have to
do is ask one of the views to be displayed and the rest happens automatically.
</p>
<p>
Since this is a very simple widget we will just have one view and we'll call it
the "main view". Instead of just saying "Hello World" we will let the user input
their name and then click a button to popup a dialog that says hello to the user
by name. E.g. if the user enters "John" we will popup "Hello John!". But we will
also create some error handling so that if the user doesn't input a name we will
popup a warning dialog that says "Please enter your name!" instead.
</p>
</div>
<div class="section"><h2 class="sectiontitle">
The HelloWorld.html file</h2>
<p>
As mentioned earlier, you create user interfaces using JavaScript rather than
HTML when you use the WRTKit. Because of this it's perhaps not so surprising
that the HTML file is extremely short. What might come as a surprise however is
that it's extremely short and nearly identical no matter what kind of widget
you are building if you are using the WRTKit. In fact it typically only has
about 10 lines of code, including the DOCTYPE declaration! Here's what it looks
like:
</p>
<pre>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="WRTKit/WRTKit.js"></script>
<script type="text/javascript" src="HelloWorld.js"></script>
</head>
<body onload="init()">
</body>
</html>
</pre>
<p>
We're using XHTML 1.0 so the DOCTYPE declaration is for XHTML 1.0 Strict. And
because this is XHTML we also have the normal XML declaration (<?xml...).
After that the content should be familiar even if you've used previously only
used HTML rather than XHTML. We have a normal html root level tag with a head
and body. Note that in XHTML tags are case sensitive and should be in lowercase
as in the example above. The xmlns attribute is a name space declaration that
states that all the tags used here are part of the XHTML standard.
</p>
<p>
Because we're creating a widget and not a web page we don't need to have a title. If you
want you can define one here but you won't see it anywhere. Next comes an important
bit: <samp class="codeph">
<script type="text/javascript" src="WRTKit/WRTKit.js"></script>.</samp>
That piece of code instructs the Web Runtime to load a JavaScript file called WRTKit.js
from a directory called WRTKit. The WRTKit.js file takes care of loading the WRTKit and
including all the files that are needed by it. Those files are all inside the WRTKit
directory and you don't need to concern yourself with them at this point. In fact
all you need to do to use the WRTKit in a widget is to copy the WRTKit directory into
your own widget's root directory and then include the XHTML script tag presented above
that loads the WRTKit/WRTKit.js JavaScript file. If you are creating a widget of your own
you can find the WRTKit directory in the Library directory in the WRTKit SDK. But for your
convenience it has already been copied to the Hello World example.
</p>
<p>
Notice that there's another script tag too, this one loading a file called HelloWorld.js.
This is where we'll put all the JavaScript code that implements our Hello World widget.
We could have just written the JavaScript code inline between a <script> and
</script> tag in the HelloWorld.html file but the HTML file is less cluttered if
we move all JavaScript to a separate file.
</p>
<p>
Finally let's look at the body tag. There are two things of interest here. First of all
there's no content between <body> and </body>. That's because all of the
content will be created by the WRTKit using JavaScript. And that leads us to the other
point of interest in the body: the <samp class="codeph">
onload="init()"</samp> attribute of the
body tag. This sets up an event handler that gets called after the widget has loaded
all of its content. The event handler calls a JavaScript function called init(). This
is the point where we jump from the HTML to JavaScript. From this point on everything
will be JavaScript and the place where it all starts is the init() function that gets
called thanks to this little onload event handler for the body tag.
</p>
</div>
<div class="section"><h2 class="sectiontitle">
The HelloWorld.js file</h2>
<p>
The HTML file that we created above set things up so that there is a function call
to a function named "init()" when the widget is done loading. No such function exists
a this point so we have to create it. The init() function is the entry point to our
JavaScript and this is also where we will start the implementation.
</p>
<p>
The S60 Web Runtime supports two kinds of user interface interaction: tab and
pointer. The WRTKit supports but methods but usually the tab interaction method
(also known as "navigation mode") is preferred. Unfortunately the pointer based
navigation mode is the default so we'll have to disable it and switch to the tab
navigation mode. Also by default the softkey bar is hidden, which we don't want
because we want to give the user a clue about how to exit the widget. The good news
is that these two tweaks are easy to do and only requires two simple method calls.
The bad news is that those method calls are done through objects that only exist
in the Web Runtime but not in a PC web browser. Due to this, we'll create the
init() function as follows:
</p>
<pre>
// Called from the onload event handler to initialize the widget.
function init() {
// set tab-navigation mode and show softkeys
// (only if we are in the WRT environment)
if (window.widget) {
widget.setNavigationEnabled(false);
menu.showSoftkeys();
}
}
</pre>
<p>
We wrapped the calls to disable the pointer navigation and show the softkeys
in an if-clause that checks if there's such an object available as window.widget.
This will evaluate to false on a PC web browser but true in the S60 Web Runtime.
</p>
<p>
Now that we've tuned the Web Runtime to our liking we can create the actual
user interface. We'll create four things: the so-called "user interface manager"
that is in charge of managing views and other user interface resources, the main
view for the widget, a text field where users can enter their name, and finally
a button that they can click on to popup a notification dialog that says "Hello"
Notice that we don't have to create the notification dialog because this is done
for us by the user interface manager.
</p>
<p>
Before we create those four objects we will declare four global variables so that
we can access those objects elsewhere in the widget. So let's add the following
to the top of the file (outside the init() function):
</p>
<pre>
// References to the WRTKit user interface manager and main view.
var uiManager;
var mainView;
// References to controls in the main view.
var helloButton;
var nameField;
</pre>
<p>
Now that we have some variables that can track the objects we are about to create
we can actually craete those objects. We'll create the objects inside the init()
function so that the user interface gets created right after the widget has loaded.
</p>
<p>
The first thing we create is the user interface manager. This is quite simple and
requires only a single line of code:
</p>
<pre>
// create UI manager
uiManager = new UIManager();
</pre>
<p>
Next we'll create the main view. The WRTKit allows all kinds of views to be created
if one has special needs for how user interface controls should be laid out. However
in the vast majority of cases the ListView class will be sufficient and that's what
we'll create this time too:
</p>
<pre>
// create main view
mainView = new ListView(null, "Hello World");
</pre>
<p>
The first argument to the ListView constructor is a unique identifier for the view.
All user interface elements in the WRTKit can have a unique identifier. The identifier
is helpful if you want to specifically target a view or control with some CSS style
rule or if you want to identify the source of an event in an event listener callback,
etc. However we don't need it here so we don't bother giving our main view a unique
id and just pass a null identifier value instead. The second argument is a caption for
the view. We'll just call our view "Hello World". The caption will be displayed at the
very top of the screen when we display the main view. But before we do that, let's
create the rest of the user interface.
</p>
<p>
The widget should have a text field to let users enter their name and a button to
trigger the greeting popup. Both the text field and the button are WRTKit controls
and will be created and added to the main view that we just created. There are two
kinds of buttons in the WRTKit though, form buttons and navigation buttons. Form
buttons are meant to trigger actions whereas navigation buttons are meant for
situations where clicking it would result in moving from one view to another. Clearly
therefore, we want a form button in this case.
</p>
<p>
Creating the textfield and form button is done as follows:
</p>
<pre>
// add a text field to the view
nameField = new TextField(null, "Enter your name");
mainView.addControl(nameField);
// add a button to the view
helloButton = new FormButton(null, "Say Hello!");
mainView.addControl(helloButton);
</pre>
<p>
The first argument for both the textfield and button is the same as for the view:
an optional unique identifier. We won't need it here either so rather than scratching
our heads trying to come up with a unique identifier that we'll end up ignoring we'll
just define it as null. The second argument for the textfield constructor is a caption.
All controls except buttons have captions and this is the second argument in all
constructors for controls with captions. The caption is displayed above the control
and tells the user what the control does. In our case we want to have a textfield where
the user should enter the name so we'll use "Enter your name" as the control caption.
The second argument for the button constructor is the text for the button. The button
text for form buttons should be a verb or other descriptive text that lets the user know
what happens if the button is pressed. We'll put "Say Hello!" on our button.
</p>
<p>
After we have created a control we can add it to a view. Custom views can have their
own ways to do so but in the case of the default ListView that you'll use in most cases
you add a control by calling the addControl() method.
</p>
<p>
The user interface for the main view is now ready and we can show it. Showing a view
is done by calling setView() in the user interface manager. So we'll add one more line
of code to the end of the init() function:
</p>
<pre>
// display the main view
uiManager.setView(mainView);
</pre>
<p>
If you zipped up the widget directory, renamed it HelloWorld.wgz and installed the
widget on an emulator or handset, or just simply ran it in a PC web browser, you'd
notice that the user interface seems to work. There's just one problem. Clicking on
the button doesn't do anything! But don't worry, we're about to fix that.
</p>
</div>
<div class="section"><h2 class="sectiontitle">
Handling events</h2>
<p>
The thing that is missing is that we have no way of knowing when the button was
pressed. And without knowing when it's pressed we can't react to the press and
show a greeting. A user interface action such as pressing a button is called an
"event". In the WRTKit events are reported to "listener" functions that developers
can register to controls. The way this is done is by creating a function that you
want to get called when an event occurrs, and then calling addEventListener() on
the control whose events you are interested in, passing the function to that method.
However there are many types of events and you are almost surely not interested in
all of them. Because of this you can specify the type of event that you want to get
notified about by giving the event type name to the addEventListener() method. The
event types and their names are described in the
<a href="WRTKit_API_Reference-GUID-00e47c27-0a1a-443f-ae85-cf3381635170.html">
WRTKit API Reference</a>
for each control. Note that because controls inherit from other classes they also
inherit event types.
</p>
<p>
The event type that we're interested in here is "ActionPerformed". That event is
fired by form buttons whenever a user clicks on them. In order to get notified
of this event we'll need two things: create a function that will get called when
the event occurs and register that function as an event listener to our button.
Let's create the function first but leave the implementation empty for now:
</p>
<pre>
// Called when the hello-button is clicked.
function helloButtonClicked(event) {}
</pre>
<p>
Now that we have the event handler callback function we can add the event listener
registration code. Let's put that right after where we create the button in
the init() function:
</p>
<pre>
helloButton.addEventListener("ActionPerformed", helloButtonClicked);
</pre>
<p>
Now our helloButtonClicked() function will get called whenever the button is
clicked. Notice that the function has an argument called event. This argument
will receive an event object that describes the event that occurred. This can
be useful if you have an event handler function that handles many different
events. The event object contains three properties that you can examine to
decide on what to do: a property called "source" that points back to the control
or view from where the event was fired, a property called "type" that contains
the event type name for this event, and a property called "value" that has
helpful additional info that depends on the event type. You'll find more detailed
information about this in the API Reference.
</p>
</div>
<div class="section"><h2 class="sectiontitle">
Notification popup dialogs</h2>
<p>
All that remains now is to write the code that shows the greeting popup dialog
when the button is pressed. This code will naturally go in the helloButtonClicked()
function.
</p>
<p>
Using notification popup dialogs is very easy with the WRTKit. The user interface
manager has two methods: showNotification() and hideNotification() that are used
to show and hide notification popup dialogs. The showNotification() method takes
four arguments: displayTime, type, text and progress. The displayTime argument is
used to supply a time (in milliseconds) for how long the notification popup should
be shown for. We want our greeting to be visible for 3 seconds so we'll pass 3000
to this argument. The type argument is a string that tells the method what kind of
popup to show, which determines the visual style of the popup. We'll be using two types:
"info" and "warning". The "info" type for when we show the greeting and "warning" if
the user didn't enter a name and we want to show a notification dialog that complains
about this. The text argument is simply the text to show in the notification dialog.
And finally the progess argument is a decimal number between 0.0 and 1.0 that is
used in progress dialogs to display how far along a process is.
</p>
<p>
A progress of 0.0 means "0% progress" and 1.0 means "100% progress". So for example
if some process is 25% completed, you'd pass 0.25 to this argument. If you don't know
how long a process will take you can pass a negative number. This will result in an
animated progress bar that has a visual style that indicates that the progress is
unknown. Typically you'd use the "wait" notification type is you want to show a
progress dialog. If you don't want to show any progress information in the dialog,
such as in our case, you can omit the progress argument or pass a null to it.
</p>
<p>
Before we can write our code we need one more thing. We need to know what the user
wrote in the name textfield. This value can be retrieved by calling the getText()
method for the textfield. We're now ready to write the code for the helloButtonClicked()
function:
</p>
<pre>
var name = nameField.getText();
if (name.length == "") {
uiManager.showNotification(3000, "warning", "Please enter your name!");
} else {
uiManager.showNotification(3000, "info", "Hello " + name + "!");
}
</pre>
<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.
The Hello World widget</span>
<br /><img src="Hello_World_Screenshot_1.png" /><br />
</div>
</div>
<div class="section"><h2 class="sectiontitle">
Wrapping up</h2>
<p>
The Hello World widget is now done and you can zip it up, rename it to HelloWorld.wgz
and deploy it on a handset or emulator. But before that, let's try it in a normal PC
browser. Testing in a PC browser is useful because it allows you to use deubugging tools
(like the Firebug JavaScript debugger for Firefox) in case something isn't working. Using
a PC browser to test is also very fast because you don't have to install the widget to
the emulator or handset. Just hit reload in the web browser when you make a change and
you can see the results immediately. Of course there are features that will be missing
in a web browser, such as that you won't have access to the Options menu or any other
advanced widget functionality. But for the purpose of rapidly testing user interfaces
it can be very helpful.
</p>
<p>
There are a couple of points that are good to note now that the widget is ready.
First of all, your widget now works with both the pointer and tab navigation modes. If
you comment out the <samp class="codeph">
widget.setNavigationEnabled(false)</samp> call in the init()
function you can try this out. Second, your widget works resolution independently.
You can try this either by resizing the PC browser window or by trying the widget out
with different resolutions in the S60 emulator. Third, the widget correctly handles
screen rotations and other resizes, e.g. if the softkey bar is hidden / shown. Fourth,
the widget looks can be customized without needing to touch any code - simply by changing
the UI.css and image files that you can find in the WRTKit/Resources directory.
</p>
<p>
But perhaps more important than any of the above is the fact that the WRTKit simplifies
the separation of user interface code from data and logic code. That's not something
that is apparent in a simple widget like this one, but it becomes very important as
you create something more complex and especially if the user interface contains elements
that are created dynamically for example based on data that has been fetched from the
Internet using AJAX.
</p>
</div>
</div>
<div>
<div class="familylinks">
<div class="parentlink"><strong>Parent topic:</strong> <a href="WRTKit_Hello_World_Tutorial-GUID-67e0a561-48ac-4938-8f1b-852422b71380.html">Hello World</a></div>
</div>
</div>
</body>
</html>