Category: PyS60


In the last post, the topic of discussion was about basic UI controls that PyS60 provides. These controls are useful when the solution to be developed is simple in terms of interaction. However, if a scenario presents itself where interaction becomes complex, then the basic controls would not suffice. For such situations, advanced controls need to be used that can abstract out the complexities of the interaction to the user as well as provide simple and consistent interface for the developer to work with. PyS60 has many such controls that a developer can use. In this discussion, the focus will be on three of the most commonly used controls – selection list, multi-selection list and text. The first section would focus on the whys and wherefores of these controls. In the last section, the application developed in the previous part will be enhanced using the controls being discussed in this section. That is the agenda for this discussion.

Lists and Text Controls – Whys and Wherefores

There are times when providing a list of choices is a better option than asking the user to enter data in an entry box. In such circumstances, providing a list of choices is a better option. To provide lists, PyS60 has two UI controls

1. Selection List

2. Multi-selection List

The former is a good choice when only one item needs to be chosen whereas when several items need to be chosen then the later is the control of choice. Here are the details.

1. Selection List:

As the name suggests, it displays a list to the user from which he or she can choose. The selection list provided by PyS60 also contains a search field that helps the user to narrow down the choices. It is displayed to the user using a function called selection_list(). It comes under the category of dialogs wrapped in functions. It takes two arguments:

a. choices

b. search_field

The latter is an optional argument.

a. choices:

It is a list of Unicode strings containing the options to be displayed to the user.

b. search_field:

It accepts a ‘0’ or ‘1’ as the value. The value decides whether the search field will be  shown or not. If the value is ‘1’, the search field is shown. The default value is ‘0’ i.e. the search field is off by default. If enabled, the search field is shown after the first key press occurs.

The value returned by the selection_list() function is the index of the selected item. For example, to show a list with ‘egg’, ‘spam’ and ‘butter’ to choose from without any search field, the statements will be

list = [u”egg”, u”spam”, u”butter”]

selection_list(list)

2. Multi-selection List:

There are cases where a single selection is not a solution. This is where multi-selection list comes handy. Like selection list, multi-selection list is also a function that wraps up a dialog and displays the dialog when it is executed. The function that brings up a Multi-selection List is multi_selection_list(). It accepts the following arguments

a. choices

b. style

c. search_field

The first and third are similar to the selection_list() arguments. The second argument is unique to multi_selection_list(). Here are the details

a. choices:

Just as in the case of selection_list, the value accepted by this argument is a list of Unicode strings.

b. style:

This is optional. The value of this parameter decides how the list will be displayed. There are two valid values for the style parameter:

i. checkbox – It is the default value. If ‘checkbox’ is given as the value of the
style, the list presented to the user will be a list containing a
checkbox against each list item. Empty checkboxes indicate
selectable item.

ii. checkmark – It is the other acceptable value for the style argument. If
‘checkmark’ is used as the value, then the list presented to
the user doesn’t have a visual clue as to which item to be
selected. However, once selected, a checkmark will appear
against that item.

c. search_field:

This argument does the same thing that search_field does for selection_list()
function. If value of 1 is passed, the search field is displayed and if value of 0 is
given, the search field is not displayed.

The value returned by the function is tuple containing selected values. If no values are selected, then an empty tuple is returned. For example, the following statements display a list from which multiple items can be selected having the checkmark style, having a search field and the returned values are displayed.

list = [u”egg”, u”spam”, u”butter”]

result = multi_selection_list(list, ‘checkmark’, 1)

print result

Next, let us move onto the control that provides the text editor functionalities.

Text:

It provides text editor with almost all the text formatting functionalities. The control is provided by Text type. Unlike selection or multi-selection list, text is a type. The functionalities provided by text type are categorized under the following:

a. Attributes

b. Methods

Since the text is a type the functionalities are exposed either as a attribute or a method. Here are the details

a. Attributes

Following are the most commonly used attributes of Text:

i. color:

It defines the color of the text. The valid values are all the colors supported by
graphic models in graphics module.

ii. font:

This attribute determines the font family of the text. It can be set using the
supported Unicode name.

iii. style:

It affects the style of the text. The valid values for this attribute are defined as
flags. The valid flags are provided by appuifw module. Some of the commonly
used flags are

  • STYLE_BOLD – Makes the text bold
  • STYLE_UNDERLINE – Underlines a displayed text
  • STYLE_ITALIC – Makes the text italic

For example, to use a Text type with LatinPlain12  as font’ value with bold text, the statements will be

t = appuifw.Text()

t.font = u”LatinPlain12″ # sets font to Latin Plain 12

t.style = appuifw.STYLE_BOLD

b. Methods

Text type provides various methods to perform common operations on the text
held by the editor. The most common methods are:

i. add() : It accepts Unicode string as argument. This method appends a text to
the existing text. It can also be used to insert the
passed argument at current cursor position.

ii. set() : Just like add() method, tt accepts Unicode string as argument. It sets
the passed Unicode string as argument. It replaces any text that
may be present in the editor.

iii. delete() : It accepts two arguments – position and length and deletes length of
characters in the editor starting from the position passed as
argument.

For example, to set a string having value as “This is a text” as the text in the editor, the statement is

t.set(u”This is a text”)

This brings us to the end of this section. In the next section, the guessing game application that was developed in last part will be enhanced using single selection list.

PyS60 in Real World:

In the last discussion, a guessing game was developed. The code was as follows

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

user_choice=query(u”Enter Y to continue or N to quit”)

if user_choice is Null or user_choice==’N’:

continue_guess=false

else:

continue_guess=true

Now, let us change the display part for displaying the choices. Instead of taking user’s input using a query dialog, let us show a selection list from which the user can select a value. The following code

user_guess=query(u”Enter your guess”, ‘number’)

needs to be changed to

list = [guess-100, guess, guess*200, u”Quit”]

user_guess = selection_list(list)

first, a list is created using the guess no. and its combination. Then the list is given as an argument to selection_list() method. The returned index, which is the value selected by the user, is then stored in the user_guess variable.

Next, let us change how the result is processed. To do so, the following code

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

to the following

if  guess_no < list [user_guess]:

note(u”Your guess is lesser than the goal”)

elif guess_no < list [user_guess]:

note(u”Your guess is higher than the goal”)

elif guess_no == list [user_guess]:

note(u”Congrats for excellent guess”)

else:

note(“Bye”)

continue_guess = false

The index returned by the selection_list() is used by the if condition to get the value selected by the user, from the list. If the index corresponds to the value lesser or greater than the goal value, then a note is displayed telling the user that he/she is either short of the goal or overshot the goal. Otherwise, user is congratulated. If user selected the option to quit, the continue_guess is set to false, thus ending ‘the game’. The complete code is as follows

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

list = [guess-100, guess, guess*200, u”Quit”]

user_guess = selection_list(list)

if  guess_no < list [user_guess]:

note(u”Your guess is lesser than the goal”)

elif guess_no < list [user_guess]:

note(u”Your guess is higher than the goal”)

elif guess_no == list [user_guess]:

note(u”Congrats for excellent guess”)

else:

note(“Bye”)

continue_guess = false

That completes our application. This discussion focused on the UI controls. From the next discussion, the focus will be moving towards the third party libraries in PyS60. However, the next discussion will focus primarily on graphics module. Till then…

GUI changed the way a program communicates with the user. It made applications interactive. Interactivity is the norm of the day. Mobiles are no exceptions. PyS60 makes creating GUI based applications easy. It can be termed as on of the RAD environment for Symbian OS. In this discussion I will focus on the basics of using UI library provided by PyS60. The first section will focus on the types of the controls. The second section will be about three basic controls – note and query. In the third section, a simple application will be developed that uses the controls discussed in second section. That’s the agenda for this discussion.

Types of Controls:

PyS60 provides controls or widgets (including dialogs) in two forms. They are:

1. Functions

2. Python types

Controls or widgets under the former mostly are methods where as those in latter category are Python objects implemented in C. Here are the details.

1. Functions:

Many of the dialogs are implemented as functions. In PyS60, dialogs take precedence over the other controls such as textboxes, list-boxes etc. This means if a control and a dialog needs to be shown, then dialog will be shown on top of the control, thus hiding the control. The examples of dialogs implemented as functions are note, query, multi_query etc.

2. Python types

The controls such as textboxes are implemented in C and directly accessed in PyS60. Their precedence is lower than UI implemented as Functions. Text, Listbox and Canvas are examples of Python types. These controls are displayed the instant they are set as the part of the application’s body. In other words, these controls are not displayed until they have been registered as the part of the application.

One of the controls is a dialog that has been implemented as a Python type. It is the Form control. That completes the discussion about the types of UI controls lets move onto next section.

UI Controls – Entry and Notes:

Query and Notes controls are the most commonly used of all the controls. They are used to take input and display messages. Here are the details:

1. Query:

Query is a dialog type. It is used to gather input from the user. It presents a single line text box with a label to the user. Since query is a dialog, so it is implemented as a function. There are three parameters to the function. They are:

i. label

ii. type

iii. initial value

The first two are mandatory parameters whereas the third is optional. Here are the details

i. label

It is the question or prompt that is shown to the user when the dialog box is displayed. The value for this argument is an Unicode string. For example, to show the “Enter name” as the prompt, one will use the following as the value of the argument:

U”Enter name”

ii. type

One can compare it with standard input dialog box that is common on PC. Since it is a dialog, it can be of different dialog types. The type is decided by the type parameter of the query function. The different types are:

a. text – it is a simple text. The text is of Unicode type.

b. code -

c. number – in this case, the input box will accept only numbers and not

decimals

d. date – the input is just date

e. time – to take time as input type needs to be set to time.

f. float – to accept only decimals, this type can be used

All these values are string type. For example to set the type to number, the value passed will be

‘number’

iii. initial value

This is an optional parameter. It sets the initial value shown to the user. However, for the type float, setting this value does not have any effect. For text fields i.e. type having value either ‘text’ or ‘code’, the value for this argument is Unicode. If the type is ‘number’, the value that can be passes is numeric values only. If the type is date, then initial value will be seconds since epoch rounded to the nearest local midnight. For example, to set the initial value to 3, the value passed will be

3

The return value of query is the value provided by the user and the type of the input box. Therefore, to display a query with “Enter any number between 1 and 9” as message, with number as the only acceptable data and 0 as initial value, the statement will be

guess=query(u“Enter any number between 1 and 9”, ‘number’,0)

2. note

note is another control implemented as a dialog. It is used to display messages to the user. This is, again, one of the most common controls in the toolkit of PyS60 as it can be used to display different messages. These messages can be anything from simple message such as information about the size of current file or critical messages such as low battery. The note function takes three arguments. They are

a. text

b. type

c. global

Of these, only text is mandatory argument. The other two are optional. Here are the details.

a. text

It is the message to be shown. It is a Unicode string. For example, to show a message stating that the memory is full, the text argument will be of following format

u”Memory is full”

The u at the starting indicates that it is a Unicode text.

b. type

As stated earlier, the note function can be used to display different kinds of messages. The kind of the message is determined by the value passed for ‘type’ parameter. This parameter can accept the following string values:

i. info – it is the default value, if no value is passed. When type is set to info,

the message shown will be of simple kind. Hence, the icon will have

‘i’ as symbol.

ii. error – to show error messages, one can use this string as the value. If the

type is set to ‘error’, the icon will have ‘e’ as the symbol.

iii. conf – set the type to ‘conf’ when the message to be shown is related to

configuration. An example of configuration is selecting and setting

the fonts. Once a font has been set, a message whose type conf can

be shown to the user informing him/her the name of the new font.

c. global

The value of global argument decides whether, the note displayed is global or not. Global note is a note that will be displayed even if the application calling the note function is not in foreground. The global argument takes an integer value. Any value other than zero is used to make a note or the displayed message global. The default value for this argument is zero. For example, to show a non-global message to the user, the value passed to the global argument will be

0

For example to display a global error message stating that memory is full, the statement will be

note(u”Memory is full”, error, 1)

That brings us to the end of second section. Next section will be about an application using whatever has been discussed until now.

PyS60 in Real World

Lets now see how these controls can be used within an application. The application going to be developed is a simple guessing game. It will perform following tasks

1. Choose a random number

2. Ask the user to enter his or her guess

3. Compare and show the result

4. Ask if he or she will like to continue

So lets start. First the imports

from appuifw import *

As you already know the above statement imports all the classess within appuifw module. Next the application has to choose a random number. However, since this will be a repeating process until the user chooses to stop, choosing the random number will be within a loop. The loop will terminate only when user says he or she will like to stop. The code is as follows

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

The loop will continue till continue_guess becomes false. Next, the application needs to accept user’s guess. To accept the value, query function will be used. The message will be “Enter your guess”, the type will be number (since decimals will not be allowed) and no initial value will be displayed. The value will be saved in user_guess variable. Here is the code

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

Next comes the comparison and displaying the result functionality. First, the user_guess will be checked for validity i.e. if user clicked cancel, it will be null. If it is not null, then it will be compare with the guess_no and appropriate no. will be displayed. If user pressed cancel, a “You opted out” will be shown and the continue_guess will be set to false. Here is the code

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

Next comes the code that asks user whether to continue or not. The query box is shown to the user with “Enter Y to continue and N quit”. If Y is entered, the loop is continued else the application is exited.

from appuifw import *

continue_guess=true

while continue_guess:

guess_no=random()

user_guess=query(u”Enter your guess”, ‘number’)

if user_guess is Null:

note(u”You have opted out”)

continue_guess=false

elif user_guess<guess_no:

note(u”Your guess is lesser than the goal”)

elif user_guess>guess_no:

note(u”Your guess is higher than the goal”)

else:

note(u”Congrats for excellent guess”)

user_choice=query(u”Enter Y to continue or N to quit”)

if user_choice is Null or user_choice==’N’:

continue_guess=false

else:

continue_guess=true

That completes the application. In this discussion, the focus was on simple UI controls. From the next part, complex UI controls such as forms. Till then…

Smart phones are becoming a common sight nowadays. Above all, the ‘smartness’ of the smart phones come from the fact that they can be programmed. In other words, one can develop custom applications for these mobiles and use them in the mobiles. Almost all the languages, from C to Java and Perl to Ruby, provide API to access and create services for the smart phones. Among them, nothing, at present, can beat the flexibility and ease-of-development that Python provides. Symbian is the most common OS used by smart phones. Symbian port of Python is known as pyS60. in this discussion I will be focusing on the basics of pyS60. The first section will focus on the topic ‘what is pyS60’. In the second section, I will detail the steps in developing and deploying a pyS60 application. In the last section, a real world application will be developed. That sets the outline for this discussion.

What is PyS60:

PyS60, also known as Python for S60 version, is a port of Python, released by Nokia for Symbian OS and targeted at N60 series of mobiles. The libraries provided by PyS60 can be divided into broad categories:

1. Built-in libraries

2. Dynamically loadable libraries

Since PyS60 essentially, is an extension to the standard Python, so, it is known as Python for S60 extension. Hence the categories can also be called as Built-in extensions and Dynamically loadable extensions. Here are the details

1. Built-in libraries or extensions:

It is one of the two native C++ extensions available in PyS60. These provide non-proprietary API to Symbian 60’s (S60) platform. The built-in extensions again divided into two modules:

i. e32:

This module provides access to those services that are not available in standard Python libraries. Essentially, this module is built into the Python interpreter to provide access to the Platform services of S60. These services include timer service (Ao_timer class), system information (sysinfo module and its classes), listing of the drives (drive_list method) etc.

ii. appuifw:

Using this module developer can access the API related to UI elements of S60 platform. The main UI elements include Text, Listbox, Canvas etc. Using the elements GUI can be constructed either as part of a window or as the part of screen itself. If the elements or controls are the part of the window then window becomes the container.

2. Dynamically loadable libraries or extension:

These extensions, as the name suggests, are loaded dynamically i.e. only when

needed as opposed to the Built-in extensions which are loaded when import statement is encountered. The reason for such a behavior is that the Dynamically Loadable extensions provide access to proprietary S60 API. There are 16 dynamically loadable extensions. Most commonly used among them are

i. graphics:

It provides access to the graphics manipulation capabilities of S60 platform including loading, saving, resizing of images.

ii. messaging:

This module provides access to the messaging capabilities of the S60. It

includes SMS and MMS services.

iii. inbox:

Using the inbox module one can access the inbox of the mobile on which

application is being executed. The information one can access includes the

message, time of message, the address of the sender etc.

iv. camera:

When one wants to access the camera, one can use this module. It grants access to all the functionalities of the camera that include image modes, flash modes, maximum zoom available etc.

v. audio:

It provides access to the audio capabilities of the device. The functionalities

include playback of different formats of audio files, recording of voice, text to

speech etc.

vi. calendar:

To use the calendar functionalities of the device, one can make use of this

module.

vii. contacts:

Using contacts module, one can access the contact list in a device. The

contacts are provided in the form of dictionary.

That completes the services provide by PyS60. Next, let us see the steps in

accessing the different services of the mobile using Python.

Accessing Services – Step By Step:

The ease of programming using Python reduces the steps required to access the different services. However, there are two steps that is always required. They are:

1. Instantiating the object of the Service

2. Setting the required properties

3. Calling the methods to access required functionality

These steps are generic to not only S60 platform but also to any mobile platform, including embedded Linux, which is another mobile platform. I will use sound module as an example for all the steps.

1. Instantiating the object of Service:

Most of the time this is the first step in accessing the service. This step is essential when working with built-in extensions. However, for most of the dynamically loadable extensions, objects are not required as their functionalities can be directly accessed. The reason is that the methods of the dynamically loadable modules are static. For example, to create a text field (the name of text field component is query) the statements will be

input= query(u”Enter Text”,”Text”)

On the other hand, to use sound module to load a file, one has to just call the open method of Sound class. The open method is a static, so object of Sound class is not required. Following statement opens a .wav file named test.wav.

Sound.open(“test.wav”)

2. Setting the required attributes:

Next step is to set up the attributes of the object instantiated. If the service can be accessed through static methods, then attributes can also be set or accessed through static mutators (setters) or accessors (getters). As with all the classes of Python, the attributes can be set at the time of instantiating the object. For example, selection_list can be used to show a list of items to the user, from which he or she can tell his or her choice. The option to show a search field can be set at instantiation. The following statements display a list of fonts available on the device and let the user select one of the available fonts.

li =available_fonts()

sl=selection_list(li,1)

However, to set the volume of Sound object one has to just call the set_volume() method, which is again a static method. The following statement sets the volume to 10.

Sound.set_volume(10)

3. Calling the methods to access required functionality:

The last step is to call the required methods on the objects to access the services. If the object is a UI component then the ‘service’ will either be displaying some value to the user or get some value from the user. If it were a device-based service such as Sound, then accessing the functionality would mean requesting the platform to either play or stop the audio file. For example, the query component returns the value entered by the user after initialization. Therefore, the instantiation returns the value entered by the user. The returned value can be displayed using note object. The following statements accepts a string from the user and display it to the user

data=entry(u”Enter your message:”, “text”)

note(u”Your message was: “+data, “info”)

If one needs to access the play service provided by Sound module, he or she has to just call the play() method of Sound class. The following statement just does that

Sound.play()

That completes the steps to work with PyS60. One point to keep in mind is that the string being passed to the methods and constructors need to be Unicode i.e. the string should be prefixed with “u” otherwise the string may not be displayed correctly. Next, I am going to develop a small application that would accept path to a .wav file and then play it.

PyS60 Programming – In Real World:

The application to be developed will have the following functionalities

1. Input box – To accept the path for file to be played

2. Playing the selected File – To play the file entered by the user

Here we go. First comes the imports. Since both UI and Sound are required, so appuifw and audio modules need to be imported

from appuifw import *

import audio

Next we need to show the entry box to the user and get the path entered by him or her. To display the text box, we can use query component. The first argument is the prompt to be shown and the second argument is the type of query. The type can be ‘text’, ’date’, ’time’, ’float’ etc. Here the type will be text as we need textual data i.e. string. The value returned by query component will be stored in a variable named data. Since, the value returned by

from appuifw import *

import audio

data=query(u’Enter the path of the file to be played’, ‘text’)

Now we need to load the file. For that we need to call the load method of sound. As discussed in the previous section every method in sound module is static. We will also check whether user clicked cancel. If cancel has been clicked, then data will contain null.

from appuifw import *

import audio

data=query(u’Enter the path of the file to be played’, ‘text’)

if data is not Null:

Sound.load(data)

else:

note(u’Give the path name’, ‘info’)

Next let us tell Symbian to play it.

from appuifw import *

import audio

data=query(u’Enter the path of the file to be played’, ‘text’)

if data is not Null:

Sound.load(data)

Sound.play()

else:

note(u’Give the path name’, ‘info’)

That completes our application. Though it is small, yet it introduces several important concepts of PyS60. In the coming discussions, I will go into the depth of each module. Till then…

Follow

Get every new post delivered to your Inbox.