1. Préambule▲
Ce tutoriel concerne l'apprentissage de l'algorithmique principalement et, secondairement, l'utilisation de fonctions OOoBasic pour la manipulation d'objets, de variables et de fichiers dans une macro.
Je ne suis pas parti d'une équation que j'ai transcrite en code ; j'ai commencé par définir un ordre d'obtention des chiffres de la grille de sudoku puis j'ai recherché le code correspondant.
Je me suis limité à l'obtention d'une grille complète et délaissé l'effacement des cases nécessaire à l'obtention d'une grille incomplète, le but de l'occupation des joueurs de sudoku étant de compléter cette grille.
Également parce qu'il est très courant de tomber sur des grilles malsaines, dans le sens qu'il est facile d'effacer aléatoirement des cases de sudoku sans tenir compte de la possibilité de résoudre la grille. La résolution de grille tient quelques fois à pas grand chose, c'est là tout l'intérêt du jeu de sudoku.
Je me suis concentré sur le code nécessaire à l'obtention de la grille et j'ai fait l'impasse sur la gestion de fichiers et de feuilles de calcul.
Je programmerai pour un fichier de calcul, cela va de soi, calc en l'occurrence.
2. Stratégie de remplissage de la grille▲
L'obtention de l'ensemble de la grille doit être aléatoire afin d'obtenir une grande variété de résultats.
Je programmerai pour obtenir la première case en haut à gauche de la grille, puis les cases de la première ligne du haut jusqu'à la dernière case de droite. Ensuite je passerai à la ligne suivante, jusqu'à la dernière ligne.
Le plus important est de garder en mémoire les contraintes d'interaction entres les différentes cases de la grille de sudoku, qui sont biens connues, que je rappelle ici, pour que ce tutoriel soit complet :
Dans une grille sudoku :
contrainte 1 : chaque ligne comportant 9 cases doit être composée des chiffres 1 à 9
contrainte 2 : chaque colonne comportant 9 cases doit être composée des chiffres 1 à 9
contrainte 3 : chaque bloc comportant 9 cases doit être composé des chiffres 1 à 9

3. Choix de rédaction▲
Sans reprendre l'ensemble de l'apprentissage nécessaire au démarrage de la rédaction du code, je liste ici les choix de rédaction, les fonctions et programmes nécessaire au code généré dans ce tutoriel :
- j'écrirai en minuscule ce qui me permet de clarifier le code et de simplifier l'écriture
- j'écrirai en majuscule la première lettre des déclarations, des noms des objets, les lettre majuscules des propriétés, méthodes ou interface(selon l'usage proposé par la documentation et qui permet de les mémoriser facilement, voir les définitions : *)
- je n'utiliserai pas la coutume de mettre des « o » devant chaque nom d'objet, ce qui m'horripile ; je préfère utiliser des noms suffisamment expressifs
- J'utiliserai des noms de variable sur 3 lettres maximum, ce qui permet d'associer leur nom à leur caractère facétieux, volage voir désobligeant
- je rangerai les déclarations d'objets et de variables en début de code, dans la plupart des cas
- je n'utiliserai pas l'appel de Function, que je maîtrise pas
* https://wiki.openoffice.org/wiki/Extensions_development_basic_fr :
4. Présentation de l'API OpenOffice.org▲
Cette section introduit les termes :
- Interface
- Module
- Service
- Méthode
- Propriété
S'il n'est pas essentiel de comprendre la différence entre une interface et un service ou ce qu'est un module pour pouvoir écrire des extensions à OpenOffice.org, la compréhension de ces termes aide à correctement interpréter la documentation ainsi qu'à l'introspection des éléments manipulés. Peut-être nous faudra-t-il relire cette section plusieurs fois.
Une interface est la définition d'un ensemble de méthodes (avec leurs arguments) qu'un service implémentant cette interface doit comporter.
Les interfaces sont regroupées en modules pour des besoins de nommage. Toutes les interfaces (et les services) commencent par le nom "com.sun.star" puis vient le nom du module puis celui de l'interface (ou du service).
Une interface fournit l'accès aux propriétés d'un service.
Une propriété est une valeur tandis qu'une méthode définit une action.
Un objet OpenOffice.org peut supporter de nombreux services.
Un objet OpenOffice.org peut supporter un service qui implémente une interface dans laquelle une description de méthode déclare qu'un autre objet OpenOffice.org est retourné.
5. Commandes et déclarations minimum en OOoBasic▲
Pour un fichier calc, elles se limitent à :
2.
3.
4.
5.
6.
7.
Sub
Dim
Dok
as
object
Dok
=
ThisComponent
Dim
Feuille
as
object
Feuille
=
Dok
.
Sheets
.
getByIndex
(
0
)
.
.
.
end
Sub
le reste étant du code pour l'obtention de la grille sudoku.
Je travaille sur le fichier ouvert, donc je n'ai pas de gestion d'ouverture ou de fermeture de fichier à faire. Attention, bien s'assurer que c'est le fichier dans lequel vous avez créé votre code qui est actif lorsque vous lancez votre macro,sinon il n'y aura pas d'exécution correcte.
C'est la signification de Dok = ThisComponent : le fichier actif.*
Je travaille également sur la première feuille du fichier calc, je n'ai pas à gérer d'autre feuille de calcul.
C'est la signification de Feuille = Dok.Sheets.getByIndex(0). 0 étant le numéro de la première feuille.
J'utilise le nom d'objet « Dok » en respect et en l'honneur du programmateur russe qui l'utilisait dans un programme d'obtention d'une grille de sudoku qui m'a servi de modèle d'apprentissage.
* annexe A, page 859 Marcelly
ThisComponent
Représente l'objet document en cours ; il est en général équivalent à :
2.
Dim
Document
as
Object
Document
=
StarDesktop
.
CurrentComponent
Cependant, si l'EDI est en premier plan, CurrentComponent renverra l'EDI et la macro ne fonctionnera pas, alors que ThisComponent continue à renvoyer l'objet document.
C'est pourquoi ThisComponent est préférable.
Notez que ThisComponent n'est pas une variable, mais un appel de fonction:s'il y a plusieurs documents OpenOffice.org ouverts, elle renvoie le document OpenOffice.org dont la fenêtre est actuellement en avant-plan. C'est pourquoi il est préférable de ne l'appeler qu'au début de la macro et de sauver le résultat dans une variable interne.
6. Transcription d'un objectif en code▲
Le cap le plus important à passer, dans votre apprentissage, est la transcription de votre idée de traitement en code : l'algorithmique.
Par exemple, le tirage des chiffres de la grille de sudoku :
(→ signifie : opération suivante)
Je veux tirer au hasard un chiffre de 1 à 9 :
- → je range dans une boîte les 9 chiffres
→ je défini chacune de leur position par un numéro de 0 à 8
→ je tire au hasard un numéro entre 0 et 8 dans un sac
→ j'écris dans une case de la feuille calc le chiffre qui a le numéro tiré
→ j'enlève du sac le chiffre qui a été tiré, pour qu'il n 'apparaisse pas une seconde fois dans la grille sudoku
→ je tire au hasard à nouveau un numéro entre 0 et 8 dans le sac
→ j'écris à nouveau dans une case de la feuille calc le chiffre qui a le numéro tiré, la case étant la suivante à droite de la précédente, tel qu'il a été défini plus haut
→ j'enlève à nouveau du sac le chiffre qui a été tiré, pour qu'il n 'apparaisse pas une seconde fois dans la grille sudoku
→ je tire au hasard à nouveau et pour la troisième fois un numéro entre 0 et 8 dans un sac, …
Dans la suite de ce tutoriel, pour une meilleure compréhension et par convention, j'utiliserai le terme« numéro» pour désigner les cases de la boîte de rangement et le terme « chiffre » pour désigner les valeurs de la grille de sudoku.
Il m'a été aisé de rédiger cette suite d'opérations, car j'ai déjà réalisé la recherche du mode opératoire le plus adapté, après plusieurs essais, et surtout qui peut être transcrit en code.
La démarche de l'algorithmique est la suivante :
- définir un découpage opérationnel du processus
- identifier les outils de codage utilisables pour chaque opération
- rédiger en code chaque opération au fur et à mesure
- reprendre depuis le début s'il y a une impossibilité de rédaction du code
Cela nécessite de connaître les outils de codage ou de rechercher de nouveaux outils utilisés dans des exemples et de comprendre leur fonctionnement puis leur utilisation.
En OOoBasic, il y a 75 modules comportant chacun 6 types(par ordre α : constant group, enum, exception, interface, service, struct) (les interfaces commencent par .X), composés de 3531 méthodes ou propriétés, comportant chacune 6 types(par ordre α : attribute, constant, field, function, property, value) ce qui représente 16572 composants au total (environ, certains composants sont déclarés mais ne sont plus utilisées).
7. Quelques outils de codage et façons de faire utilisés▲
Á la lecture de l'exemple précédent, vous voyez que j'ai écrit « à nouveau » en italique ; c'est pour vous préparer à l'écriture d'une boucle.
7-A. La boucle de programme ou itération▲
C'est parce qu'il est plus intéressant d'écrire un code simple de quelques lignes, qu'une page répétitive de code et aussi parce que les processeurs ne s'ennuient jamais lorsqu'ils font des opérations répétitives.
Quelles sont les opérations répétées ?
...
- → je tire au hasard à nouveau un numéro entre 0 et 8 dans le sac
→ j'écris à nouveau dans une case de la feuille calc le chiffre qui a le numéro tiré, la case étant la suivante à droite de la précédente, tel qu'il a été défini plus haut
→ j'enlève à nouveau du sac le chiffre qui a été tiré, pour qu'il n 'apparaisse pas une seconde fois dans la grille sudoku
…
Cela forme un bloc d'opérations répétitives qui seront inclues dans la boucle.
Le principe de la boucle est que lorsque la dernière opération est effectuée, on reprend l'exécution au début de la boucle, c'est-à-dire à la première opération de la boucle.
L'itération sera effectuée tant que l'objectif n'est pas atteint, dans notre cas, tant que tous les chiffres de 1 à 9 n'ont pas été tirés.
Alors il faut compter le nombre d'exécutions de la boucle. C'est le rôle d'une variable.
7-B. Les variables▲
Elles prennent des valeurs temporelles, utiles pour l'exécution des opérations, puis sont renseignées à nouveau, ou s'effacent.
Dans mon cas, il me faut une variable qui compte chaque exécution, alors il suffit de la faire progresser d'une unité à chaque exécution, c'est-à-dire, inclure cette progression dans la boucle via une opération d'addition de 1 à la valeur de la variable en cours d'utilisation.
Les variables ne progressent pas forcément d'une unité, il est intéressant par exemple, de sauter une ligne dans un fichier, alors il suffit de faire progresser une variable de 2 unités, ou 3, ou de la faire diminuer pour reculer ou remonter dans un fichier.
Pour une utilisation correcte des variables, il faut déclarer leur type : est-ce un nombre, un texte, une date, une bascule oui/non ?
Dans notre cas, pour le comptage des exécutions de la boucle, ce doit être un nombre.
OOoBasic est assez souple, vous pouvez utiliser une variable sans la déclarer. OOoBasic est assez soupe au lait, si vous ne déclarez pas votre variable et que vous voulez l'utiliser dans différents programmes, vous aurez quelques surprises.
Il est préférable de faire une déclaration de variable, située avant son utilisation. Dans mon cas, j'effectue les déclarations en début de programme.
C'est aussi se préparer à l'apprentissage de langages plus exigeants.
7-C. Les déclarations▲
A l'intérieur d'un programme, les déclarations se font par l'outil « Dim ».
Si vous voulez utiliser une variable ou un objet dans plusieurs programmes, vous devez les déclarer « Public », c'est-à-dire, comme un lieu accessibles à tout le monde, accessible à tous les programmes, en dehors des programmes dont le programme principal.
Dans un premier temps, j'ai utilisé le déclaratif « Global », cela pourrait être imagé par « mondial », le monde entier peut utiliser mon programme, j'ai été peut-être un peu prétentieux (c'était mon « Hello World »).
Pourquoi je suis passé de déclarations « Dim », privées, à « Public », « locales » ?
Dans la rédaction du programme, je me suis rendu compte qu'une boucle était utile à différents endroits du programme, alors je les ai copiées/collées, puis j'en ai eu marre de faire une opération répétitive, alors j'ai écris cette boucle dans un programme que j'ai appelé depuis différents endroits du programme principal.
La conséquence a été que les variables et les objets utilisés dans le programme principal et les sous-programmes, pour être en adéquation d'état ou de valeur, devaient être connues par les différents programmes, donc être déclarées « Public »*.
* https://wiki.openoffice.org/wiki/FR/Documentation/BASIC_Guide/Scope_of_Variables
7-D. L'affectation▲
C'est l'opération qui permet :
- d'attribuer un contenu à une variable : valeur, texte, oui/non, ...
- d'attribuer un service ou une propriété à un objet
L'opérateur est le signe : = . Il fonctionne de la droite vers la gauche ; l'opérateur = attribue la valeur (ou autre) située à sa droite, à l'opérande situé à sa gauche.
Dok = ThisComponent : affectation de la propriété « fichier actif » à l'objet Dok.
7-E. Les sous-programmes▲
L'utilisation de sous-programmes est aussi intéressantes d'un point de vue de l'organisation du travail à effectuer. Il faut être ordonné pour être programmateur.
Un sous-programme correspond à une tâche, c'est intéressant pour la rédaction des opérations nécessaires à votre objectif, mais aussi, d'un point de vue intellectuel.
Lorsque vous travaillez sur un sous-programme, vous n'êtes pas perturbé par les autres éléments de votre programme principal.
Cela correspond aussi à la répartition des tâches et à la spécialisation dans l'organisation du travail.
7-F. Les exécutions conditionnelles▲
« Si tu me donnes un foret, je pourrai percer le mur ».
« Tant que je n'ai pas atteint l'autre côté du mur, je continue à percer ».
J'ai utilisé les outils d'exécution conditionnelle parce qu'à un moment donné, je devais attendre qu'un état soit atteint pour pouvoir continuer.
Par exemple, tant que l'ensemble des cases de la première ligne n'ont pas été tirées, je ne passe pas au tirage des cases de la deuxième ligne.
Vous remarquerez que j'utilise le présent, c'est-à-dire que la lecture de la condition se fait à l'instant t de l'exécution du programme.
La deuxième condition a été un cas d'écueil lorsque j'effectuais le tirage de la fin de la troisième ligne de la grille de sudoku. J'effectuais un tirage entre 3 chiffres restants qui devaient respecter les 3 contraintes de viabilité de la grille, alors le tirage était recommencé de façon interminable.
Je me suis rendu compte de cet écueil en affichant à l'écran le chiffre tiré.
7-G. La commande rnd()▲
C'est la commande qui permet le tirage au sort. Cette commande génère aléatoirement un chiffre en 0 et 1 à chaque utilisation. Sa programmation :
2.
3.
4.
.
.
.
randomize
Y
=
X
*
rnd
(
)
.
.
.
X est une valeur qui permet de « décoller » le résultat obtenu entre 0 et 1, c'est un facteur tout simplement, et donc d'affecter à Y une valeur représentative dans le programme.
La commande randomize() est à déclarer avant l'utilisation de la commande rnd().
Description de ces deux commandes :
http://christianwtd.free.fr/index.php?rubrique=BasFonction04
Bravo Christian, c'est très bien résumé. Un site très intéressant et bien fait.
J'ai ajouté une valeur entre les parenthèses de la fonction rnd(): rnd(sqr(5)) afin d'obtenir une meilleure répartition aléatoire.
Voici les statistiques de cette commande :
Je trouve cette fonction déséquilibrée. Elle a une tendance répétitive, liée à l'instant t du démarrage du programme.
Si vous lancez les tirages dans une boucle, comme je l'ai réalisé, le résultat est homogène. Si vous faites plusieurs exécutions indépendantes, le résultat est aléatoire. Surprenant !
L'autre possibilité est que je ne sache pas l'utiliser.
Voici le programme que j'ai utilisé pour obtenir le graphique ci-dessus :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
REM
*****
BASIC
*****
rem
-----
Déclarations
----------------------------------------------------------------------
Public
document
as
object
Public
a
as
integer
Public
lim
as
integer
Global
x
as
integer
rem
-----
Déclarations
pour
impression
---------------------------------------------------
Public
col
as
integer
'
numéro
de
la
colonne
en
cours
pour
impression
Public
lig
as
integer
'
numéro
de
la
ligne
en
cours
pour
impression
Public
compt
as
integer
'
compteur
d'exécution
Public
col_tt
as
integer
'
numéro
de
la
colonne
en
cours
pour
impression
totaux
Public
lig_tt
as
integer
'
numéro
de
la
ligne
en
cours
pour
impression
totaux
rem
-----
Programme
------------------------------------------------------------------------
Sub
lancement
x
=
0
for
u
=
0
to
10
'
correspond
au
facteur
de
10
000
boucles
:
10
pour
100
000
boucles
col
=
2
lig
=
4
compt
=
0
compt_max
=
1000
for
t
=
0
to
9
for
compt
=
0
to
compt_max
-
1
print_compt
Fonction_rnd
aprint_a
next
col
=
col
+
1
lig
=
4
next
aprint_graph
next
end
Sub
Sub
Fonction_rnd
randomize
lim
=
8
a
=
lim
*
rnd
(
sqr
(
5
)
)
end
Sub
rem
-----
Impression
-------------------------------------------------------------------------
Sub
print_compt
document
=
ThisComponent
Feuille
=
document
.
Sheets
.
getByIndex
(
0
)
Feuille
.
getCellByPosition
(
0
,
0
)
.
value
=
u
Feuille
.
getCellByPosition
(
2
,
0
)
.
value
=
compt
Feuille
.
getCellByPosition
(
col
,
2
)
.
value
=
a
end
Sub
Sub
aprint_a
Set
document
=
ThisComponent
Feuille
=
document
.
Sheets
.
getByIndex
(
0
)
Feuille
.
getCellByPosition
(
col
,
lig
)
.
value
=
a
lig
=
lig
+
1
end
Sub
Sub
aprint_graph
col_tt
=
14
lig_tt
=
3
+
x
document
=
ThisComponent
Feuille
=
document
.
Sheets
.
getByIndex
(
0
)
Feuille
.
getCellByPosition
(
col_tt
,
2
)
.
string
=
"
0
"
Feuille
.
getCellByPosition
(
col_tt
+
1
,
2
)
.
string
=
"
1
"
Feuille
.
getCellByPosition
(
col_tt
+
2
,
2
)
.
string
=
"
2
"
Feuille
.
getCellByPosition
(
col_tt
+
3
,
2
)
.
string
=
"
3
"
Feuille
.
getCellByPosition
(
col_tt
+
4
,
2
)
.
string
=
"
4
"
Feuille
.
getCellByPosition
(
col_tt
+
5
,
2
)
.
string
=
"
5
"
Feuille
.
getCellByPosition
(
col_tt
+
6
,
2
)
.
string
=
"
6
"
Feuille
.
getCellByPosition
(
col_tt
+
7
,
2
)
.
string
=
"
7
"
Feuille
.
getCellByPosition
(
col_tt
+
8
,
2
)
.
string
=
"
8
"
Feuille
.
getCellByPosition
(
col_tt
-
1
,
3
+
x
)
.
value
=
x
for
col
=
2
to
11
for
lig
=
4
to
1003
e
=
Feuille
.
getCellByPosition
(
col
,
lig
)
.
value
Select
case
e
case
0
Feuille
.
getCellByPosition
(
col_tt
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
,
lig_tt
)
.
value
+
1
case
1
Feuille
.
getCellByPosition
(
col_tt
+
1
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
1
,
lig_tt
)
.
value
+
1
case
2
Feuille
.
getCellByPosition
(
col_tt
+
2
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
2
,
lig_tt
)
.
value
+
1
case
3
Feuille
.
getCellByPosition
(
col_tt
+
3
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
3
,
lig_tt
)
.
value
+
1
case
4
Feuille
.
getCellByPosition
(
col_tt
+
4
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
4
,
lig_tt
)
.
value
+
1
case
5
Feuille
.
getCellByPosition
(
col_tt
+
5
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
5
,
lig_tt
)
.
value
+
1
case
6
Feuille
.
getCellByPosition
(
col_tt
+
6
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
6
,
lig_tt
)
.
value
+
1
case
7
Feuille
.
getCellByPosition
(
col_tt
+
7
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
7
,
lig_tt
)
.
value
+
1
case
8
Feuille
.
getCellByPosition
(
col_tt
+
8
,
lig_tt
)
.
value
=
Feuille
.
getCellByPosition
(
col_tt
+
8
,
lig_tt
)
.
value
+
1
end
select
next
next
x
=
x
+
1
end
sub
Pour info, voici le code source en C des deux fonctions randomize et rnd de OpenOffice, issu du site opengrok :
http://opengrok.adfinis-sygroup.org/source/xref/aoo-AOO34/main/basic/source/runtime/methods.cxx#3354
3339RTLFUNC
(
Randomize
)
3340
{
3341
(
void
)
pBasic
;
3342
(
void
)
bWrite
;
3343
3344
if
(
rPar
.
Count
(
)
>
2
)
3345
OOoBasic
:
:
Error
(
SbERR_BAD_ARGUMENT
)
;
3346
sal_Int16
nSeed
;
3347
if
(
rPar
.
Count
(
)
=
=
2
)
3348
nSeed
=
(
sal_Int16
)
rPar
.
Get
(
1
)
-
>
GetInteger
(
)
;
3349
else
3350
nSeed
=
(
sal_Int16
)
rand
(
)
;
3351
srand
(
nSeed
)
;
3352
}
3353
3354RTLFUNC
(
Rnd
)
3355
{
3356
(
void
)
pBasic
;
3357
(
void
)
bWrite
;
3358
3359
if
(
rPar
.
Count
(
)
>
2
)
3360
OOoBasic
:
:
Error
(
SbERR_BAD_ARGUMENT
)
;
3361
else
3362
{
3363
double
nRand
=
(
double
)
rand
(
)
;
3364
nRand
=
(
nRand
/
(
double
)
RAND_MAX
)
;
3365
rPar
.
Get
(
0
)
-
>
PutDouble
(
nRand
)
;
3366
}
3367
}
7-H. La commande « Print »▲
J'utilise beaucoup cette fonction pour voir ce qui se passe dans le programme, pour faire une pause programme, donc une sortie possible en cas d'écriture d'une boucle infinie.
La fonction « Print » affiche dans une boîte de dialogue la valeur d'une variable ou de plusieurs variables et stoppe l'exécution du programme. Selon la réponse choisie, le programme s'arrête ou continue.
7-I. L'outil Aprint▲
Ce n'est pas une commande OOoBasic. C'est un de mes outils, un sous-programme en fait.
J'appelle Aprint, l'impression dans la feuille de calcul des variables à l'instant t, ce qui permet de rédiger un rapport d'exécution final, mais surtout en cours d'exécution.
Cela m'a permis de déboguer rapidement certaines anomalies de mes programmations.
J'ai regroupé dans un sous-programme, toujours dans la même logique d'économie de travail et d'organisation, l'impression (l'écriture dans la feuille de calcul) des variables du programme à un instant t :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
Sub
aprint
Dim
Dok
as
object
Set
Dok
=
ThisComponent
Dim
Feuille
as
object
Feuille
=
Dok
.
Sheets
.
getByIndex
(
0
)
Dim
col
as
integer
Dim
lig
as
integer
col
=
5
lig
=
3
Feuille
.
getCellByPosition
(
col
,
lig
)
.
string
=
"
Num()
"
col
=
col
+
2
Dim
i
as
integer
Dim
Num
(
8
)
as
integer
for
i
=
0
to
8
Feuille
.
getCellByPosition
(
col
,
lig
)
.
value
=
Num
(
i
)
col
=
col
+
1
next
end
Sub
Le système fait la différence entre le programme principal et ce sous-programme lors du lancement de ce dernier car il ne se nomme pas « main » ( principal) et n'est pas situé en première position dans l'éditeur.
Aide en ligne de OpenOffice : Un clic sur l'icône Exécuter le programme BASIC de la barre de macro permet d'exécuter le programme à partir de la première ligne de l'éditeur Basic. Le programme exécute le premier Sub ou Function puis l'exécution du programme s'interrompt. L'instruction Sub Main n'est pas prioritaire sur l'exécution du programme.
8. Un premier code▲
Vous retrouvez dans le programme ci-dessus, 4 des outils de codage et façons de faire que je vous ai présentés ci-dessus :
- la boucle
- les variables
- la déclaration
- l'affectation
8-A. Détaillons ce programme :▲
2.
3.
4.
Sub
aprint
Dim
Dok
as
object
Dok
=
ThisComponent
…
Vous le savez , il s'agit des déclarations minimum en OOoBasic pour travailler avec une feuille de calcul. Vous retrouverez end Sub en fin de programme, évidemment.
2.
3.
4.
…
Dim
Feuille
as
object
Feuille
=
Dok
.
Sheets
.
getByIndex
(
0
)
…
Je déclare ensuite que l'objet Feuille puis déclare qu'elle représente la première (numéro : 0) feuille de calcul de l'objet Dok, le fichier actif.
Attention : toujours penser à démarrer la numérotation par 0. Afin d'avoir une uniformité intellectuelle de numérotation, je démarre aussi la numérotation des boucles par 0, ce qui évite des maux de tête.
Afin de simplifier cette description de programme, j'ai regroupé les déclarations et les affectations dans la même partie du code.
2.
3.
4.
5.
6.
7.
…
Dim
col
as
integer
Dim
lig
as
integer
col
=
5
lig
=
3
…
Donc il y a deux déclarations correspondant aux deux variables qui vont représenter la ligne et la colonne permettant de trouver la cellule de la feuille de calcul, dans laquelle je veux écrire un nom ou une valeur de variable.
Vous remarquerez que je ne me suis pas cassé la tête pour trouver un nom de variable représentant le numéro de colonne et de ligne.
Puis, j'affecte une valeur à chacune des variables qui correspondent à la cellule : F4, dans la quelle je souhaite démarrer la rédaction du rapport d'exécution, à chaque exécution.
2.
3.
…
Feuille
.
getCellByPosition
(
col
,
lig
)
.
string
=
"
Num()
"
…
J'appelle la méthode .getCellByPosition(colonne, ligne) de l'interface .XcellRange*, que j'applique à l'objet Feuille, représentant la feuille de calcul, dans notre cas.
* https://www.openoffice.org/api/docs/common/ref/com/sun/star/table/XCellRange.html
« Description : provides access to the cells or to Sub-ranges of a cell range. »
L'interface n'a pas notion qu'il s'agit d'une feuille de calcul, elle autorise l'accès à une cellule d'un groupe de cellules.
C'est ce qui m'émerveille dans la programmation objet, cet espèce de dilettantisme, d'anonymat plutôt confortable, il faut le dire.
J'aurais utilisé la méthode .getCellByName(Référencedecellule), qui ne me permet pas d'utiliser de variable représentant la position de cellule, par exemple :
Feuille.getCellByName(A1) : la première cellule en haut à gauche de la feuille de calcul.
C'est assez perturbant d'utiliser cette méthode ,car la numérotation des lignes commence par 1, ce qui est habituel lorsque l'on utilise un tableur mais qui devient inhabituel lorsque l'on démarre l'étude des macros.
Ensuite, je dois déterminer ce que je veux écrire dans cette cellule : quel est le contenu cette cellule ?
Est-ce une valeur ? Une formule ? Quel est son type ? Est-ce une valeur d'erreur ?
Le contenu d'une cellule est géré par l'interface .Xcell :
* https://www.openoffice.org/api/docs/common/ref/com/sun/star/table/XCell.html
« Description : provides methods to access the contents of a cell in a table. »
En premier, ne pas oublier le point « . »entre la méthode et son type.
Dans mon cas , je veux écrire dans la cellule, un titre qui informera du nom des variables, un texte donc (string) :
Feuille.getCellByPosition(col, lig).string
Je viens de définir entièrement la cellule dans laquelle je veux écrire, et j'ai déterminé le genre de contenu que j'écrirai. Il me reste à lui affecter [une valeur, un texte,oui/non,...], dans mon cas un texte :
Feuille.getCellByPosition(col, lig).string = "Num()"
C'est un texte, alors il faut le déclarer entre guillemets : " … " . L'éditeur reconnaît bien que c'est un texte car il est affiché en rouge.
2.
3.
…
col
=
col
+
2
…
Pour des questions de présentation, je souhaite sauter deux colonnes de cellules dans mon rapport, alors j'ajoute la valeur 2 à la valeur de la colonne à cet instant t.
J'aurais pu écrire :
col = 7
puisque sa valeur précédente était 5, mais, j'ai prévu d'utiliser ce sous-programme plusieurs fois, correspondant à différentes cellules donc à différentes valeur de colonne, alors j'effectue une addition « relative » : j'ajoute la valeur 2 à la valeur temporaire de col.
Affecter la valeur 7 à la variable col est similaire à un déplacement absolu de l'index dans la feuille de calcul.
Ajouter la valeur 2 à la valeur temporaire de col est similaire à un déplacement relatif de l'index dans la feuille de calcul. L'index passe à la cellule : H4.
8-B. Vient ensuite :▲
2.
3.
…
Dim
i
as
integer
…
C'est une déclaration de variable de type entière. Cette variable est utilisée dans la déclaration de la boucle et effectuera le comptage du nombre de boucles effectuées.
Déclaration de la boucle :
2.
3.
for
i
=
0
to
8
…
next
Le commande for...next se déclare sur deux lignes qui encadrent les commandes à répéter.
Le fonctionnement est le suivant : l'initialisation de la boucle de programme est déclarée par la commande : for i = 0 …
Puis, à chaque fois que l'exécution du programme arrive à la commande next , i est augmenté de la valeur 1, jusqu'à atteindre le maximum fixé par la commande : for … to 8 .
Ce qui nous fait au total : 9 valeurs correspondant à la totalité des numéros (de 0 à 8) de position dans la boîte de rangement des 9 chiffres.
La variable i a une double fonction :
- compter le nombre d'exécutions ;
- lister les valeurs des numéros de position dans la boîte de rangement.
Comment gérer dans le programme, les numéros 0 à 8 de position dans la boîte de rangement ?
Par 8 variables ? C'est faisable.
Par une matrice : une variable matrice. C'est plus simple à gérer et plus « préhensible ».
https://wiki.openoffice.org/wiki/FR/Documentation/BASIC_Guide/Arrays
8-C. La variable matrice▲
La déclaration de la variable matrice :
2.
3.
…
Dim
Num
(
8
)
as
integer
…
Vous voyez apparaître des parenthèses à la suite du nom de la variable, entre lesquelles est inscrit une valeur.
Cette valeur représente le nombre maximum de zones mémoires d'enregistrement à l'instant t de la matrice : 8.
C'est-à-dire :
0, 1, 2, 3, 4, 5, 6, 7, 8 : nous avons bien 9 zones mémoires qui correspondent aux 9 positions attendues.
Une variable matrice est définie comme ceci :
- sa dimension est définie par la valeur d'index de la dernière zone mémoire, entre parenthèses, à la suite de son nom
- ses zones mémoires sont accessibles par leur valeur d'index
- la valeur du premier index est 0
L'affectation d'une variable matrice se rédige comme ceci :
Num() = array(9,8,7,6,5,4,3,2,1)
Indexes de la matrice : 0, 1, 2, 3, 4, 5, 6, 7, 8
Le terme array signifie matrice. Le nombre de valeurs saisies doit correspondre au nombre déterminé lors de la déclaration de la variable, voir ci-dessus.
L'accès à une zone mémoire de la matrice, se fait par le numéro d'index :
Num(1) = 0
alloue la valeur 0 à la deuxième case de la matrice :
Num() = array(9,0,7,6,5,4,3,2,1)
Une variable simple peut prendre une infinité de valeur au cours de l'exécution d'un programme mais une seule à l'instant t.
Une variable matrice peut prendre une infinité de valeur au cours de l'exécution d'un programme mais autant que sa déclaration le permet à l'instant t.
Je pourrais déclarer 9 variables simples à la place de la variable matrice, mais déjà, je dois rédiger 9 déclarations, donc 9 lignes de programme supplémentaires. Imaginez si je souhaitais enregistrer 150 valeurs !
8-D. La boucle comporte deux lignes de commande :▲
Dans la première, je veux écrire les valeurs, donc (value), de la variable Num() à chaque exécution :
Feuille.getCellByPosition(col, lig).value = Num(i)
Num(i) est écrit en noir dans l'éditeur, donc c'est l'appel d'une entité connue par le programme et non plus un texte qui sera enregistré dans une cellule de la feuille de calcul.
C'est ici que l'on retrouve la deuxième fonction de la variable i : lister les valeurs de position dans la boîte de rangement.
À chaque exécution de la boucle, i prend une valeur qui va progresser de 1, ce qui permettra de lister l'ensemble des cases de Num(), de 0 à 8 par l'exécution des boucles de programme jusqu'à son terme.
Cette commande fait appel également aux variables col et lig .
Lors de la première exécution de la boucle, les valeurs de ces variables sont celles correspondantes à l'affectation précédente :
col = 5
lig = 3
Si je ne fais pas évoluer l'une de ces variables, les 9 valeurs de Num(i) vont s'enregistrer dans la même cellule. Alors je ne verrai rien !
C'est l'intérêt de la deuxième ligne de commande de la boucle :
col = col + 1
Comme je l'ai expliqué ci-dessus, il s'agit d 'un déplacement relatif de l'index dans la feuille de calcul.
Après chaque enregistrement via la commande de la première ligne de la boucle, la variable col représentant la valeur de colonne de l'enregistrement glisse d'un pas vers la droite : H4, I4, J4,K4, L4, M4, N4, O4, P4.
Ce qui me permet d'obtenir le résultat suivant :

Enfin, la commande :
…
end Sub
permet de déclarer la fin du programme.
Aide en ligne de OpenOffice :
Instruction end [Exécution]
Indique la fin d'une procédure ou d'un bloc.
Syntaxe :
end, end Function, end if, end Select, end Sub
Paramètres :
Utilisez l'instruction end comme suit :
Instruction
end : non obligatoire, mais peut être saisie n'importe où dans une procédure afin de mettre fin à l'exécution du programme.
end Function : marque la fin d'une instruction Function.
end if : marque la fin d'un bloc if...Then...else.
end Select : marque la fin d'un bloc Select Case.
end Sub : marque la fin d'une instruction Sub.