1. Un peu plus loin avec l'interaction et le pilotage
2. Une méthode
de construction
1. Un peu plus loin avec l'interaction et le pilotage
Nous allons nous servir dans
ce paragraphe, de ce que nous connaissons sur la programmation par la syntaxe
(ou programmation par les grammaires) pour piloter les actions de dialogue
avec l'utilisateur.
1.1 Reconnaissance syntaxique du dialogue
Nous supposons que le dialogue peut être spécifié par une grammaire (ceci est d'autant plus vrai que c'est le programmeur qui décide du genre de dialogue à instaurer dans son interface, il lui est donc loisible de définir une " bonne " grammaire pour le dialogue entre son logiciel et l'utilisateur).
Nous recensons deux catégories
de dialogue :
Le deuxième mode de guidage
est classique et ressort de ce qui a été vu dans les chapitres
précédents. Nous nous intéressons plutôt au premier
mode de saisie qui est en fait plus aisé à programmer.
1.2 Saisie dirigée par la syntaxe : principe
Ce genre de saisie est le plus simple à mettre en œuvre en initiation, et donne des résultats immédiats ; en particulier, il se prête bien au prototypage avec un RAD visuel. Le programmeur peut élaborer un prototype (squelette d'IHM) de son interface, le faire fonctionner et le tester d'une manière autonome sans avoir besoin d'écrire le code interne complet. La partie visuelle et événementielle du RAD permet de construire, de tester et de modifier rapidement l'interface.
Le principe général de conception est le suivant :
L'interface présente à l'utilisateur et pour chaque nouveau plan d'action, tous les choix admissibles pour le passage au plan d'action suivant. Ceci se traduira pour la saisie d'un texte par la présentation à l'utilisateur des symboles terminaux actuellement possibles pour construire son dialogue et au masquage de tous les autres. Nous introduisons ici la notion de plan d'action matérialisé par un ensemble d'états des objets de l'interface combiné avec des actions sur ces objets. |
Nous nous servons d'une grammaire
décrite par ses diagrammes syntaxiques pour spécifier les étapes
de passage d'un plan d'action à l'autre.
1.3 Utilisation du TAD grammaire graphique pour la saisie
Nous rappelons le TAD générique Diag de grammaire graphique déjà défini pour spécifier de façon abstraite et graphique les règles d'une C-grammaire.
TAD : Diag
utilise : VT, VN // les vocabulaires de la grammaire
opérations
:
t1 : à Diag
t2 : VT È VN à Diag
t3 : VN à Diag
t4 : VT È VN à Diag
t5 : (VT È VN)n à Diag
t6 : (VT È VN)2 à Diag
t7 : (VT È VN)2 à Diag
· : Diag x Diag à Diag
Axiomes :
· est associative (concaténation de diagrammes)
"tiÎ Diag (i ³1) / t1·ti = ti·t1(élément neutre)
ti(A)·tk(B) = ti(A)tk(B) (méthode
de construction des diagrammes)
Les opérateurs tk représentent pour notre interface des plans d'action élémentaires. Un plan d'action général est constitué d'une combinaison de plans d'action élémentaires.
Remarque :
Nous aurions pu aussi utiliser une autre propriété booléenne de masquage des TButton, la propriété " visible ". |
A partir d'un diagramme événementiel
général comme ci-dessous :
où
:
= entrée dans le
plan d'action tk = passer au plan d'action suivant |
action " " = " événement clic du bouton"
activation " " = " NomduBouton.enabled :=true "
désactivation " " = " NomduBouton.enabled :=false "
gestionnaire d'action
= gestionnaire d'événement Clic du bouton.
Propriété enabled :=true Propriété enabled :=false
(activable)
(inactivable)
2. Une méthode
de construction
Nous proposons une méthode de construction de plans d'action en suivant la syntaxe d'une grammaire LL(1). Nous associons des diagrammes événementiels et des schémas de plan d'action algorithmique aux diagrammes syntaxiques de la grammaire. L'implantation des plans d'action sera exécutée en Delphi. |
Cette traduction est valide
pour des éléments A ÎVTet B ÎVT . L'élément " Suite " (associé
à la règle vide) représente un événement
permettant de passer d'un plan d'action au suivant sans avoir de choix terminal
à proposer à l'utilisateur.
Diagramme de règle
|
Diagramme événementiel
associé |
Au moment où le plan d'action t1 est exécuté, le bouton est activé. Une action clic appelle le gestionnaire de l'événement clic du bouton suite.
Le code du gestionnaire du bouton suite est :
Suite.enabled :=false ; {le
bouton se désactive}
AfficherPlanSuivant ; {exécution
du plan suivant}
Diagramme de règle
|
Diagramme événementiel
associé |
Au moment où le plan d'action t2 est exécuté, le bouton est activé. Une action clic appelle le gestionnaire de l'événement clic du bouton A.
Le code du gestionnaire du bouton A est :
A.enabled :=false ;
{le bouton se désactive}
Saisie(A) ; {saisie
de l'information}
AfficherPlanSuivant ;
{exécution du plan suivant}
Diagramme de règle
|
Diagramme événementiel
associé |
Au moment où le plan
d'action t3 est exécuté, le bouton
est activé, le bouton
n'est pas activé.
Une action clic sur le bouton A appelle le gestionnaire de l'événement clic du bouton A.
Suite.enabled :=false ; {le bouton se désactive}
A.enabled :=false ; {bouton
A désactivé}
AfficherPlanSuivant ; {exécution
du plan suivant}
Le code du gestionnaire du bouton A est :
Suite.enabled :=true ; {bouton
suite activé}
Saisie(A) ; {saisie de l'information}
Diagramme de
règle
|
Diagramme événementiel
associé |
Au moment où le plan
d'action t4 est exécuté, le bouton
est activé, le bouton
est activé aussi.
Suite.enabled :=false ; {le bouton se désactive}
A.enabled :=false ; {bouton
A désactivé}
AfficherPlanSuivant ; {exécution
du plan suivant}
Le code du gestionnaire du bouton A est :
Suite.enabled :=true ; {bouton
suite activé}
Saisie(A) ; {saisie de l'information}
Diagramme de règle
t5(A1,...,An) =
|
Diagramme événementiel
associé |
Au moment où le plan
d'action t5 est exécuté, les boutons
,...,
sont activés.
DésactiverTous; {tous les boutons sont désactivés}
...etc...
Opérateur t6
:
Diagramme de règle
t6(A,B)=
|
Diagramme événementiel
associé |
Au moment où le plan d'action t6 est exécuté, le bouton est activé, les boutons et ne sont pas activés.
Une action clic sur le bouton A appelle le gestionnaire de l'événement clic du bouton A qui agit sur suite et B. Une action clic sur le bouton B appelle le gestionnaire de l'événement clic du bouton B qui agit sur A et suite. Une action clic sur le bouton suite appelle le gestionnaire de l'événement clic du bouton suite qui agit sur A et B.
Suite.enabled :=false ; {le bouton se désactive}
A.enabled :=false ; {bouton A désactivé}
B.enabled :=false ; {bouton
B désactivé}
AfficherPlanSuivant ; {exécution
du plan suivant}
Le code du gestionnaire du bouton A est :
Suite.enabled :=true ; {bouton suite activé}
B.enabled :=true ; {bouton B activé}
A.enabled :=false ; {bouton
A désactivé}
Saisie(A) ; {saisie de l'information
de A}
Le code du gestionnaire du bouton B est :
Suite.enabled :=false ; {bouton suite activé}
B.enabled :=false ; {bouton B activé}
A.enabled :=true ; {bouton
A désactivé}
Saisie(B) ; {saisie de l'information
de B}
Diagramme de règle
t7(A,B)=
|
Diagramme événementiel
associé |
Au moment où le plan d'action t7 est exécuté, les boutons , et sont activés.
Une action clic sur le bouton A appelle le gestionnaire de l'événement clic du bouton A. Une action clic sur le bouton B appelle le gestionnaire de l'événement clic du bouton B. Une action clic sur le bouton suite appelle le gestionnaire de l'événement clic du bouton suite qui agit sur A et B.
Suite.enabled :=false ; {le bouton se désactive}
A.enabled :=false ; {bouton A désactivé}
B.enabled :=false ; {bouton
B désactivé}
AfficherPlanSuivant ; {exécution
du plan suivant}
Le code du gestionnaire du bouton A est :
Saisie(A) ; {saisie de l'information de A}
Le code du gestionnaire du bouton B est :
Saisie(B) ; {saisie de l'information
de B}
Nous nous préoccupons maintenant des plans associés à des éléments du vocabulaire non terminal VN de notre grammaire supposée être LL(1).
Le passage d'un plan d'action
à un autre est conditionné par les symboles de Vt
qui doivent être présentés à l'utilisateur dans
le nouveau plan d'action. Or nous savons que l'ensemble Init(A) de l'élément
A de VN d'une grammaire nous fournit tous les symboles possibles
d'un plan d'action associé à l'élément A. Puis
nous ferons fonctionner notre grammaire en mode générateur.
Au lieu d'engendrer aléatoirement des phrases du langage nous engendrons
des phrases correctes où les choix des éléments terminaux
ont été effectués par l'utilisateur. En partant de cette
remarque, nous pouvons construire des schémas généraux
écrits en langage d'algorithme (LDFA) décrivant le fonctionnement
d'un plan d'action associé à un élément A,A Î VN.
Le tableau avec ses objets et outils de base :
Nous supposons disposer d'un
moyen d'activer (présenter à l'utilisateur) tous les symboles
de Init(A) afin de ne lui laisser que ces choix possibles : Activer(Init(A)).
Nous supposons disposer d'un
moyen de désactiver tous les symboles de Init(A) dès que l'utilisateur
a fait son choix : Désactiver(Init(A)).
Le symbole suite a la
même signification qu'au paragraphe précédent, il sert
à passer au plan d'action suivant.
Le symbole action indique
quelle est l'action que vient d'effectuer l'utilisateur sur l'interface.
Diagramme de règle | Schéma LDFA associé |
Opérateur t2 :
Plan A ; Désactiver(Init(A)) |
Activer(Init(A))
Répéter Plan A ; Activer(Init(Suite)) jusquà action = Suite ; Désactiver(Init(A)) |
Opérateur t4 :
Activer(Init(A))
; Activer(Suite) ;
Tantque action ¹ Suite faire Plan A ; Activer(Suite) Ftant ; Désactiver(Init(A)) |
t5(A1,...,An)
= |
Activer(Init(A1));
Activer(Init(A2)) ; .... si action Î Init(A1) alors Plan A1 sinon si action Î Init(A2) alors Plan A2 sinon si .... fsi ; Désactiver(Init(A1)) ; .... |
t6(A,B)= |
répéter
Activer(Init(A)) ; Plan A ; Activer(Init(B)) ; Activer(Init(Suite)) ; si action Î Init(B) alors Plan B fsi jusquà action = Suite |
t7(A,B)=
|
Activer(Init(A))
; Activer(Init(B)) ; Activer(Suite) ; Tantque action Î Init(B)ÈInit(A) faire si action Î Init(B) alors Plan B sinon Plan A fsi ; Activer(Init(A)) ; Activer(Init(B)) ; Activer(Suite) ; Ftant ; |
Application à un exemple |
Soit la grammaire G déjà vue lors de l'étude des First et des Follow :
axiome: S
|
Règles : |
Activer(a) ; |
Activer(a) ; |
Implantation en Delphi
procedure Activer(Elt:TButton);
begin Elt.enabled:=true; end; |
procedure Desactiver(Elt:TButton);
begin Elt.enabled:=false; end; |
procedure AttenteSaisie;
begin if not ActionFaite then begin repeat Application.ProcessMessages until ActionFaite ; ActionFaite:=false end end{Attendre}; procedure saisie(ch:string);
Attendre; saisie(SymLu); end{AttenteSaisie}; |
procedure
Plan_A; begin with Form1 do begin Activer(Button_a); Activer(Button_b); AttenteSaisie; if SymLu='a' then Desactiver(Button_a) else begin Desactiver(Button_b); Plan_S; Plan_A end; Desactiver(Button_a); Desactiver(Button_b) end end; |
procedure
Plan_S; begin with Form1 do begin Activer(Button_a); Activer(Button_b); AttenteSaisie; if SymLu='a' then begin Desactiver(Button_a); Plan_A; Plan_S end else Desactiver(Button_a); Desactiver(Button_b) end end; |
procedure TForm1.Button_aetbClic(Sender:
TObject); begin ActionFaite:=true; Symlu:=TButton(Sender).caption end; |
procedure TForm1.ButtonLancerClic(Sender:
TObject); begin RAZTout; ButtonLancer.enabled:=false; Plan_S; PlanSuivant; end; |
procedure PlanSuivant;
begin Form1.ButtonLancer.enabled:=true; end; |
2.3 Interface de saisie du mini-français
Delphi.PlanAction
PlanGF2.dlfi
Nous fournissons ici uniquement l'énoncé et les choix principaux de l'exemple, il est entièrement traité sur le CD.
La grammaire choisie est la grammaire
LL(1) GF2 du mini-français déjà étudiée.
VT ={le, un, chat, chien, aime, poursuit, malicieusement, joyeusement, gentil, noir, blanc, beau, '.'} |
VN = { á phraseñ, á GN ñ, áGVñ, á Artñ, á Nom ñ, á Adjñ, á Adv ñ, áverbeñ, á LeNom ñ, á Suite ñ } |
1 :á phrase ñ ® á GN ñ á
GV ñ.
2 :á
GN ñ
® á
Art ñ á
LeNom ñ
3 :á
LeNom ñ ® á Adj ñ á Nom ñ | á Nom ñ á
Adj ñ
4 :á
GV ñ
® á
verbe ñ
á Suite
ñ
5 :á
Suite ñ
® á
GN ñ | á Adv ñ á
GN ñ
6 :á
Art ñ ® le | un
7 :á
Nom ñ
® chien | chat
8 :á
verbe ñ
® aime | poursuit
9 :á
Adj ñ ® blanc | noir | gentil | beau
10 :á
Adv ñ
® malicieusement | joyeusement
Afin que le lecteur puisse bien
se pénétrer de la similitude des démarches entre les
blocs d'analyse du chapitre " analyser des phrases " et la saisie par plan
d'action, nous lui livrons ci-dessous deux plans et les blocs correspondants.
Il lui est demandé de construire les autres plans d'action sur le même
modèle et ensuite d'implanter son interface de saisie.
Bloc Analyser Phrase :
si
SymLuÎ Init(GN) alors |
Plan phrase
Activer(Init(Phrase)); Plan GN ; Plan GV ; Plan point Désactiver(Init(Phrase)) ;
|
l'implantation en Delphi est immédiate :
procedure Plan_phrase;
begin Plan_GN; Plan_GV; Plan_point; end; |
Bloc Analyser LeNom :
si SymLu Î
Init(Adj) alors
|
Plan LeNom Activer(Init(LeNom)); |
l'implantation en Delphi est immédiate :
procedure Plan_LeNom;
begin
...etc
end;
Code Delphi7 complet de l'exemple-2 Interface de saisie du mini-français
unit UFplanGF2 ;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons ;
type
TFPPlanGF2 = class (TForm)
ButtonLe : TButton ;
ButtonUn : TButton ;
Buttonblanc : TButton ;
Buttonnoir : TButton ;
Buttonbeau : TButton ;
Buttongentil : TButton ;
Buttonaime : TButton ;
Buttonpoursuit : TButton ;
Buttonchat : TButton ;
Buttonmalicieus : TButton ;
Buttonjoyeus : TButton ;
ButtonLancer : TButton ;
Edit_saisie : TEdit ;
Buttonchien : TButton ;
Buttonpoint : TButton ;
BitBtnFermer : TBitBtn ;
procedure ButtonLancerClick( Sender: TObject) ;
procedure ButtonsClick( Sender: TObject) ;
procedure FormCreate( Sender: TObject) ;
procedure BitBtnFermerClick( Sender: TObject) ;
private
{ Déclarations privées }
public
{ Déclarations publiques }
SymLu :string ;
ActionFaite , stop : boolean ;
procedure ActiverDesactiver(Elt : TButton ; const etat :boolean ) ;
procedure InitGN(active :boolean ) ;
procedure InitLeNom(active :boolean ) ;
procedure InitGV(active :boolean ) ;
procedure InitSuite(active :boolean ) ;
procedure InitArt(active :boolean ) ;
procedure InitNom(active :boolean ) ;
procedure InitVerbe(active :boolean ) ;
procedure InitAdj(active :boolean ) ;
procedure InitAdv(active :boolean ) ;
procedure RAZTout ;
procedure AttenteSaisie ;
procedure PlanSuivant ;
procedure Plan_Art ;
procedure Plan_Nom ;
procedure Plan_Verbe ;
procedure Plan_Adj ;
procedure Plan_Adv ;
procedure Plan_LeNom ;
procedure Plan_GN ;
procedure Plan_Suite ;
procedure Plan_GV ;
procedure Plan_point ;
procedure Plan_phrase ;
end;
var
FPPlanGF2 : TFPPlanGF2 ;
implementation
{$R *.dfm }
procedure TFPPlanGF2.ActiverDesactiver(Elt : TButton ;const etat :boolean ) ;
begin
Elt.enabled := etat ;
end;
//////////////////// LES INIT ///////////////////////////
procedure TFPPlanGF2.InitGN(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.ButtonLe,active) ;
ActiverDesactiver(FPPlanGF2.ButtonUn,active)
end;
procedure TFPPlanGF2.InitLeNom(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.Buttonblanc,active) ;
ActiverDesactiver(FPPlanGF2.Buttonnoir,active) ;
ActiverDesactiver(FPPlanGF2.Buttonbeau,active) ;
ActiverDesactiver(FPPlanGF2.Buttongentil,active) ;
ActiverDesactiver(FPPlanGF2.Buttonchat,active) ;
ActiverDesactiver(FPPlanGF2.Buttonchien,active)
end;
procedure TFPPlanGF2.InitGV(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.Buttonaime,active) ;
ActiverDesactiver(FPPlanGF2.Buttonpoursuit,active)
end;
procedure TFPPlanGF2.InitSuite(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.ButtonLe,active) ;
ActiverDesactiver(FPPlanGF2.ButtonUn,active) ;
ActiverDesactiver(FPPlanGF2.Buttonjoyeus,active) ;
ActiverDesactiver(FPPlanGF2.Buttonmalicieus,active)
end;
procedure InitArt(active :boolean ) ;
begin
InitGN(active)
end;
procedure TFPPlanGF2.InitNom(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.Buttonchat,active) ;
ActiverDesactiver(FPPlanGF2.Buttonchien,active)
end;
procedure TFPPlanGF2.InitVerbe(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.Buttonaime,active) ;
ActiverDesactiver(FPPlanGF2.Buttonpoursuit,active)
end;
procedure TFPPlanGF2.InitAdj(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.Buttonblanc,active) ;
ActiverDesactiver(FPPlanGF2.Buttonnoir,active) ;
ActiverDesactiver(FPPlanGF2.Buttonbeau,active) ;
ActiverDesactiver(FPPlanGF2.Buttongentil,active)
end;
procedure TFPPlanGF2.InitAdv(active :boolean ) ;
begin
ActiverDesactiver(FPPlanGF2.Buttonjoyeus,active) ;
ActiverDesactiver(FPPlanGF2.Buttonmalicieus,active)
end;
//////////////////// fin des INIT ////////////////////////
procedure TFPPlanGF2.RAZTout ;
begin
with FPPlanGF2 do
begin
InitArt(false) ;
InitNom(false) ;
InitVerbe(false) ;
InitAdj(false) ;
InitAdv(false) ;
Buttonpoint.Enabled := false ;
SymLu := '';
ActionFaite := false ;
Edit_saisie.text := '';
stop := false
end
end;
procedure TFPPlanGF2.AttenteSaisie ;
procedure Attendre ;
begin
if not ActionFaite then
begin
repeat
Application.ProcessMessages
until
actionfaite ;
ActionFaite := false
end
end { Attendre} ;
procedure saisie(ch :string ) ;
begin
if ActionFaite = false then
FPPlanGF2.Edit_saisie.text := FPPlanGF2.Edit_saisie.text + ' ' + ch
else
actionfaite := false
end {saisie} ;
begin
Attendre ;
saisie(SymLu) ;
end {AttenteSaisie} ;
procedure TFPPlanGF2.PlanSuivant ;
begin
FPPlanGF2.ButtonLancer.enabled := true ;
end;
{--------------- Les procédures des plans d'actions ----------------}
procedure TFPPlanGF2.Plan_Art ;
begin
InitArt(true) ;
AttenteSaisie ;
InitArt(false) ;
end;
procedure TFPPlanGF2.Plan_Nom ;
begin
InitNom(true) ;
AttenteSaisie ;
InitNom(false) ;
end;
procedure TFPPlanGF2.Plan_Verbe ;
begin
InitVerbe(true) ;
AttenteSaisie ;
InitVerbe(false) ;
end;
procedure TFPPlanGF2.Plan_Adj ;
begin
InitAdj(true) ;
AttenteSaisie ;
InitAdj(false) ;
end;
procedure TFPPlanGF2.Plan_Adv ;
begin
InitAdv(true) ;
AttenteSaisie ;
InitAdv(false) ;
end;
procedure TFPPlanGF2.Plan_LeNom ;
begin
InitLeNom(true) ;
AttenteSaisie ;
InitLeNom(false) ;
ActionFaite := true ; // action déjè saisie
if (SymLu = 'chat' ) or (SymLu = 'chien' ) then
begin
Plan_Nom ;
Plan_Adj
end
else // adjectif
begin
Plan_Adj ;
Plan_Nom
end;
end;
procedure TFPPlanGF2.Plan_GN ;
begin
Plan_Art ;
Plan_LeNom ;
end;
procedure TFPPlanGF2.Plan_Suite ;
begin
InitSuite(true) ;
AttenteSaisie ;
InitSuite(false) ;
ActionFaite := true ; // action déjè saisie
if (SymLu = 'le' ) or (SymLu = 'un' ) then
begin
Plan_GN ;
end
else // adverbe
begin
Plan_Adv ;
Plan_GN
end;
end;
procedure TFPPlanGF2.Plan_GV ;
begin
Plan_Verbe ;
Plan_Suite ;
end;
procedure TFPPlanGF2.Plan_point ;
begin
FPPlanGF2.Buttonpoint.Enabled := true ;
AttenteSaisie ;
FPPlanGF2.Buttonpoint.Enabled := false ;
end;
procedure TFPPlanGF2.Plan_phrase ;
begin
Plan_GN ;
Plan_GV ;
Plan_point ;
end;
procedure TFPPlanGF2.ButtonLancerClick( Sender: TObject) ;
begin
RAZTout ;
ButtonLancer.enabled := false ;
Plan_phrase ;
PlanSuivant ;
end;
procedure TFPPlanGF2.ButtonsClick( Sender: TObject) ;
begin
ActionFaite := true ;
if stop then
halt ; //l'utilisateur a demandé d'arrêter
Symlu := TButton( Sender ).caption
end;
procedure TFPPlanGF2.FormCreate( Sender: TObject) ;
begin
RAZTout ;
end;
procedure TFPPlanGF2.BitBtnFermerClick( Sender: TObject) ;
begin
stop := true
end;
end.