Programmer le Palm

Cet article a été publié dans le numéro 4 (décembre 1999) du magazine Team Palmtops.
Il est reproduit avec l'aimable autorisation de Posse Press.

 

Le mois dernier, nous avons sacrifié à la coutume du "Hello, world !" avec une application plutôt minimaliste. Ce mois-ci, nous allons étendre cette application en nous appuyant sur les composants d'interface proposés par PalmOS, afin de la rendre capable d'interagir avec l'utilisateur.

Les fichiers mentionnés dans cet article sont contenus dans l'archive ex01.zip.

Débutons par un petit peu de théorie. Notre application d'exemple comportait un formulaire (form). En fait, l'interface utilisateur du Palm repose presque exclusivement sur les formulaires : vues, boîtes de dialogues et autres alertes ne sont rien d'autre que des déclinaisons.

Fondamentalement, un formulaire consiste en une zone rectangulaire qui contient d'autres objets, tels qu'un bouton ou un champ de saisie. Généralement doté d'un titre et souvent d'une bordure, le formulaire s'apparente beaucoup aux fenêtres des environnements graphiques comme Windows, MacOS ou X11. Sous PilRC, un formulaire est déclaré comme suit :

form
	id <identifiant>
	at (<position> <extension>)
	<options>
begin
	<objets>
end

<identifiant> est le numéro de ressource affecté au formulaire. Dans l'exemple du mois dernier il s'agissait de la constante idFormMain. <position> indique les coordonnées du point supérieur gauche du formulaire. <extension> en indique les dimensions horizontale et verticale.

Un certain nombre d'options sont disponibles, qui permettent de caractériser plus précisément un formulaire. Elles sont décrites dans le tableau 1. Enfin, le formulaire peut contenir un certain nombre d'objets, listés dans le tableau 2. La syntaxe et les différentes options pour déclarer des objets figurent dans la documentation de PilRC (c:\PalmSDK\PilRC\doc\Pilrc.htm pour l'installation décrite dans le numéro d'octobre), nous ne les détaillerons pas outre mesure.

Tableau 1 - Les options de définition d'un formulaire

Objet Description
NOFRAME Supprime la bordure.
MODAL Transformation en boîte de dialogue.
NOSAVEBEHIND Supprime la mémorisation de ce qui était affiché avant l'apparition du formulaire.
HELPID Spécifie le texte d'aide que l'utilisateur pourra consulter en tapant sur le "i" à droite de la barre de titre.
DEFAULTBTNID Indique le bouton par défaut.
MENUID Définit le menu à attacher au formulaire.

Tableau 2 - Les objets pouvant figurer dans un formulaire

Objet Description
TITLE Titre du formulaire.
LABEL Label : chaîne de caractères contenant un texte statique à afficher dans le formulaire.
FORMBITMAP Bitmap : élément graphique statique inséré dans le formulaire.
FIELD Champ de saisie ou d'affichage, contenant des informations dynamiques.
LIST Liste.
TABLE Table.
BUTTON Bouton simple.
REPEATBUTTON Bouton à répétition automatique, tant que l'on appuie dessus.
CHECKBOX Case à cocher.
PUSHBUTTON Bouton radio : les boutons d'un même groupe sont mutuellement exclusifs, on ne peut en activer qu'un à la fois.
POPUPTRIGGER Déclencheur de liste : affiche la valeur courante d'un choix dans une liste et déclenche l'affichage de cette liste lorsqu'il est actionné.
SELECTORTRIGGER Déclencheur de sélection : affiche la valeur courante d'une sélection et déclenche l'affichage de la boîte de dialogue de sélection lorsqu'il est actionné.
POPUPLIST Liste surgissante, dont l'affichage est déclenché par action sur un POPUPTRIGGER.
SCROLLBAR Barre de défilement.
GRAFFITISTATEINDICATOR Indicateur d'état Graffiti (majuscule, ponctuation, caractères spéciaux, etc.).
GADGET Gadget : objet indéfini dont le comportement est entièrement gouverné par l'application.

C'est pour un sondage !

Pour étoffer notre application, nous allons imaginer qu'elle doit servir à collecter des informations pour un petit sondage. La figure 1 présente les deux pages du questionnaire envisagé. L'objectif n'est évidemment pas de mener une véritable enquête, mais de mettre en œuvre les principaux éléments d'interface proposés par PalmOS.

Figure 1 - Les deux pages de notre questionnaire.

La première page du questionnaire contient ainsi une liste (plate-forme préférée), des boutons radio (l'utilisateur possède-t-il un palmtop ?), des cases à cocher en mode non-exclusif (magazines lus) et en mode exclusif (sexe), et bien sûr un bouton standard.

La définition PilRC de cette page est contenue dans le fichier app.rcp, pour le formulaire idFormPage1.

Les textes en gras sont de simples labels tracés en utilisant la fonte 1. Pour effectuer la justification à droite des labels de la liste et des boutons radio, nous profitons de la directive rightat disponible avec PilRC : rightat 95 signifie alors simplement que le côté droit du label devra être positionné sur l'abscisse 95. Par ailleurs, nos labels n'apparaissent que pour " habiller " notre formulaire et n'intéragissent pas avec le programme. Aussi, il n'est pas nécessaire de définir précisément la valeur de leur identifiant. C'est pourquoi nous utilisons la clause autoid, qui indique à PilRC d'affecter automatiquement un identifiant à l'objet considéré.

La définition de la liste n'est guère plus complexe. Il suffit en effet d'énumérer les différents items qui la constituent et de préciser la position et les dimensions de la zone rectangulaire dans laquelle elle doit apparaître. Dans notre cas, les dimensions que nous avons choisies ne permettent pas l'affichage de tous les items de la liste. Ce cas de figure est géré automatiquement et une petite flèche, sur laquelle l'utilisateur peut taper, lui indique qu'il existe d'autres items.

Les boutons poussoirs "Oui" et "Non" sont également définis de façon très simple. Notons qu'il est nécessaire de les lier, afin que la sélection de l'un provoque la libération de l'autre. Le lien est établi à l'aide de la clause group : leur appartenance au même groupe lie nos deux boutons. On remarquera par ailleurs l'usage de trois autres directives disponibles avec PilRC : auto laisse à PilRC le soin de définir la largeur ou la hauteur de l'objet, en fonction de son contenu ; prevtop reprend l'ordonnée du côté supérieur de l'objet précédent ; prevright reprend l'abscisse du côté droit de l'objet précédent. Ces deux dernières directives se révèlent très utiles pour positionner des groupes d'objets les uns relativement aux autres, de sorte qu'il ne soit nécessaire de préciser qu'une position absolue : celle du premier objet, qui sert de référence pour tout le groupe. Dès lors, pour déplacer tout le groupe, il suffit de modifier les coordonnées de l'objet de référence, ce qui s'avère beaucoup plus commode que de recalculer toutes les positions.

Les cases à cocher s'apparentent beaucoup aux boutons poussoirs. Si elles sont indépendantes, on ne précise pas de groupe d'appartenance. Sinon, comme les boutons poussoirs, on les lie en les affectant à un même groupe. Une case à cocher peut être cochée par défaut, ce que l'on précise à l'aide de la directive checked.

Enfin, le bouton poussoir est caractérisé par son libellé, sa position et ses dimensions, que l'on définit ici encore avec le concours bienveillant de PilRC, puisque l'on s'appuie sur les directives auto, rightat et son homologue bottomat.

La seconde page du questionnaire comporte un champ de saisie multi-lignes, l'indicateur d'état Graffiti (nécessaire car il y a possibilité de saisir des caractères), un déclencheur de liste (ainsi que la liste surgissante associée, représentée figure 2), un déclencheur de sélection et deux boutons graphiques.

Figure 2 - Une liste surgissante permet de sélectionner la tranche d'âge.

La définition d'un champ de saisie peut comporter de nombreuses options. Dans notre cas il s'agit d'un champ multi-lignes, limité à 160 caractères, dont chaque ligne est soulignée par des pointillés.

L'indicateur d'état Graffiti est inclus dans le formulaire en spécifiant simplement ses coordonnées.

Le déclencheur de liste est défini par son libellé, sa position et ses dimensions. Nous utilisons de plus la directive leftanchor pour indiquer qu'en cas de changement de libellé, la longueur sera ajustée par la droite (ancrage à gauche). En effet, pour le déclencheur de liste l'ancrage par défaut est à droite. La liste associée au déclencheur ressemble à celle de la première page, mais on précise cependant qu'elle est inutilisable et désactivée (directives unusable et disabled), de façon qu'elle reste cachée lorsque le formulaire est affiché. L'association entre le déclencheur et la liste est obtenue par la déclaration d'un pseudo-objet popuplist, dont les propriétés ne sont autres que les identifiants du déclencheur et de la liste.

Le déclencheur de sélecteur fonctionne de façon similaire mais sera associé à un autre formulaire. En l'occurrence, il s'agira du formulaire standard qui permet de sélectionner une date (voir figure 3).

Figure 3 - Sélection de la date par le formulaire standard.

En ce qui concerne les boutons graphiques, nous recourons à une petite astuce. En effet, les boutons graphiques n'existent pas à proprement parler dans PalmOS. Pour y suppléer, nous incluons une bitmap dans le formulaire puis nous lui superposons deux boutons standards sans cadre (directive noframe) ni libellé, dont la position et les dimensions sont ajustées pour correspondre aux pictogrammes choisis (voir figure 4).

Figure 4 - Bouton + Bitmap = Bouton graphique !

 

Au menu aujourd'hui…

La philosophie du Palm est de réduire au maximum le nombre d'actions que doit effectuer l'utilisateur pour parvenir à son but, de façon à lui faciliter la vie. A ce titre, un menu n'est généralement pas l'élément d'interface le plus indiqué. En revanche, c'est une bonne règle de conception que d'y inclure toutes les actions disponibles. De cette façon, l'utilisateur n'est jamais pris au dépourvu s'il ne trouve pas comment effectuer une opération : il sait qu'il lui suffit de chercher dans les menus. Pour notre application, nous prévoyons un menu constitué de deux sous-menus (voir figure 5).

Figure 5 - Le menu de notre application.

La définition d'un menu est très facile. On précise le nom de chaque sous-menu à l'aide de la directive pulldown, puis on indique la liste des items en utilisant la directive menuitem. Il est possible d'insérer des lignes de séparation dans un sous-menu, en déclarant un menuitem separator.

Un raccourci peut être affecté à chaque item d'un sous-menu. Pour ce faire, on indique simplement le caractère à utiliser. Par exemple, dans notre menu nous avons affecté les raccourcis C, X et V aux actions Copier, Couper et Coller, comme c'est l'usage sous Windows par exemple. Au lieu de sélectionner Couper dans le menu, l'utilisateur pourra se borner à saisir <commande>-X en Graffiti (pour mémoire, <commande> est un " / " tracé de bas en haut). Bien entendu, il n'est pas indispensable d'associer un raccourci à chaque action. Notons également que chaque raccourci doit être unique, c'est-à-dire qu'un même caractère ne peut pas être affecté à deux items distincts, même s'ils ne figurent pas dans le même sous-menu.

A titre d'exemple, nous n'implémenterons que la fonction "A propos" du menu. Cette fonction fera apparaître une boîte de dialogue affichant le logo de Team Palmtops et menant à des informations complémentaires (voir figure 6), grâce à la directive helpid, qui permet d'associer un texte explicatif à une boîte de dialogue. L'association se traduit par l'affichage d'un petit " i " dans la barre de titre.

Figure 6 - Mise en œuvre de la directive helpid.

Conclusion

Nous avons à présent défini la plupart des éléments de notre interface utilisateur. Le mois prochain nous nous intéresserons au code sous-jacent. En attendant, vous pouvez d'ores et déjà le consulter et le compiler, ou simplement tester app.prc. Vos questions et commentaires sont bienvenus : n'hésitez pas à les transmettre par courrier électronique à l'adresse palmprog@ablivio.com.

Denis Faivre - palmprog@ablivio.com.

Copyright © 1999-2000 - Denis Faivre et Posse Press.
Tous droits réservés.