Différences fondamentales entre VBA et OOo Basic : commandes et
Si les points examinés jusqu'ici étaient communs à la plupart des langages de programmation employés par les tableurs, en matière de commandes et de sélections il existe des divergences profondes entre les langages des deux produits servant d'exemple dans ce livre, c'est-à-dire le VBA d'Excel et le OOo Basic de Calc.
En VBA, tout est objet. Chaque objet (appartenant éventuellement à une collection) peut posséder des propriétés et des méthodes.
Les principales collections d'objets du tableur Excel sont WorkBooks (classeur), Sheets (feuille de calcul) et Range (cellules). Elles sont utilisables selon une hiérarchie descendante :
Veillez à ne pas confondre collection et objet membre d'une collection. Le nom d'une collection se termine par un « s ». Ainsi, Sheets est la collection de toutes les feuilles d'un classeur, Sheet est une feuille.
Une fois un objet désigné, vous pouvez :
Par exemple, si vous lancez l'enregistrement de la macro nommée TestGras, sélectionnez la plage A1:B5, puis cliquez sur le bouton Gras de la barre d'outil pour mettre les données de la sélection en gras, le code de la macro enregistrée sera le suivant :
Sub TestGras
(...)
Range("A1:B5").Select
Selection.Font.Bold = True
End Sub
Vous appliquez à un objet plage (Range) défini comme étant A1:B5 la méthode Select pour le sélectionner, puis fixez la valeur de la propriété Bold de la propriété Font de l'objet Selection (la sélection active) à True. Ce simple enregistrement vous a permis au passage de voir comment sélectionner une plage de cellules continues !
Les propriétés et méthodes d'un objet portent le nom de membres. L'éditeur VBA propose d'ailleurs deux dispositifs très intéressants, la liste des membres et l'Information rapide automatique, qui simplifient considérablement le travail de rédaction de code.
Vous avez peut-être remarqué, lors de la saisie d'instructions dans l'éditeur, l'apparition d'une boîte de liste déroulante, après la saisie d'un nom d'objet suivi par un point. C'est la liste de membres, qui affiche la liste des méthodes et propriétés de l'objet qui précède le point. Sélectionnez une méthode ou une propriété dans la liste en cliquant dessus ou en tapant quelques-unes des premières lettres de son nom, puis appuyez sur la barre Espace pour que l'éditeur place la sélection dans votre déclaration.
De même, lorsque vous saisissez un nom de fonction suivi d'une seule parenthèse (celle de gauche), l'Information rapide automatique affiche les arguments requis par cette fonction dans une info bulle. Cette aide réduit les risques d'erreur de syntaxe. Elle est disponible même pour des fonctions personnalisées créées par vous-même, comme le montre la figure suivante pour la fonction NbJours() créée un peu plus tôt dans ce chapitre.
Les choses sont plus complexes avec OOo Calc. Lancez un enregistrement de macro, sélectionnez la plage A1:B5, puis cliquez sur le bouton Gras de la barre d'outils pour mettre les données de la sélection en gras. Le code de la macro enregistrée est le suivant :
Sub TestGras
dim document as object
dim dispatcher as object
rem ---------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ---------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "ToPoint"
args1(0).Value = "$A$1:$B$5"
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, args1())
rem ---------------------------------------------------------------------
dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Bold"
args2(0).Value = true
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args2())
End Sub
Ce code semble bien plus intimidant, mais en réalité il n'est pas si complexe (ou plus exactement, il est plus complexe qu'il n'est nécessaire, comme nous le verrons plus loin). Tout d'abord, tout accès à un objet OpenOffice.org s'effectue à l'aide de l'API OpenOffice.org.
L'API OpenOffice.org est une interface de programmation universelle qui sert à créer, ouvrir, modifier et imprimer des documents OpenOffice.org.
Elle peut être employée tant avec OOo Basic qu'avec d'autres langages de programmation comme Java et C++, grâce à la technique UNO (Universal Network Objects, objets réseau universels) qui fournit une interface compatible avec différents langages de programmation.
Afin de pouvoir utiliser une architecture UNO dans OOo Basic, vous devez déclarer une variable pour l'objet associé. Cette déclaration se fait avec l'instruction Dim. Pour déclarer une variable objet, vous devez utiliser la désignation du type Object, puis l'initialiser à l'aide de la fonction createUnoService. Dans le code précédent, vous aviez ainsi :
dim dispatcher as object
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Cet appel assigne à la variable dispatcher une référence à l'objet qui vient d'être créé. com.sun.star.frame.DispatchHelper ressemble à un type d'objet, mais la terminologie UNO emploie plus volontiers le terme service que type. Selon la philosophie UNO, ce dispatcher est décrit comme « une référence à un objet prenant en charge le service com.sun.star.frame.DispatchHelper ». Le terme « service » employé dans OpenOffice.org Basic correspond donc aux termes « type » et « classe » employés dans d'autres langages de programmation, dont VBA.
OpenOffice.org fournit des centaines de services. Afin que l'utilisateur en ait une meilleure vue générale, ils ont été regroupés en modules. Ces modules n'ont aucun autre intérêt fonctionnel pour les programmeurs OOo Basic. Lorsque vous spécifiez le nom d'un service, seul le nom du module importe, puisqu'il doit aussi apparaître dans le nom indiqué. Le nom complet d'un service est constitué de l'expression com.sun.star, qui spécifie qu'il s'agit d'un service OOo, suivie du nom du module, frame par exemple, et enfin du nom du service en lui-même, comme DispatchHelper. Le nom complet dans ce cas est ici :
com.sun.star.frame.DispatchHelper
La sélection de la plage s'effectue en créant un objet com.sun.star.beans.PropertyValue nommé args1(0) dont on fixe les propriétés Name et Value :
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "ToPoint"
args1(0).Value = "$A$1:$B$5"
puis on exécute la méthode execute.dispatch de l'objet dispatcher en lui fournissant comme arguments le document, une fonction uno, un argument égal à 0 (ne vous en préoccupez pas), puis l'object args1() :
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, args1())
La procédure pour mettre la sélection en gras est similaire : création d'un objet com.sun.star.beans.PropertyValue nommé args2(0) dont on fixe les propriétés Name et Value, puis exécution de la méthode execute.dispatch de l'objet dispatcher en lui fournissant comme arguments le document, une fonction uno, un argument égal à 0 (ne vous en préoccupez pas), puis l'object args2() :
dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Bold"
args2(0).Value = true
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args2())
Le processus est différent, mais le résultat identique à ce qui est obtenu en VBA.
Je disais que cette procédure était un peu compliquée. En effet, l'enregistreur OOfo génère un ensemble d'appels UNO d'affichage (Dispatch), lourds et peu utiles à l'apprentissage du langage.
Vous trouverez la liste complète des appels Dispatch à cette adresse
Ainsi, la macro précédente peut être largement simplifiée en créant une fonction générique qui effectue les appels UNO Dispatch. Certains appels UNO Dispatch renvoyant une valeur, se servir d'une fonction la rend plus universelle qu'employer une sous-routine. Voici d'abord cette fonction :
Function fnDispatch(sCommand as string, optional mArgs)
oFrame = ThisComponent.getCurrentController.getFrame
oDispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
`on error resume next
if isMissing(mArgs) then
fnDispatch = oDispatcher.executeDispatch(oFrame, ".uno:" & sCommand, "", 0, array())
else
nArgs = uBound(mArgs) 2
dim Args(nArgs) as new com.sun.star.beans.PropertyValue
for i = 0 to nArgs
Args(i).name = mArgs(i * 2)
Args(i).value = mArgs(i * 2 + 1)
next
fnDispatch = oDispatcher.executeDispatch(oFrame, ".uno:" & sCommand, "", 0, Args())
end if
End Function
Voici la procédure simplifiée qui s'en sert :
Sub TestGras2
fnDispatch("GoToCell", array("ToPoint","$A$1:$B$5"))
fnDispatch("Bold", array("Bold",true))
End Sub
C'est tout de suite plus parlant et plus proche de la version VBA... Nous n'entrerons pas dans le détail du code de la fonction fnDispatch, car cela excède largement le cadre de ce livre, mais vous pouvez la réemployer à votre guise...
VISUAL BASIC FOR APPLICATION
En VBA, tout est objet. Chaque objet (appartenant éventuellement à une collection) peut posséder des propriétés et des méthodes.
Les principales collections d'objets du tableur Excel sont WorkBooks (classeur), Sheets (feuille de calcul) et Range (cellules). Elles sont utilisables selon une hiérarchie descendante :
- Workbooks("Ventes 2009").Sheets("Janvier").Range("B2") désigne la cellule B2 de la feuille Janvier du classeur Ventes 2009.
- Sheets("Janvier").Range("B2") désigne la cellule B2 de la feuille Janvier du classeur actif (ouvert et affiché).
- Range("B2") désigne la cellule B2 de la feuille active.
À SAVOIR
Veillez à ne pas confondre collection et objet membre d'une collection. Le nom d'une collection se termine par un « s ». Ainsi, Sheets est la collection de toutes les feuilles d'un classeur, Sheet est une feuille.
Une fois un objet désigné, vous pouvez :
- lui appliquer une méthode, à l'aide de la syntaxe NomObjet.NomMéthode. Ainsi, Range("B2").Select sélectionne la cellule B2...
- consulter ou modifier une de ses propriétés, à l'aide des syntaxes respectives NomObjet.Propriété et NomObjet.Propriété=valeur. Parmi les propriétés classiques figurent Visible (à utiliser avec True et False pour afficher ou masquer), Value (valeur d'une cellule), Count (nombre de cellules d'une page, de feuilles de classeur, etc.).
Par exemple, si vous lancez l'enregistrement de la macro nommée TestGras, sélectionnez la plage A1:B5, puis cliquez sur le bouton Gras de la barre d'outil pour mettre les données de la sélection en gras, le code de la macro enregistrée sera le suivant :
Sub TestGras
(...)
Range("A1:B5").Select
Selection.Font.Bold = True
End Sub
Vous appliquez à un objet plage (Range) défini comme étant A1:B5 la méthode Select pour le sélectionner, puis fixez la valeur de la propriété Bold de la propriété Font de l'objet Selection (la sélection active) à True. Ce simple enregistrement vous a permis au passage de voir comment sélectionner une plage de cellules continues !
Les propriétés et méthodes d'un objet portent le nom de membres. L'éditeur VBA propose d'ailleurs deux dispositifs très intéressants, la liste des membres et l'Information rapide automatique, qui simplifient considérablement le travail de rédaction de code.
Vous avez peut-être remarqué, lors de la saisie d'instructions dans l'éditeur, l'apparition d'une boîte de liste déroulante, après la saisie d'un nom d'objet suivi par un point. C'est la liste de membres, qui affiche la liste des méthodes et propriétés de l'objet qui précède le point. Sélectionnez une méthode ou une propriété dans la liste en cliquant dessus ou en tapant quelques-unes des premières lettres de son nom, puis appuyez sur la barre Espace pour que l'éditeur place la sélection dans votre déclaration.

De même, lorsque vous saisissez un nom de fonction suivi d'une seule parenthèse (celle de gauche), l'Information rapide automatique affiche les arguments requis par cette fonction dans une info bulle. Cette aide réduit les risques d'erreur de syntaxe. Elle est disponible même pour des fonctions personnalisées créées par vous-même, comme le montre la figure suivante pour la fonction NbJours() créée un peu plus tôt dans ce chapitre.

OPENOFFICE.ORG BASIC
Les choses sont plus complexes avec OOo Calc. Lancez un enregistrement de macro, sélectionnez la plage A1:B5, puis cliquez sur le bouton Gras de la barre d'outils pour mettre les données de la sélection en gras. Le code de la macro enregistrée est le suivant :
Sub TestGras
dim document as object
dim dispatcher as object
rem ---------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ---------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "ToPoint"
args1(0).Value = "$A$1:$B$5"
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, args1())
rem ---------------------------------------------------------------------
dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Bold"
args2(0).Value = true
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args2())
End Sub
Ce code semble bien plus intimidant, mais en réalité il n'est pas si complexe (ou plus exactement, il est plus complexe qu'il n'est nécessaire, comme nous le verrons plus loin). Tout d'abord, tout accès à un objet OpenOffice.org s'effectue à l'aide de l'API OpenOffice.org.
L'API OpenOffice.org est une interface de programmation universelle qui sert à créer, ouvrir, modifier et imprimer des documents OpenOffice.org.
Elle peut être employée tant avec OOo Basic qu'avec d'autres langages de programmation comme Java et C++, grâce à la technique UNO (Universal Network Objects, objets réseau universels) qui fournit une interface compatible avec différents langages de programmation.
Afin de pouvoir utiliser une architecture UNO dans OOo Basic, vous devez déclarer une variable pour l'objet associé. Cette déclaration se fait avec l'instruction Dim. Pour déclarer une variable objet, vous devez utiliser la désignation du type Object, puis l'initialiser à l'aide de la fonction createUnoService. Dans le code précédent, vous aviez ainsi :
dim dispatcher as object
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Cet appel assigne à la variable dispatcher une référence à l'objet qui vient d'être créé. com.sun.star.frame.DispatchHelper ressemble à un type d'objet, mais la terminologie UNO emploie plus volontiers le terme service que type. Selon la philosophie UNO, ce dispatcher est décrit comme « une référence à un objet prenant en charge le service com.sun.star.frame.DispatchHelper ». Le terme « service » employé dans OpenOffice.org Basic correspond donc aux termes « type » et « classe » employés dans d'autres langages de programmation, dont VBA.
Dans VBA la structure d'un objet est définie par la classe à laquelle il appartient. Dans OOo Basic, sa structure est définie par les services qu'il prend en charge. Un objet VBA est toujours assigné à une classe unique. Un objet OOo Basic peut quant à lui prendre en charge plusieurs services.
OpenOffice.org fournit des centaines de services. Afin que l'utilisateur en ait une meilleure vue générale, ils ont été regroupés en modules. Ces modules n'ont aucun autre intérêt fonctionnel pour les programmeurs OOo Basic. Lorsque vous spécifiez le nom d'un service, seul le nom du module importe, puisqu'il doit aussi apparaître dans le nom indiqué. Le nom complet d'un service est constitué de l'expression com.sun.star, qui spécifie qu'il s'agit d'un service OOo, suivie du nom du module, frame par exemple, et enfin du nom du service en lui-même, comme DispatchHelper. Le nom complet dans ce cas est ici :
com.sun.star.frame.DispatchHelper
La sélection de la plage s'effectue en créant un objet com.sun.star.beans.PropertyValue nommé args1(0) dont on fixe les propriétés Name et Value :
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "ToPoint"
args1(0).Value = "$A$1:$B$5"
puis on exécute la méthode execute.dispatch de l'objet dispatcher en lui fournissant comme arguments le document, une fonction uno, un argument égal à 0 (ne vous en préoccupez pas), puis l'object args1() :
dispatcher.executeDispatch(document, ".uno:GoToCell", "", 0, args1())
La procédure pour mettre la sélection en gras est similaire : création d'un objet com.sun.star.beans.PropertyValue nommé args2(0) dont on fixe les propriétés Name et Value, puis exécution de la méthode execute.dispatch de l'objet dispatcher en lui fournissant comme arguments le document, une fonction uno, un argument égal à 0 (ne vous en préoccupez pas), puis l'object args2() :
dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Bold"
args2(0).Value = true
dispatcher.executeDispatch(document, ".uno:Bold", "", 0, args2())
Le processus est différent, mais le résultat identique à ce qui est obtenu en VBA.
Je disais que cette procédure était un peu compliquée. En effet, l'enregistreur OOfo génère un ensemble d'appels UNO d'affichage (Dispatch), lourds et peu utiles à l'apprentissage du langage.
À SAVOIR
Vous trouverez la liste complète des appels Dispatch à cette adresse
Ainsi, la macro précédente peut être largement simplifiée en créant une fonction générique qui effectue les appels UNO Dispatch. Certains appels UNO Dispatch renvoyant une valeur, se servir d'une fonction la rend plus universelle qu'employer une sous-routine. Voici d'abord cette fonction :
Function fnDispatch(sCommand as string, optional mArgs)
oFrame = ThisComponent.getCurrentController.getFrame
oDispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
`on error resume next
if isMissing(mArgs) then
fnDispatch = oDispatcher.executeDispatch(oFrame, ".uno:" & sCommand, "", 0, array())
else
nArgs = uBound(mArgs) 2
dim Args(nArgs) as new com.sun.star.beans.PropertyValue
for i = 0 to nArgs
Args(i).name = mArgs(i * 2)
Args(i).value = mArgs(i * 2 + 1)
next
fnDispatch = oDispatcher.executeDispatch(oFrame, ".uno:" & sCommand, "", 0, Args())
end if
End Function
Voici la procédure simplifiée qui s'en sert :
Sub TestGras2
fnDispatch("GoToCell", array("ToPoint","$A$1:$B$5"))
fnDispatch("Bold", array("Bold",true))
End Sub
C'est tout de suite plus parlant et plus proche de la version VBA... Nous n'entrerons pas dans le détail du code de la fonction fnDispatch, car cela excède largement le cadre de ce livre, mais vous pouvez la réemployer à votre guise...