I. Présentation▲
XPCE n'est pas Prolog mais permet d' utiliser Prolog (en l'occurence SWI-Prolog)
dans des programmes avec des fenêtres ou des boîtes de dialogue.
XPCE possède un utilitaire pour les créations de boîtes de dialogue, il permet d'utiliser des contrôles
prédéfinis, on sait moins qu'on peut définir ses propres contrôles puis les insérer dans le code
des boîtes de dialogue créées à l'aide de l'utilitaire.
Le but de cet article est de décrire la création des contrôles de saisie d'une IP et d'un mot de passe
puis de montrer l'insertion de ces contrôles dans le code des boîtes de dialogue.
Les codes ont été testés avec la version 6.3.11 de la version 64 bits de SWI-Prolog.
I-1. Le "Key_binding"▲
Les contrôles de saisie d'une IP ou d'un mot de passe sont dérivés de la classe text_item.
Cette classe permet d'utiliser la classe key_binding qui analyse les évènements
clavier et souris et lance des actions en fonctions des touches pressées ou des clics effectués.
Un utilitaire très intéressant fournit par SWI-Prolog est XPCE Event-viewer qui permet de connaître
les noms des évènements clavier qui seront utilisés dans les key_bindings associés aux contrôles de saisie.
On peut voir sur cette image les évènements associés au curseur, ces évènements devront être traités
par le key_binding des contrôles. Les lettres et chiffres seront aussi traités.
Les évènements de touches doivent être reportés dans les buffers de saisie, qui sont de type "text". Les
actions correspondantes sont décrites dans l'utilitaire Class Browser à la classe text.
On peut voir ainsi que l'évènement clavier cursor_home devra être transformé en beginning_of_line pour le buffer de saisie, et l'évènement clavier end en end_of_line, etc, etc.
II. Création d'un contrôle de saisie d'une IP▲
II-1. Création de la classe "ip_item".▲
Ici on travaille directemement sur le buffer de saisie du text_item, il n'y pas besoin de créer un champ spécial comme ce sera nécessaire pour la création du contrôle de saisie du mot de passe, car ce qui est affiché est ce qui est saisi. La classe ip_item se décrit ainsi:
:-
pce_begin_class(
ip_item,
text_item,
"
saisie
d'une
ip
"
)
.
variable(
kb,
recogniser,
both,
"
gestionnaire
de
touches
"
)
.
initialise(
P,
Title)
:-
>
%
on
initialise
le
champ
de
saisie
send_super(
P,
initialise,
Title,
'
000.000.000.000
'
)
,
%
15
caractères
uniquement
send(
P,
width,
15
)
,
send(
P,
recogniser,
new(
KB,
key_binding(
@nil,
argument)
)
)
,
send(
P,
slot,
kb,
KB)
,
send(
P,
make_key_binding)
.
%
création
des
données
du
gestionnaires
de
touches
make_key_binding(
P)
:-
>
get(
P,
slot,
kb,
K)
,
%
¨Par
défaut,
tout
est
interdit
!
send(
K,
default_function,
alert)
,
%
on
n'autorise
que
les
chiffres
send_list(
P,
init_key_binding,
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
]
)
,
%
on
gère
maintenant
les
touches
reconnues
par
le
text_item
%
les
deux
"fonctions"
suivantes
doivent
être
écrites
send(
K,
function,
'
backspace
'
,
message(
P,
execute_backward)
)
,
send(
K,
function,
'
DEL
'
,
message(
P,
execute_del)
)
,
%
les
autres
sont
prédéfinies
send(
K,
function,
'
cursor_home
'
,
message(
P,
beginning_of_line)
)
,
send(
K,
function,
'
cursor_left
'
,
message(
P,
backward_char)
)
,
send(
K,
function,
'
cursor_right
'
,
message(
P,
forward_char)
)
,
send(
K,
function,
'
end
'
,
message(
P,
end_of_line)
)
,
%
ici
le
message
envoyé
"next"
est
un
message
de
fenêtre
%
on
passe
au
contrôle
suivant
send(
K,
function,
'
TAB
'
,
message(
P,
next)
)
,
send(
K,
function,
'
RET
'
,
enter)
.
%
programmation
des
touches
de
chiffres
init_key_binding(
P,
V)
:-
>
get(
P,
slot,
kb,
K)
,
atom_number(
AV,
V)
,
%
obtention
du
code
de
touche
Ascii is
V +
48
,
%
creation
du
key_binding
associé
au
chiffre
send(
K,
function,
AV,
message(
P,
execute_insert,
Ascii)
)
.
%
fonction
a
exécuter
lorsque
le
chiffre
est
tapé
execute_insert(
W,
V)
:-
>
%
celà
dépend
de
la
position
du
curseur
get(
W,
caret,
Pos)
,
%
est-on
sur
un
point
ou
en
fin
de
ligne
?
(
(
member(
Pos,
[
3
,
7
,
11
]
)
;
Pos >
14
)
->
(
Pos >
14
->
send(
W,
alert)
%
si
on
n'et
pas
en
fin
de
ligne
%
on
avance
d'un
caractère
;
send(
W,
forward_char)
,
%
et
on
reessaye
d'insérer
le
caractère
send(
W,
execute_insert,
V)
)
%
si
on
est
en
début
de
séquence
%
on
n'autorise
que
0
et
1
;
(
member(
Pos,
[
0
,
4
,
8
,
12
]
)
,
V >
50
)
->
send(
W,
alert)
%
sinon
on
efface
le
caractère
courant
;
send(
W,
delete_char)
,
%
et
on
insère
le
caractère
tapé
send(
W,
insert_self,
1
,
V)
)
.
%
on
a
appuyé
sur
la
touche
'BackSpace'
%
on
efface
le
caractère
à
gauche
du
curseur
execute_backward(
W)
:-
>
%
celà
dépend
de
la
position
du
curseur
get(
W,
caret,
Pos)
,
%
est-on
sur
un
point
?
(
member(
Pos,
[
4
,
8
,
12
]
)
%
oui
on
recule
simplement
->
send(
W,
backward_char)
%
sinon,
on
recule
en
effaçant
le
caractère
;
Pos >
0
->
send(
W,
backward_delete_char)
,
%
on
insere
un
0
send(
W,
insert_self,
1
,
48
)
,
%
et
on
revient
d'un
caractère
send(
W,
backward_char)
)
.
%
on
veut
effacer
le
caractère
à
droite
du
curseur
execute_del(
W)
:-
>
%
celà
dépend
de
la
position
du
curseur
get(
W,
caret,
Pos)
,
%
est-on
sur
un
point
?
(
member(
Pos,
[
3
,
7
,
11
]
)
%
inpossible
dans
ce
cas
->
send(
W,
alert)
%
on
efface
le
caractère
;
send(
W,
delete_char)
,
%
on
insere
un
0
send(
W,
insert_self,
1
,
48
)
,
%
et
on
revient
d'un
caractère
send(
W,
backward_char)
)
.
:-
pce_end_class(
ip_item)
.
II-2. Création du contrôle de saisie d'une IP▲
Supposons que nous ayons besoin d'une boîte de dialogue pour saisir une IP. On crée la boîte de dialogue en positionnant un text_item au bon endroit. Une fois glissé la boîte de dialogue dans le code du programme, on remplace simplement text_item par ip_item ! Code de la boîte de dialogue :
dialog(
ip,
[
object
:
=
Ip,
parts :=
[
Ip
:
=
dialog
(
'
Ip
'
)
,
Nom_item :=
text_item(
'
Votre
nom
'
)
,
IP_item :=
ip_item(
'
Votre
IP
'
)
,
Button :=
button(
ok)
],
modifications :=
[
]
,
behaviour :=
[
Button
:
=
[
message
:
=
message
(
@
pce
,
write_ln
,
Nom_item?selection,
'
a
pour
IP
'
,
IP_item?selection)
]],
layout :=
[
area
(
Nom_item
,
area(
50
,
10
,
253
,
24
)
)
,
area(
IP_item,
area(
50
,
50
,
253
,
24
)
)
,
area(
Button,
area(
86
,
86
,
50
,
24
)
)
]
])
.
La boîte de dialogue obtenue :
Le message associé au bouton Ok correspond plus ou moins au writeln de SWI-Prolog.
III. Création d'un contrôle de saisie de mot de passe.▲
III-1. Création de la classe "mdp_item"▲
Ici, ce qui est affiché n'est évidemment pas ce qui est saisi. De plus un test personnalisé
de contrôle de la validité du mot de passe est prévu, le nom du prédicat de test
(qui doit être d'arité 1) est passé en paramètre d'initialisation.
On n'autorise dans la saisie que les chiffres et les lettres majuscules ou minuscules.
La classe mdp_item se décrit ainsi:
:-
pce_begin_class(
mdp_item,
text_item,
"
saisie
de
mots
de
passe
"
)
.
variable(
kb,
recogniser,
both,
"
gestionnaire
de
touches
"
)
.
variable(
mdp,
string,
both,
"
mot
de
passe
saisi
"
)
.
variable(
test,
object,
both,
"
pour
verifier
que
le
mot
de
passe
est
acceptable
"
)
.
%
initialisation
sans
test
de
validité
de
mot
de
passe
%
on
passe
@nil
comme
prédicat
initialise(
P,
Title)
:-
>
send(
P,
initialise,
Title,
@nil)
.
%
initialisation
avec
test
de
validité
de
mot
de
passe
initialise(
P,
Title,
Passe)
:-
>
send_super(
P,
initialise,
Title)
,
string_to_list(
Lst,
"
"
)
,
send(
P,
slot,
mdp,
Lst)
,
send(
P,
slot,
test,
Passe)
,
send(
P,
recogniser,
new(
KB,
key_binding(
@nil,
argument)
)
)
,
send(
P,
slot,
kb,
KB)
,
send(
P,
make_key_binding,
KB)
.
make_key_binding(
P,
K)
:-
>
send(
K,
default_function,
alert)
,
%
les
codes
ASCII
des
majuscules
numlist(
65
,
90
,
Maj)
,
%
les
codes
ASCII
des
minuscules
numlist(
97
,
122
,
Min)
,
%
les
codes
ASCII
des
chiffres
numlist(
48
,
57
,
Chiffres)
,
append(
[
Maj
,
Min
,
Chiffres
]
,
Codes)
,
send_list(
P,
init_key_binding,
Codes)
,
%
les
touches
de
déplacement
send(
K,
function,
'
backspace
'
,
message(
P,
execute_backward)
)
,
send(
K,
function,
'
DEL
'
,
message(
P,
execute_del)
)
,
send(
K,
function,
'
cursor_home
'
,
message(
P,
beginning_of_line)
)
,
send(
K,
function,
'
cursor_left
'
,
message(
P,
backward_char)
)
,
send(
K,
function,
'
cursor_right
'
,
message(
P,
forward_char)
)
,
send(
K,
function,
'
end
'
,
message(
P,
end_of_line)
)
,
%
ici
le
message
envoyé
"next"
est
un
message
de
fenêtre
%
il
passe
au
controle
suivant
send(
K,
function,
'
TAB
'
,
message(
P,
next)
)
,
send(
K,
function,
'
RET
'
,
message(
P,
next)
)
.
init_key_binding(
P,
V)
:-
>
get(
P,
slot,
kb,
K)
,
atom_codes
(
Atm,
[
V
]
)
,
send(
K,
function,
Atm,
message(
P,
execute_insert,
Atm)
)
.
execute_insert(
P,
V)
:-
>
get(
P,
caret,
Pos)
,
get(
P,
slot,
mdp,
Str)
,
%
on
affiche
une
étoile
(code
ASCII
42)
send(
P,
insert_self,
1
,
42
)
,
%
on
insere
le
bon
caractère
dans
la
chaîne
en
mémoire
send(
Str,
insert,
Pos,
V)
.
execute_backward(
P)
:-
>
send(
P,
backward_char)
,
get(
P,
caret,
Pos)
,
%
on
efface
le
caractère
à
l'écran
send(
P,
delete_char)
,
get(
P,
slot,
mdp,
Str)
,
%
on
efface
le
caractère
correspondant
de
la
chaîne
send(
Str,
delete,
Pos,
1
)
.
execute_del(
P)
:-
>
get(
P,
caret,
Pos)
,
send(
P,
delete_char)
,
get(
P,
slot,
mdp,
Str)
,
send(
Str,
delete,
Pos,
1
)
.
%
verifie
la
validité
du
mot
de
passe
saisi
validate(
P)
:-
>
get(
P,
slot,
test,
Test)
,
(
Test \= @nil
->
get(
P,
slot,
mdp,
Passe)
,
get(
Passe,
value,
V)
,
(
%
le
mot
de
passe
est-il
valide
?
\+call(
Test,
V)
->
send(
@display,
inform,
'
Passe
incorrect
'
)
,
fail
;
true
)
;
true
)
.
:-
pce_end_class(
mdp_item)
.
III-2. Création d'une boîte de saisie de mot de passe.▲
La boîte de saisie doit vérifier que le mot de passe est valide. Si le mot de passe
est correct, il est retourné dans MDP, sinon un message d'erreur est affiché.
Si on clique sur la croix, ou abandon, la prédicat échoue.
Le code de la boîte de saisie est :
ask(
MDP)
:-
new(
D,
dialog(
'
Saisie
de
mot
de
passe
'
)
)
,
send(
D,
append(
new(
NameItem,
mdp_item(
'
Votre
mot
de
passe
'
,
my_test)
)
)
)
,
send(
D,
append(
button(
ok,
and(
message(
NameItem,
validate)
,
message(
D,
return,
NameItem?mdp?value)
)
)
)
)
,
send(
D,
append(
button(
abandon,
message(
D,
return,
@nil)
)
)
)
,
send(
D,
default_button(
ok)
)
,
get(
D,
confirm,
Rval)
,
free(
D)
,
Rval \== @nil,
MDP =
Rval.
%
le
mot
de
passe
doit
comporter
%
des
lettres
minuscules
%
des
lettres
majuscules
%
des
chiffres
my_test(
Passe)
:-
atom_codes
(
Passe,
Codes)
,
partition(
test_char,
Codes,
Chiffres,
Maj,
Min)
,
Chiffres \= [
]
,
Maj \= [
]
,
Min \= [
]
.
%
la
on
teste
les
chiffres
test_char(
Ch,
<
)
:-
Ch >=
48
,
Ch =<
57
.
%
la
on
teste
les
majuscules
test_char(
Ch,
=
)
:-
Ch >=
65
,
Ch =<
90
.
%
la
on
teste
les
minuscules
test_char(
Ch,
>
)
:-
Ch >=
97
,
Ch =<
122
.
Des renseignements sur partition/5 peuvent être trouvés
ici.
La boîte de dialogue obtenue :