An application for Series 60 - a step-by-step example
1 juill. 2004 - 08:11

This tutorial will demonstrate the basic programming concepts of the Series 60 SDK by showing step after step how to write a Tetris game for the Series 60.

Step 1 - a Hello World application

step1.zip
step1.zip
Step1.sis
Step1.sis

The first program is generaly the Hello World application from the SDK examples. The SIS file can be installed on the phone, while the ZIP file contains the source code tree.

In the group\ directory you will find the project files. These are bld.inf and S60Test.mmp. abld.bat is generated by bldmake. A descrption of the comilation process can be found here. An overview of the compilation system can be found here. The directory contains also the Borland C++Builder project files (Project_Sources.* and S60Test_Sources.*).

The group\step1.rss is the resources file. In our example it contains the softkeys configuration (R_AVKON_SOFTKEYS_OPTIONS_EXIT - an Options button on the left and Exit on the right) and the Options menu. More resources will be added later.

The group\step1.pkg file contains the description how to build the *.SIS file - the file that can be installed on the phone.

The inc\ and src\ contains the source code of the program. The Hello World example is described in the SDK documentation. I will give a brief description of the code below.

Unlike application for Windows or Unix, application for Symbian OS don't have a main() function with the main loop inside, but are loaded by the framework as a DLL. Like every DLL it has a E32Dll function, but it should return quickly.

The framework will call the NewApplication() function to get a CApaApplication object. An application for Avkon (for Series 60) will return an object of a type subclassed from CAknApplication. In our example this is CS60TestApplication implemented in s60testapplication.cpp. Two functions should be overwritten in an implementation. The first is AppDllUid which return the UID of the application (each application has a unique UID. Note that our examples uses development UIDs, so they should not appear in release software).

The second function is the CreateDocumentL which creates a object of type CApaDocument. In our example it is a CS60TestDocument which is a subclass of CAknDocument. One function needs to be overwritten in this class - the CreateAppUiL which creates the object responsible for the application User Interface.

In our example it is done by the class CS60TestAppUi. In the ConstructL function we first call the BaseConstructL function which does some initialisation of the object, like loading the softkeys/menu configuration from the resources. Then we create an object of class CS60TestAppView which is a subclass of CCoeControl. The CCoeControl object are control which are drawn on the screen. Our control will fill the ClientRect() i.e. the space between the status pane and the softkeys description. Changing that to ApplicationRect() would create a fullscreen application. The call AddToStackL will make the view recieve keyboard event.

The AppUi object also recieves the events from the menu. When the user chooses a menu command, the HandleCommandL is called with the command code (the codes are defined in the definition of the menu in the resources file). We implement the 'Exit' command and 'Hello' command which displays a note.

In the CS60TestAppView class we overwrite only one function - the Draw method which is called when the view needs to be redrawn. In our implementation we write the size of the ClientRect (176x144) on the screen. To build the string we use the TBuf class. The Symbian string classes which are described here.

Step 2 - adding the data structures

step2.zip
step2.zip
Step2.sis
Step2.sis
step2.diff.txt
step2.diff.txt

In the second step we will add data structures needed by our Tetris game. You can see in the differences file what is added.

We use two classes TBlock and TGrid. These classes has no pointer to owned data, so these are T classes (for the classes types see here). The TBlock represents a single Tetris block (a shape built of four bricks). The TGrid represents the grid (20x10 bricks) with the bricks which are already fixed. The Document class has now the iGrid field which contains the board and the iCurrBlock which contains the block which is currently falling. The iBlockPos field is the position of the falling block.

The code added in this example is mainly bit manipulations. The only Symbian OS specific part is the use of the TFixedArray classes. These template classes are accessed like normal arrays, but internally they do range checking - e.g. if in a TFixedArray<T, 10> you will write to the index 20 there will be no random memory corruption but an error will be raised.

We also changed the menu under the Options softkey to what we will want to have in the final version.

Step 3 - adding a user interface

step3.zip
step3.zip
Step3.sis
Step3.sis
step3.diff.txt
step3.diff.txt

In this step we add a user interface which will allow us to test the data structures. By the use of the arrow keys the user can place the block where he wants and with the OK fix it (note: at the beginning each block is above the top of the board. You have to press the down key several times to see it). The user can also rotate the block.

First in the CS60TestAppView::Draw we draw the board. We use the methods of TGrid to obtains the types of blocks and use DrawLine and DrawRect to draw the board. To control the color we use SetPenColor (the color of the lines and the outline of the rectangles) and SetBurushStyle/SetBurshColor (the color of the rectangle's interior). A description of all the methods of CWindowGc can be found in the SDK help.

We also want to react when the user presses a key. Each key press generates a key event. This event is first sent to CS60TestAppView, as it was added to the top of the stack by AddToStackL. The default implementation return EKeyWasNotConsumed, so the framework will send this event to the next object on the stack - the CS60TestAppUi. In that class we intercept the event in HandleKeyEventL and do the appropriate task.

Note that after making a change to the grid, the view must be redrawn to show that change. We redraw the whole screen with DrawDeferred in CS60TestAppUi::UpdateBoard.

A good implementation would return EKeyWasConsumed to every key it used. My implementation always return EKeyWasNotConsumed what send the key event to the framework. The framwork reacts to some keys like the softkeys but is not interested in the keys we are using, so it will not make a difference.

The last change is the implementation of the 'New Game' option in the menu.

Step 4 - adding the engine

step4.zip
step4.zip
Step4.sis
Step4.sis
step4.diff.txt
step4.diff.txt

The previous program is not yet an interesting game. The user can place the block everywhere he wants, what becomes quite boring. In this step we will add an engine which will lower the block after every time interval.

The engine class is the CS60TestEngine. It is a subclass of CTimer. This class is used to suspend the engine for some time - we call After(iInterval) and after at least iInterval microseconds the system will run the CS60TestEngine::RunL function. If we would use a delay loop instead of CTimer, we would block the main thread and we would not recieve key events, the menu would not show etc.

The CTimer is an active object, so we need to call CActiveScheduler::Add(this) to add it to the scheduler queue.

When the user resets the game and a request has been issued, we cancel it with Cancel and issue a new one with a fresh time interval.

In the RunL we lower the block by one line. If it cannot be lowered then we try to fix it and create a new block. If the block cannot be fixed, it's because it is above the screen and the game is over. We display o note and stop the engine (the iState variable).

One thing to note is that we load the "Game over" string from the resources file. This allows an easy translation of the application to a diffrent language - we need only to translate the resources file. The string is a TBUF record added to the s60test.rss file. The record is called r_note_game_over. The build process will create a s60test.rsg file which is a C++ include file. In this file R_NOTE_GAME_OVER will be defined as the ID of our resource. We load it with CEikonEnv::Static()->ReadResource(message, R_NOTE_GAME_OVER);

Step 5 - polishing the game

step5.zip
step5.zip
Step5.sis
Step5.sis
step5.diff.txt
step5.diff.txt

We have already a game. However it can be improved in many ways.

The first problem is that when the user switches to another application or opens the menu, the game still goes on and when the user will be back the game will be probably over. To avoid it we implement pausing the engine.

There are to function to pause - Pause/Unpause will pause the game at a user request. This will also change the Options menu as you will see below. The TechPause/TechUnpause are called when the user switches the application or open the menu - they do not change the menu. Both of these functions uses reference counting - e.g. after calling twice TechPause you need to call twice TechUnpause to unpause the game. It is not used in this program - that's a remaining of an older version.

The pausing and unpausing itself if done in DoPause. To pause we save the time to be able to compute how much from that time-slice is used and cancel the timer request. To unpause we compute the remaining time and issue a timer request for that time.

We call TechPause/TechUnpause in CS60TestAppView::FocusChanged. As the name suggests that function is called when the view looses focus (e.g. the users open the menu or switches the application) or gains it again. The Pause/Unpause is called in CS60TestAppUi::HandleCommandL - this command is chosen by the user from the Options menu.

When the user chooses the 'Pause' command from the menu, we would like the option name to change to 'Unpause'. That can be implemented in CS60TestAppUi::DynInitMenuPaneL which is called every time before the menu is shown. We check the state if the engine is paused by the user and set the appropriate string from the resources.

We will also add a bitmap for the background. It is based on a bitmap I've found somewhere in the Internet.

The bitmaps are stored by Symbian OS applications as *.mbm files - the Multi BitMap files. They are created from *.bmp files in the build process - we add a START BITMAP block in the *.mmp. One *.mmp can contain several *.bmp file.

In our example we will create the s60test.mbm file which will contain one bitmap - the tlo.bmp. The c12 before the bitmap name means that the color should be represented by 12 bits (4,096 colors) to use less space. If you want to have a 65,536 color bitmap change it to c16. The build tools will create also another file - s60test.mbg. This is an include file with the IDs of the bitmaps in our *.mbm file. In our example we have one bitmap which ID will be called EMbmS60testTlo. We load the bitmap with CEikonEnv::Static()->CreateBitmapL(iPathName, EMbmS60testTlo). Note that we provide the path (\System\Apps\Step5\S60Test.mbm) without the drive letter - the bitmap will be loaded from the drive where the application is installed and will work from both the memory as well as the MMC.

You can read more about bitmaps here.

To draw the bitmap we use the DrawBitmap function. We also show the points and the level to the user - these are simple text drawing function as used in step 1/2.

Step 6 - adding the AIF file

step6.zip
step6.zip
Step6.sis
Step6.sis
step6.diff.txt
step6.diff.txt

Out program needs two more thing - a nice icon and a nice name. Both these goals can be achieved by creating an AIF (Application Information File).

The main part is a resource file with a AIF_DATA record. It is defined in S60TestAif.rss file. Here we can define the application name that will be shown in the Application Launcher.

Apart from this file we also need to include four bitmaps - a 44x44 bitmap, a 44x44 mask (i.e. you mark with white the pixels that should be transparent and with black the ones that should be not), a 42x23 bitmap and a 42x23 mask. The bitmaps are in diffrent colors so it's easy to check when each one is used. The AIF file should be referenced from the *.mmp file with the AIF command. That will build the step6.aif file which will be installed in the application directory.

Tutorial posted juillet 1st, 2004 by mikolaj

Soumis par Anonymous le jeu, 2004-08-19 17:08.

Thank you much for your tutorial man! Really appreciated!

Soumis par cofd (non vérifié) le ven, 2005-08-12 19:01.

nice ^_^, thanks!Really appreciated!

Soumis par Anonymous le mer, 2006-01-25 18:34.

Its seems really really helpfull to understand the symbian OS internals , but i find difficulties at some place as i am nota pro C progmr. Can any one give me some links from where i can sort out my doubts. (Like NewL(), NewLC(), many more)

Thanks


Soumis par mikolajz (non vérifié) le mer, 2006-01-25 18:55.

What you have written is not C but Symbian OS C++ conventions. I've also written a tutorial about that. You can find it here.

Soumis par Fengle (non vérifié) le mer, 2004-12-01 14:14.

I can not find "step6.rsg" in the "src" directory.How to get it,Sir?

Soumis par mikolajz (non vérifié) le mer, 2004-12-01 14:34.

Teh step6.rsg file will be generated from the step6.rss file by the resource compiler. After a successful compilation it will be created in %EPOCROOT%\epoc32\include

Soumis par Anonymous le sam, 2004-12-18 16:11.

how do you compile it?

Soumis par Anonymous le sam, 2004-12-18 19:48.

To compile a Symbian program you need a Symbian SDK and a Win32 compiler. If you have it you can compile from the command line by "bldmake bldfiles" and "abld build wins" (winscw for CoreWarrior).

Symbian programs can also be compiled in Visual Studio (ABLD can create a VS project file but I don't remember with which command), CodeWarrior, Borland C++BuilderX (there is also a Series 60 v1.2 SDK for C++Builder 6 but not for newer versions) or Eclipse.

A description on how to install/setup Eclipse with Symbian support can be found here


Soumis par Anonymous le dim, 2004-12-19 14:50.

I've compiled everything and it appears in the emulator -the series 60 SDK (I named it tetris) but when I open it, its just an empty screen with "add your text here". I want to see if it will run or not on the emulator. How do I get it to run on the emulator? Will I need to install the .sis?

Soumis par Anonymous le mar, 2004-12-21 00:42.

I don't know what's the 'add your text here'. It looks like a different application. Maybe a template created by some kind of New Project wizard or an example...

The build of Step 6 should result in step6.app, step6.aif, step6.rsg and step6.mbm being created. These files should go to %EPOCROOT%\epoc32\release\wins\urel\z\system\Apps\STEP6 (there could be udeb instead of urel). I've never used Visual Studio for Symbian programming but I expect this is where it puts them. Now the emulator should detect the application - start the emulator e.g. from the start menu (the Debug version if the files are in UDEB or the Release if they are in UREL). It should be called Tetris and have a Tetris block as an icon as this is how it is defined in the AIF file.

One reason why it may fail that comes to my mind is if you created an applicaiton with the same UID (Step 6 uses an experimental UID of 0x04545FF6). If there are two applications with the same UID the emulator will show only one of them.

The SIS file contains the program compiled for the device and should not be installed in the emulator.


Soumis par Anonymous le mar, 2004-12-21 23:32.

Tried using a completely new UID but came up with the same message "Example view" and at bottom of emulator screen: "add your controls here." Tried compiling an example application from the series 60 SDK directories. Same thing. Default appplication icon appears. Any more suggestions or is this THE END of the line?

Soumis par mikolajz (non vérifié) le lun, 2005-01-10 23:37.

As you see the problem lays in a wrong usage of the IDE not in my examples - the compilation of the helloworld gave the same result. I have no idea why it failed without some more details (e.g. were the four files I mentioned in the previous message created). I could try to help you if you would contact me by clicking the authors name and give an e-mail address I could reply to. You could also try to use the NewLC forums where there are more people to reply so you could probably get the response quicker.

PS: Here are some screenshots of the application:

Step 1

Step 2 - the same

Step 3

Step 4 - the same (now the block falls automatically)

Step 5

Step 6 - the same (except for the "Tetris" title)


Soumis par mikolaj le sam, 2008-11-15 21:25.

These links may stop working in near future. Links that should work are:

Step 1
Step 3
Step 5


Soumis par Anonymous le ven, 2005-07-08 11:41.

nice tutorial. =)

Soumis par Neeraj (non vérifié) le ven, 2005-07-29 07:52.

The tutorial is really informative. Thank You.


copyright 2003-2009 NewLC SARL