Exemple seaside: gestion d'une liste d'étudiants
From OFSET Wiki
Cette page a été construite par deux étudiants CNAM de Brest, Florent Pezennec et Olivier Kerlau. Merci donc et bravo car ils ne connaissaient rien du tout de Smalltalk avant de commencer leur application. Ce travail peut aider pour débuter avec squeak et seaside.
Contents |
[edit] Objectifs
Cette application seaside à plusieurs objectifs :
1) Permettre la saisie d'informations via un formulaire (nom, prenom, adresse, email, sexe et date de naissance d'étudiants);
2) Sauver ces enregistrements dans une "base" (variable de classe);
3) Effectuer une recherche alphanumérique sur certains champs (nom, prenom, adresse);
4) Afficher une liste synthétique des enregistrements, en permettant via un lien hypertext sur le nom d'accéder à la visualisation et la modification de l'enregistrement sélectionné;
5) Supprimer les enregistrements de la "base"
6) Exporter tous les enregistrements dans un fichier texte (format séparateur ;)
L’application est divisée en quatre éléments graphiques.
Ces 4 éléments auront chacune une classe ce qui permettra de simplifier et de ne pas surcharger le code de chacune.
________________________________
| Titre |
| Sous-Titre |
|________________________________|
| | | |
| | Corps | |
| | de | Message |
| Menu | l'appli. | d'infos |
|(Liens)| (saisie, | sur |
| | résultat) | l'appli.|
|_______|______________|_________|
Téléchargement :
Squeak : http://www.squeak.org/Download
Seaside : http://www.seaside.st/Download/Images/
Serveur depuis Squeak (Workspace) :
Lancement : WAKomEncoded startOn: 9090
Arrêt : WAKomEncoded stop
Configuration :
Dans Seaside : http://localhost:9090/seaside/config
Par défaut ==> user : seaside, password : admin (ou ceux que vous avez rentrer lors de l'installation)
Depuis Squeak (Workspace): <Nom de la classe> registerAsApplication: '<nom de l'application dans le browser>'
Exemple : WAEtudiant registerAsApplication: 'Etudiant'
Exemples de composants :
http://localhost:9090/seaside/alltests
Lancement d'une application :
http://localhost:9090/seaside/<Nom de l'application passé à la méthode registerAsApplication:>
Exemple : http://localhost:9090/seaside/Etudiant
Liens utiles :
Tutotiel de david Shaffer : http://community.ofset.org/wiki/Tutoriel_de_David_Shaffer
Documentation Community Ofset : http://community.ofset.org/wiki/Seaside
Squeak swiki : http://minnow.cc.gatech.edu/squeak/
[edit] Processus de mise en oeuvre
Pour commencer, vous aurez besoin de :
* Installation fonctionnelle de Squeak http://www.squeak.org/Download
Télécharger une version de Squeak (.zip)
Image file - Basic Squeak Release - Full Squeak Release
Décompresser cette archive dans un dossier qui devrait contenir :
Squeak3.X.image, Squeak3.X.changes, SqueakV3.sources (avec "X" pour la version, par exemple 8-6665) et l'exécutable (nommé selon les spécifications de la plateforme, exemple Squeak.exe sur Windows).
* Seaside et de ses dépendances
- Soit à partir d'une image déjà fonctionnelle téléchargeable sur
http://www.seaside.st/Download/Images/
- Soit à partir de l'image Squeak sur laquelle vous devrez installer le package Seaside.
Tous ces paquets sont disponibles grâce à SqueakMap. Cliquez sur le bureau de Squeak pour ouvrir le menu World, choisissez ouvrir, puis PackageLoader. Depuis le package loader, installez les éléments suivants dans cet ordre :
- DynamicBindings
- KomServices
- KomHttpServer
- Seaside
(Pour installer, sélectionnez le nom du paquet et ouvrez le menu contextuel associé, choisissez 'install'.
À la fin de l'installation, un nom d'utilisateur et un mot de passe vous sera demandé - ils sont utilisés par l'utilitaire de configuration Seaside.
* Connaissance du Smalltalk et de notions de HTML
La maîtrise de l'environnement de Squeak pourra vous aider.
Avec l'image 2.5 de Seaside, l'écran ouvert dans Squeak devrait ressembler à celui-ci :
Quand tout est installé, vous devez lancer le service Seaside. Seaside fournit une classe WAKom pour pouvoir utiliser le serveur web Commanche. Pour lancer commanche configuré pour Seaside, évaluez la ligne suivant dans un Workspace :
WAKom startOn: 9090
Seaside doit maintenant écouter sur le port 9090. À chaque fois que vous rouvrirez l'image à partir de maintenant, le service Seaside sera automatiquement lancé.
Pour vérifier que Seaside fonctionne, ouvrez un navigateur à l'adresse : http://localhost:9090/seaside/counter. Cela doit faire apparaître une petite application Seaside : un simple compteur avec deux liens pour incrémenter et décrémenter. Commençons par jouer un peu avec et vérifions qu'il fonctionne correctement : cliquez sur le lien "++" pour augmenter le nombre et sur le lien "--" pour le diminuer.
Comme sur l'écran ci-dessous :
[edit] Description du framework Seaside
Seaside est un framework orienté objet qui est développé en Squeak, une plateforme open-source et un environnement de développement pour Smalltalk.
Le code peut être ajouté et édité pendant que l'application web tourne. Il n'est pas nécessaire de redémarrer le serveur ou de recompiler le code.
Dans plusieurs cas, cela rend possible la mise à jour de système en production sans aucune coupure et sans qu'un serveur backup soit nécessaire.
Nous verrons plus loin comment implémenter une classe simple, mais nous allons nous intéresser à deux points importants de Seaside le Debug et l'affichage dans le navigateur.
Debugger avec Seaside :
Lorque qu'une erreur se produit une page d'erreur survient invoquant le problème qu'il y a dans le code ( MessageNotUnderstood:)
Sur cette page on peut voir un lien appelé Debug.
En cliquant sur ce lien, le développeur active un débuggeur dans l'environnement de développement Squeak qui le laisse inspecter les variables et même changer le code à la volée.
Voici un example en images:
On voit donc qu'en cliquant sur debug (1) cela ouvre le debugger dans l'environnement de développement ou l'on peut donc corrigé le code (2).
Dans l'exemple ci-dessus, remove a été mal écrit , si il est modifié correctement et que l'on clique sur proceed, la page réactualisé (F5) est affichée correctement dans le browser et il n'y a eu besoin d'aucun arrêt serveur...
Les éléments d'une page Seaside :
Exemple : Application Etudiant
Toolbar:elle apparait en bas de l'application web durant la phase de développement, elle permet au développeur d'accéder à quelques outils.
Ces outils étant écrits en seaside eux-memes.
- New Session: démarre l'application dans une nouvelle session. - Configure: permet de configurer les paramètres de l'application
(ou démarrer une nouvelle session, la Toolbar visible ou non..)
- Toggle halos: pour voir ou cacher les halos dont on parlera juste un peu plus loin. - Profile: temps passé à construire la page. - Memory use: mémoire utilisé par l'application. - XHTML: démarre un validateur XML externe sur cette page.
Les halos: Quand on clique sur Toggle Halos, les composants sont entourés par une ligne grise avec un titre donnant le nom de la classe et quelques outils qui permettent de changer les vues.
- System Browser: ouvre un éditeur sur la classe en cours et permet de modifier le code alors que l'application tourne.
- Inspecteur: ouvre une vue du composant.
- Library Browser: ouvre un éditeur qui permet de changer le code du style et de le modifier en direct pour différents tests de rendus.
- Source View: nous montre une syntaxe plus conviviale XHTML.
[edit] Description des différentes possibilités de Rendering
Pour ces différents rendering, nous utiliserons une classe simple issu de la super classe WAComponent.
Cette classe WAComponent représente les éléments d'une application Seaside.
Un élément (composant) de Seaside peut a des états (variables d'instances), des aspects graphiques (decorations), des sous-composants (children), et l'aspect graphique (affichage) obtenu par la méthode renderContentOn:.
Un composant peut appeler d'autre composant par la méthode call:
Nous devons tout d'abord déclarer une nouvelle classe (sous classe de WAComponent) que nous appellerons WATest :
WAComponent subclass: #WATest instanceVariableNames: 'champ date' classVariableNames: poolDictionaries: category: 'TP-Etudiant'
Nous allons voir ci-après les principales possibilités d'affichage de texte et d'éléments de formulaires :
TEXTE
L'affichage se fait par la méthode renderContentOn: Directement :
renderContentOn: html html html: 'texte a afficher directement'.
Ou par l'intermédiaire d'une méthode ici "text" qui renvoie une chaine de caractère avec éventuellement une mise en forme retour à la ligne, gras, italic, etc.
Bien que ce ne soit pas le but, il est ainsi possible d'utiliser directement le langage HTML pour la mise en forme
html html: self text
Champ TEXTE simple
html divClass: 'label' with: 'Nom du champ :'.
html divClass: 'field'
with: [html textInputWithValue: self champ callback: [:v | self champ: v]]
Les méthodes champ et champ: sont utilisés ici pour mémoriser et restituer la valeur saisie par l'intermédiaire de la variable d'instance 'champ'.
champ
^ champ
champ: aString
champ := aString
Champ ZONE de TEXTE
html divClass: 'label' with: 'Nom du champ :'.
html divClass: 'field'
with: [html textAreaWithValue: self champ callback: [:v | self champ: v]].
Champ DATE
html divClass: 'label' with: 'Date de naissance :'.
html divClass: 'field'
with: [html dateInputWithValue: self date callback: [:v | self date: v]].
avec les méthodes
date
^date ifNil: [date := Date today]
et
date: aDate
date := aDate
BOUTON de validation
html divClass: 'button'
with: [html submitButtonWithAction: [self save] text: 'Nom du champ'.]
La méthode save serait ici utiliser pour effectuer une action lors de la validation du champs.
RADIO BOUTON
html divClass: 'label' with: 'Nom du champ:'.
html divClass: 'field'
with: [|group|
group := html radioGroup.
html radioButtonInGroup: group
selected: self champ = #ValeurOption1
callback: [self champ: #ValeurOption1].
html text: 'option 1'; break.
html radioButtonInGroup: group
selected: self champ = #ValeurOption2
callback: [self champ: #ValeurOption2].
html text: 'option 2'].
La valeur du champ radio est soit la chaine de caractère 'valeurOption1' soit 'valeurOption2' suivant le radio sélectionné.
CASE A COCHER
html spanClass: 'label' with: 'Nom du champ :'.
html spanClass: 'field'
with: [html checkboxOn: #champ of: self]
LISTE Déroulante
html spanClass: 'label' with: 'Nom du champ :'.
html spanClass: 'field'
with: [html selectInputOn: #champ of: self list: #(choix1 choix2)]
Voici l'illustration des différents type de champ décrit ci-dessus :
Une partie de ces champs est utiliser pour la fonction ENREGISTRER de l'application Etudiant, notamment dans la classe WAEtudiantFormView décrite plus loin.
[edit] L'application ETUDIANT (Classes et Méthodes)
Catégorie : TP-Etudiant
Les principales classes :
1) Classe WAEtudiant
2) Classe WAEtudiantTab
3) Classe WAEtudiantMain
4) Classe WAEtudiantInfo
5) Classe EtudiantForm
Les autres classes (par fonctionnalités) :
1) RECHERCHER (EtudiantInventory, EtudiantItem, WAEtudiantItemView, WABatchSelection)
2) ENREGISTRER (WAEtudiantFormView)
3) LISTER (WAListeEtudiant, WAEtudiantFormView2)
4) EXPORTER (WAExportEtudiant)
5) RESET DATABASE
Les Principales Classes :
1) Classe WAEtudiant, entrée de l'application ETUDIANT
Création d'une instance de classe WAEtudiantTab dans l'initialize .
WAComponent subclass: #WAEtudiant instanceVariableNames: 'tab' classVariableNames: poolDictionaries: category: 'TP-Etudiant'
Gestion de l'affichage de cette classe avec la méthode Children et renderContentOn:.
initialize
tab _ WAEtudiantTab new.
children
^ Array with: tab
renderContentOn: html
html cssId: 'banner'.
html table: [
html tableRowWith: [
html divNamed: 'title' with: self title.
html divNamed: 'subtitle' with: self subtitle.
]
].
html divNamed: 'body' with: tab
L'écran est composé d'une banniere et du corps de la page. Titre et sous-titre de l'application renseigné dans les méthodes title et subtitle.
title
^ 'Gestion des Etudiants du CNAM'
subtitle
^ 'Application de gestion des étudiants du CNAM'
style
^ '
body {margin: 0px; font-family: sans-serif}
#banner {width: 100%}
#banner tr {background-color: lightblue; text-align: center; padding: 10px; vertical-align: bottom}
#title {font-size: 18pt; font-weight: bold}
#subtitle {font-size: 9pt; font-style: italic}
#body {padding: 5px}
.validation-error {color: red; font-size: 9pt; padding: 5px}
'
2) Classe WAEtudiantTab, composition du corps de la page
Création des instances de classe WAEtudiantMain et WAEtudiantInfo dans l'initialize . Gestion de l'affichage de cette classe avec la méthode Children et renderContentOn:.
WAComponent subclass: #WAEtudiantTab
instanceVariableNames: 'main info'
classVariableNames:
poolDictionaries:
category: 'TP-Etudiant'
initialize
main _ WAEtudiantMain new.
info _ WAEtudiantInfo new.
children
^ Array with: main with: info
renderContentOn: html
html table: [
html tableRow: [
html cssId: 'nav'; tableData: [self renderNavBarOn: html].
html cssId: 'main'; tableData: main.
html cssId: 'infoEtu'; tableData: info.
]
]
Cette classe définit la composition du corps de la page, il y a 3 parties distinctes :
- Le menu à gauche (méthode renderNavBarOn:)
- L'affichage au centre (classe WAEtudiantMain)
- Les informations à droite (classe WAEtudiantInfo)
La méthode renderNavBarOn: propose le menu suivant :
- Rechercher (méthode search:) qui fonctionne avec les classe EtudiantInventory, EtudiantItem et WAEtudiantItemView;
- Enregistrer (méthode enregistrer) qui fonctionne avec la classe WAEtudiantFormView;
- Lister (méthode lister) qui fonctionne avec la classe WAListeEtudiant et WAEtudiantFormView2;
- Exporter (méthode exporter) qui fonctionne avec la classe WAExportEtudiant;
et pour les tests :
- Reset Main (méthode resetMain) qui fonctionne avec la classe WAEtudiantMain;
- Reset Database (méthode reset) qui fonctionne avec la classe EtudiantForm
L'activation des ces différentes fonctionnalités se fait par ce menu.
renderNavBarOn: html
html form: [
html bold: 'Rechercher :'.
html space.
html textInputWithValue: callback: [:v | self search: v].
].
html anchorWithAction: [self enregistrer] text: 'Enregistrer un étudiant'.
html br.
html br.
html anchorWithAction: [self lister] text: 'Lister '.
html br.
html br.
html anchorWithAction: [self exporter] text: 'Exporter'.
html br.
html br.
html br.
html br.
html br.
html br.
html br.
html anchorWithAction: [self resetMain] text: 'Reset Main'.
html br.
html anchorWithAction: [self reset] text: 'Reset Database'.
html br.
3) Classe WAEtudiantMain, initialisation partie centrale
Cette classe sert uniquement à initialiser (affichage "vierge") la partie centrale au démarrage de l'application.
renderContentOn: html
html html: ' '
4) Classe WAEtudiantInfo, initialisation partie droite
Cette classe sert uniquement à initialiser (Information de bienvenue, etc.) la partie droite au démarrage de l'application.
renderContentOn: html
html html: self text
Le texte est paramétrable dans la méthode "text".
5) Classe EtudiantForm
Cette classe permet la gestion (affectation et récupération) des informations d'un objet Etudiant (nom, prenom, adresse, etc).
Elle permet égalament la gestion de la classVariableNames: Database qui permet ici le stockage des enregistrements saisis par le biais des méthodes add:, database, resetDatabase et sample1.
La validation du formulaire de création entraine l'appel de la méthode validate qui permet de vérifier la cohérence des informations saisies.
Les Autres Classes (par fonctionnalités) :
1) ENREGISTRER (WAEtudiantFormView)
Il s’agit de remplir un formulaire tout en gardant les données dans une base (on utilisera la variable de classe Database)
Mise en œuvre : avec la méthode enregistrer dans la classe
enregistrer
main call: (WAEtudiantFormView new).
Qui fait appel à WAEtudiantFormView (mise en œuvre du formulaire dans cette classe)
Le tutoriel de D Shaffer sur les formulaires nous a permis de mettre en place très simplement ceci : http://community.ofset.org/wiki/Tutoriel_de_David_Shaffer/Formulaires
On crée le rendu avec des boutons radio, des cases à remplir….
renderContentOn: html
html heading: 'Enregistrement dun étudiant' level: 3.
html cssId: 'form'; form:
[html divClass: 'label' with: 'Nom :'.
html divClass: 'field'
with: [html textInputWithValue: self nom
callback: [:v | self nom: v]].
html divClass: 'label' with: 'Prenom :'.
html divClass: 'field'
with: [html textInputWithValue: self prenom
callback: [:v | self prenom: v]].
Derrière le bouton Enregistrer, on met une gestion d’erreur en cas de cases non remplies.
save
|etu d erreur|
erreur:=0.
[nom ifNil: [erreur:=1. self error: 'Vous devez rentrer un NOM !']]
on: Error
do: [:e | self inform: ' ', e asString].
(erreur=0) ifTrue:
[
[prenom ifNil: [erreur:=1. self error: 'Vous devez rentrer un PRENOM !']]
on: Error
do: [:e | self inform: ' ', e asString].
].
(erreur=0) ifTrue:
[
[addresse ifNil: [erreur:=1. self error: 'Vous devez rentrer une ADRESSE !']]
on: Error
do: [:e | self inform: ' ', e asString].
].
(erreur=0) ifTrue:
[etu := EtudiantForm new
nom: nom;
prenom: prenom;
addresse: addresse;
sexe: sexe;
email: email;
datenaiss: datenaiss;
yourself.
d:= etu database.
d add: etu.
self answer].
On voit que dans cette méthode save, on a une nouvelle classe EtudiantForm qui sert de modèle avec pour définition ceci : (à noter la variable de classe pour stocker les formulaires).
Object subclass : #EtudiantForm
instanceVariableNames: 'nom prenom addresse sexe email datenaiss'
classVariableNames: 'Database'
poolDictionaries:
category: 'TP-Etudiant'
et
add: anEtudiant
self Database add: anEtudiant.
On voit donc que quand l’on presse sur le bouton Enregistrer, on rajoute l’étudiant du formulaire rempli dans la Database.
2) RECHERCHER (EtudiantInventory, EtudiantItem, WAEtudiantItemView, WABatchSelection)
Dans la méthode Initialize, création d'une Collection "items", initialiser avec le nom, prenom et adresse des étudiants présent dans la Database par les méthodes de la classe EtudiantItem.
Puis parcours de celle ci afin de trouver les enregistrements dont les champs nom, prenom ou adresse comprennent la chaine de caractère recherché avec les méthodes "findItem:" et "matches:" des classes respective EtudiantInventory et EtudiantItem.
Le résultat obtenu est le suivant :
- Si aucun enregistrement ne corresponda à la recherche, affichage du message :
"Aucune occurence de <chaine recherchée>";
- Si un seul enregistrement est trouvé, affichage de celui ci par la classe "WAEtudiantItemView";
- Si plusieurs occurences sont trouvées, affichage de la liste (nom, prenom) via la
classe "WABatchSelection" avec un lien sur le nom permettant de faire appel à la
classe "WAEtudiantItemView" pour afficher l'ensemble des informations.
Rechercher fait appel à la méthode search :(dans WAEtudiantTab)
search: aString | results | results _ self inventory findItem: aString. results isEmpty ifTrue: [main inform: 'Aucune occurence de ', aString printString] ifFalse: [self displayItems: results].
On voit que l’on affichera : ‘Aucune occurence de’ ce que l’on a tapé ou bien le résultat de la recherche. Avec les résultats qui proviennent de inventory méthode suivante :
inventory ^ EtudiantInventory new
Avec EtudiantInventory nouvelle sous classe qui s’initialise ainsi :
initialize
|e|
e := EtudiantForm new.
items _ OrderedCollection new.
e database do:
[:row |
items add: (self itemFromSpec: row)]
qui utilise de nouveau EtudiantForm une sorte de modèle d ‘étudiant que l’on a déjà vu au dessus (Avec dedans nom, prenom,...) et aussi l initialisation de database à une collection ordonné.
Et les méthodes suivantes d’EtudiantInventory qui sert à l’inventaire des résultats de la recherche
itemFromSpec: aDatabase
^ EtudiantItem new
nom: aDatabase nom;
prenom: aDatabase prenom;
adresse: aDatabase addresse
Avec EtudiantItem sous classe qui sert un peu de modèle pour afficher le résultat avec le nom, le prénom et l’adresse de la recherche voulue et notamment sa méthode matches qui sert pour cette recherche :
matches: aString ^ (nom includesSubstring: aString caseSensitive: false) or: [prenom includesSubstring: aString caseSensitive: false] or: [adresse includesSubstring: aString caseSensitive: false]
et dans la méthode de EtudiantInventory
findItem: searchString ^ items select: [:ea | ea matches: searchString]
Et ainsi displayItems peut afficher le résultat dans la fenetre principal:
displayItems: aCollection | list | aCollection size = 1 ifTrue: [^ self displayItem: aCollection first]. list _ WABatchSelection items: aCollection link: #nom text: #prenom. [self displayItem: (main call: list)] repeat
On a donc ceci :
avec :
displayItem: anItem main call: (WAEtudiantItemView new item: anItem)
qui grace à sa méthode de rendu permet d’afficher le détail quand on clique sur le lien Nom.
3) LISTER (WAListeEtudiant, WAEtudiantFormView2)
lister
main call: (WAListeEtudiant new)
Dans cette nouvelle classe, il y a un nouveau rendu (on affiche un tableau avec des noms) :
renderContentOn: html
Etc….
self renderDatabaseRowsOn: html].
avec :
renderDatabaseRowsOn: html
self promo do: [:etudiant |
html tableRow: [self renderEtudiant: etudiant on: html]]
renderEtudiant: etudiant on: html
html tableData: [html anchorWithAction: [self editEtudiant: etudiant] text: etudiant nom].
html tableData: etudiant prenom.
html tableData: etudiant addresse.
html tableData: etudiant email.
html tableData: [html anchorWithAction: [self removeEtudiant: etudiant] text: 'Effacer'].
editEtudiant: etudiant
|view|
view := WAEtudiantFormView2 new.
view model: etudiant.
self call: view
removeEtudiant: etudiant
|etu d |
etu := EtudiantForm new.
d:= etu database.
d remove: etudiant.
avec, WAEtudiantFormView2 modification WAEtudiantFormView pour éditer une instance de EtudiantForm.
On peut voir le tutoriel de D Shaffer pour appréhender ceci :
4) EXPORTER (WAExportEtudiant)
Il s’agit de saisir un nom de fichier dans lequel effectuer l’export du contenu de la variable de classe Database.
Remarque : Il faut saisir le nom du fichier uniquement, pour permettre d’utiliser différent système (windows/ linux) on récupère « le répertoire » par défaut grâce à la méthode default de FileDirectory.
Mise en œuvre : avec la méthode exporter dans la classe
exporter
main call: (WAExportEtudiant new)
Qui fait appel à WAExportEtudiant (mise en œuvre du formulaire dans cette classe)
On crée le rendu :
renderContentOn: html
html heading: 'Export de la liste des étudiants' level: 3.
html cssId: 'form'; form:
[
html br.
html divClass: 'label' with: 'Nom du fichier dexport (Default Directory) : '.
html divClass: 'field'
with: [html textInputWithValue: self nomfic
callback: [:v | self nomfic: v]].
html br.
html br.
html br.
html divClass: 'button'
with: [html submitButtonWithAction: [self fileExport] text: 'Exporter']
].
Dans la méthode fileExport, on vérifie la saisie d’un nom de fichier puis on récupère via la méthode database le contenu de la variable de classe que l’on va parcourir via la méthode PrintLignExp qui va formater les enregistrements et les écrire dans le fichier en utilisant la méthode nextPutAll.
fileExport
|fic e d erreur|
erreur:=0.
[nomfic ifNil: [erreur:=1. self error: 'Vous devez rentrer un nom pour le fichier export !']]
on: Error
do: [:elt | self inform: ' ', elt asString].
(erreur=0) ifTrue:
[e := EtudiantForm new.
d := e database. « database initialisée ainsi ^Database ifNil: [Database := OrderedCollection new] »
fic := (FileDirectory default) fileNamed: self nomfic.
d
do: [:element | fic nextPutAll: element printLignExp].
fic close.
]
et la méthode printLignExp utilise les méthodes de la classe EtudiantForm et formate le résultat en séparant les champs par des « ; ».
printLignExp | ts | ts:= TextStream on: (Text new: 200). ts nextPutAll: self nom asText. ts nextPutAll: ';' asText. ts nextPutAll: self prenom asText. ts nextPutAll: ';' asText. ts nextPutAll: self addresse asText. ts nextPutAll: ';' asText. ts nextPutAll: self email asText. ts nextPutAll: ';' asText. ts nextPutAll: self sexe asText. ts nextPutAll: ';' asText. ts nextPutAll: self datenaiss asText. ts nextPutAll: ';' asText. ts nextPutAll: String crlf. “retour à la ligne entre chaque enregsitrement” ^ ts contents.
On obtient ainsi un fichier texte ayant le format suivant :
5) RESET DATABASE
Cette fonction permet d’initialiser la base avec deux exemples de formulaires pré remplis. Le fait de cliquer sur ce bouton engendre la méthode reset dans la classe WAEtudiantTab :
reset
| p |
[(main confirm: ('Etes vous certains de vouloir initialiser la base ?'))
ifTrue:[(p := EtudiantForm new).
(p resetDatabase)]]
on: Error
do: [main inform: 'Caught: ']
à noter, la confirmation avant de réinitialiser la base et si l’on répond OUI, la méthode resetdatabase de la classe EtudiantForm se produit et réinitialise donc la base ainsi :
resetDatabase
Database := OrderedCollection
with: self sample1
with: self sample2.
^Database
et ceci :
sample1
^EtudiantForm new
nom: 'Pezennec';
prenom: 'Florent';
addresse: 'xxxxxxx 29000 xxxxxxx';
masculin;
email: 'xxxxxxxxx@xxxxxx.fr';
datenaiss: ('xx/xx/xxxx');
yourself.
















