Vous êtes sur la page 1sur 40

I N F O G E S T

RECORDSETS HIERARCHIQUES
GRILLES & LISTES

Praticiel

Version 1.0 - Décembre 2001

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


Created by Neevia Personal Converter trial version
 PRATICIEL INFOGEST RECORDSETS HIÉRARCHIQUES, GRILLES & LISTES SOMMAIRE

_____________________________________________________________________________________________________

RECORDSET HIÉRARCHIQUE, GRILLES ET LISTES

Sommaire

PRÉAMBULE

1 - OBJECTIF

2 - PRÉ REQUIS

3 - CONVENTIONS

4 - ENVIRONNEMENT ET PRÉALABLES

INTRODUCTION

1 - INTRODUCTION

SECTION 1 - UTILISATION DU CONCEPTEUR DATA ENVIRONMENT

1 - CRÉATION DE LA SOURCE DE DONNÉES


11 - DÉFINITION DE LA CONNEXION
12 - DÉFINITION DES TABLES
121 - La table Parent
122 - La table Enfant
13 - OBJET COMMAND ET RECORDSET
14 - CONCUSION

2 - LA GRILLE HIÉRARCHIQUE LIÉE À L'OBJET COMMAND

3 – COMPLÉMENT SUR LA NOTION DE HIÉRARCHIE


31 - CRÉATION D'UN OBJET COMMAND AVEC UNE COMMANDE SQL INNER JOIN
32 - CONCEPTION ASSISTÉE DANS LES OBJETS COMMAND

4 - AMMÉLIORER LA GRILLE HIÉRARCHIQUE


41 - DISPOSITION DES BANDES
42 - DÉFINITION DES TITRES DE COLONNES ET DE BANDES
421 - Titres de la bande 0
422 - Titres de la bande 1
43 - DÉFINITION DE LA LARGEUR DES COLONNES
44 - COLORER LA LIGNE SÉLECTIONNÉE

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIEL INFOGEST RECORDSETS HIÉRARCHIQUES, GRILLES & LISTES SOMMAIRE

_____________________________________________________________________________________________________

SECTION 2 - RECORDSET HIÉRARCHIQUE ET DATAGRID

1 - CRÉATION DE LA DATAGRID

2 - CRÉATION DU RECORDSET HIÉRARCHIQUE ET DÉCLARATION DES SOURCES PAR PROGRAMME


21 - LA SECTION DÉCLARATION
22 - PROCÉDURE FORMLOAD

3 - LA NAVIGATION DANS LE RECORDSET

4 - UTILISATION D'UNE COMBOBOX POUR SÉLECTIONNER UN ENREGISTREMENT


41 - CRÉATION DE LA DATACOMBO ET CODE NÉCESSAIRE

SECTION 3 - CRÉATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE

1 - DÉMARCHE GÉNÉRALE

2 - RÉALISATION
21 - SECTION DE DÉCLARATIONS ET CHARGEMENT DE LA FORM
22 - PROCÉDURES POUR LE CHARGEMENT DE LA FORM
221 - Procédure Form_Load
222 - Création du recordset
223 - Formatage de la MSHFlexGrid
23 - INTERCEPTION ET TRAITEMENT DES APPUIS DES TOUCHES CLAVIER (ANSI)
24 - INTERCEPTION ET TRAITEMENT DES APPUIS DES TOUCHES DE FONCTION
25 - MISE À JOUR DE LA GRILLE
26 - AJOUT D'UNE NOUVELLE LIGNE À LA GRILLE
261 - Principe
262 - Phase d'ouverture de la form
263 - Mise à jour du recordset
27 - SUPPRESSION D'UNE LIGNE DANS LA GRILLE

CONCLUSION

CONCLUSION

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


Created by Neevia Personal Converter trial version http://www.neevia.com
 PRATICIELS INFOGEST RECORDSETS HIÉRARCHIQUES, GRILLES & LISTES PRÉAMBULE

_____________________________________________________________________________________________________

PRÉAMBULE

1 - OBJECTIF

Ce didacticiel a pour objectif de vous faire découvrir et utiliser certaines procédures d'accès aux données.

A notre habitude, si vous relevez ses erreurs, si vous vous heurtez à quelque point pas assez bien
expliqué, ou si vous avez des compléments ou des améliorations à proposer, n'hésitez pas à utiliser le post-it du
forum Visual Basic pour nous en faire part et pour bénéficier d'éventuels soutient de la communauté. N'oubliez pas
de préciser de quel praticiel il s'agit.

2 - PRÉ REQUIS

Ce didacticiel est d'un niveau de connaissances que je qualifierais de "débutant", tout au moins en ce qui
concerne l'accès aux données. Il est toutefois souhaitable de savoir comment démarrer un projet Visual Basic et
construire un formulaire.

La base de données Access étant présente dans beaucoup de configuration, nous l'utiliserons tout au long
du présent didacticiel. Il est donc également souhaitable de connaître quelque peu l'utilisation de l'environnement
et des bases Access.

Si vous pensez devoir vous mettre à niveau en ce qui concerne Visual Basic, commencez par "Premiers
pas avec Visual Basic" (pour débutant). Pour progresser dans l'accès aux données, et notamment aborder les
recordsets hiérarchiques, ADO et DAO, consultez:
 Initiation à l'accès aux données
 Accès aux données avec DAO
 Accès aux données avec ADO
Pour accéder à la liste de tous mes praticiels:
 Praticiels Visual Basic
3 - CONVENTIONS

Quelques conventions concernant la présentation du document:

Cette icône annonce un point important. La teneur de ce point important est présentée en italique.

Cette icône annonce un rappel. La teneur de ce rappel est présentée en italique.

Cette icône annonce une remarque. La teneur de cette remarque est présentée en italique.

Cette icône renvoie à une autre partie du document, ou à une documentation externe, pour plus
d'information. Il suffit souvent de cliquer sur l'adresse proposée pour atteindre cette partie, si elle set
incluse dans le document, voire dans certains cas ailleurs....
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST RECORDSETS HIÉRARCHIQUES, GRILLES & LISTES PRÉAMBULE

_____________________________________________________________________________________________________

Dernier point: il peut être nécessaire de cliquer sur une image de ce document afin de la faire apparaître.
Ce n’est pas ma faute, c'est WORD… Mais plus de problème avec PDF!

4 - ENVIRONNEMENT ET PRÉALABLES

Pour pouvoir utiliser ADO, il faut que le projet VB fasse référence à Microsoft ActiveX Data Object 2.5
1 2
Library (ou supérieure). Il faut également charger le composant Microsoft Hierarchical FlexGrid Control 6.0 .

Les composants autres que les composants par défaut de Visual Basic seront indiqués au cours du
didacticiel.

Ce didacticiel utilise une conversion sous Access2002 de la base de données exemple Biblio fournie avec
Visual Basic, version Access98. Cette base est aussi fournie avec Access. Outre ces deux possibilités, vous
pouvez télécharger cette base de données à l'adresse suivante:
http://www.cs.fiu.edu/~downeyt/cop3175/03a.hw5.html
Vous aurez de toute façon à convertir la base Biblio.mdb en version Access 2000 ou mieux, 2002 et à
placer la base ainsi convertie dans le répertoire dans lequel vous aurez placé le projet qui sous tend ce praticiel.

1
La version 2.5 est celle du Pack5. Utilisez la version que vous possédez ou téléchargez le Pack5 de VD sur le
site Microsoft
http://www.microsoft.com/FRANCE/vstudio/Telecharge/info/info.asp?mar=/FRANCE/vstudio/Telecharge/info/vbrun
60sp5.html
2
Également version Pack5.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST RECORDSETS HIÉRARCHIQUES, GRILLES & LISTES INTRODUCTION

_____________________________________________________________________________________________________

INTRODUCTION

Une des fonctions de l'informatique, je serais presque tenté de dire la plus courante et même la principale,
consiste à manipuler des données, c'est à dire à les enregistrer puis à les ressortir pour les consulter ou les traiter.
Généralement, ces données sont enregistrées dans des bases de données qui maintenant sont le plus souvent
dites relationnelles.

Très schématiquement, une base de données relationnelle est une base de données qui comporte au
3
moins deux tables, dont l'une dite Parent contient des enregistrements auxquels sont reliés des enregistrements
4 5 6
de la seconde, dite Enfant . On parlera aussi d'enregistrement Parents et d'enregistrements Enfants . Assez
souvent, une base de données est composée de plus de deux tables en relation, instaurant ainsi des relations
multiples (relation d'une table avec plusieurs autres), relations en cascades (une table parent est en relation avec
une table enfant, elle-même étant le parent d'une troisième table, et ainsi de suite.

De plus, la notion de relation se décline en relation de "un à plusieurs" et en relations de plusieurs à


plusieurs, pour ne pas parler de relation de un à un, type de relation employé rarement pour scinder une
enregistrement en deux parties (pour des raison d'accès et de confidentialité par exemple).

Une relation de un à plusieurs est un type de relation dans laquelle un enregistrement (parent) peut être lié
à plusieurs enregistrements (enfants). Par exemple, un enregistrement "facture" est lié à un enregistrement" client"
et un seul, mais un enregistrement "client" peut être lié à plusieurs enregistrements "facture".

Une relation de plusieurs à plusieurs est un type de relation dans laquelle un ou plusieurs enregistrements
parents peuvent être liés à un ou plusieurs enregistrements enfants. Par exemple, dans le cadre d'une gestion de
stock, un produit pourrait être fourni par plusieurs fournisseurs et un fournisseur pourrait fournir plusieurs produits.
La relation est ici plus complexe et exige une table intermédiaire, comme nous l'étudierons par la suite. En fait, un
produit donné est ici déterminé par deux éléments: la référence du produit (ou ce qui en tient lieu) et l'identification
du fournisseur (code fournisseur par exemple).

La relation entre les tables s'effectue par l'intermédiaire d'un champ commun aux tables. Ce champ sera le
champ Clé primaire de la table Parent et un champ souvent indexé de la table Enfant. Ces deux champs sont
fréquemment nommés d'une façon identique, mais ce n'est nullement une obligation.

La relation entre tables induit une notion de hiérarchie entre ces tables et donc entre les enregistrements
qu'elle contiennent. Il convient donc de restituer cette notion de hiérarchie quand on consulte ou que l'on traite les
données de la base de données. Ce praticiel porte sur la mise en œuvre de divers objets de Visual Basic (version
6) permettant d'établir, de visualiser et d'utiliser cette notion de hiérarchie.

Dans ce praticiel, nous utiliserons la technologie ADO (ActiveX Data Objects), technologie qui offre un
modèle objet plus simple, mais surtout permet l'utilisation de jeux d'enregistrements (recordset) hiérarchiques et
propose une grille spécifique (MSHFlexGrid) pour en afficher les enregistrements.

3
On trouvera également le terme "table principale".
4
On trouvera également les termes "table secondaire" ou "table connexe".
5
Ou enregistrement principal.
6
Ou enregistrement secondaire ou connexe.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 8
_____________________________________________________________________________________________________

SECTION 1 - UTILISATION DU CONCEPTEUR DATA ENVIRONMENT

1 - CRÉATION DE LA SOURCE DE DONNÉES

L'utilisation du concepteur data environment est la façon la plus simple et la plus rapide pour définir une
connexion et un fichier à atteindre. Comme nous allons le découvrir, le concepteur data environment permet de
définir ces éléments dans un environnement interactif au moment de la création.

Nous souhaitons obtenir l'affichage d'un enregistrement parent et des enregistrements enfants qui lui sont
éventuellement liés. Nous constaterons par la suite qu'il existe plusieurs méthodes pour afficher les données
obtenues. Concentrons nous pour l'instant sur la création de la source de données.

11 - DÉFINITION DE LA CONNEXION

7
Pour accéder au data environment, droite-cliquez dans la fenêtre de l'explorateur de projet, et dans le
menu contextuel qui apparaît, cliquez sur l'item Ajouter. La fenêtre de l'objet DataEnvironment1 s'affiche alors.
Vous remarquerez aussi l'affichage du Concepteur dans la fenêtre d'exploration du projet, avec l'objet
DataEnvironment1. En cliquent sur ce dernier, vous pourrez afficher la fenêtre de l'objet.

L'objet DataEnvironment1 contient un objet


Connection1. Droite-cliquez dessus puis cliquez sur
l'item Propriétés du menu déroulant pour en afficher la
fenêtre des propriété qui va vous permettre d'indiquer
les paramètres de la connexion.

Dans l'onglet Fournisseur de cette fenêtre, sélectionnez


8
Microsoft Jet OLE DB 4.0 Provider , puis cliquez sur
le bouton de commande Suivant pour afficher l'onglet
Connexion. Dans ce dernier, saisissez le chemin de la
base de données. Utilisez l'explorateur (le bouton avec
les trois petits points) pour éviter toute erreur d'écriture.
Saisissez éventuellement le nom de l'utilisateur et le
9
mot de passe, selon votre configuration . La connexion
avec la base de données est maintenant établie et vous
pouvez la tester en cliquant sur le bouton de
commande Tester la connexion.
Dans l'onglet Avancé, vérifiez que l'option Share Deny
None est sélectionnée, afin que d'autres utilisateurs
puissent accéder en lecture/écriture à la base de
10
données .

7
Traduction: cliquez avec le bouton droit de la souris.
8
Ou 3.51 selon votre version de VB et de sa mise à jour.
9
Sur un PC personnel, ce n'est pas une obligation.
10
Pour une base en réseau.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 9
_____________________________________________________________________________________________________

12 - DÉFINITION DES TABLES

121 - LA TABLE PARENT

Dans un premier temps, nous allons créer un objet Command qui fera référence à la table Publishers de la
base de données Biblio.mdb. Cette table est la table parent (table principale).

Droite-cliquez sur l'icône de l'objet Connection1, puis


sur l'item Ajouter une commande du menu déroulant
pour créer l'objet Command1 dépendant de l'objet
Connection1.
Vous obtenez la fenêtre ci-contre. Droite-cliquez sur
l'icône de l'objet Command1 puis sur l'item Propriétés
du menu déroulant afin d'ouvrir la fenêtre de
propriétés de cet objet.
Nous utilisons ici les noms par défaut des objets, par
flemme peut-être, mais il vous est possible, voire
recommandé, de les modifier.

Renseignez l'onglet Général comme montré ci-contre.


Notez que nous aurions pu ici opter pour une
instruction SQL au lieu de spécifier une table dans les
zones de texte. Mais la désignation d'une table reste
le chemin le plus facile…, et nous verrons le SQL in
peu plus loin.
La table que nous avons indiquée est la table parent
Publishers à laquelle seront liés les enregistrements
de la table Titles.
Cliquez sur le bouton de commande OK.

122 - LA TABLE ENFANT

Comme nous devons traiter deux tables liées, cela implique la création de deux objets Command, un pour
chacune des tables. Ce second objet Command sera une commande fille, c'est-à-dire qu'il dépendra de
Command1.

Notez que l'objet Command1, que nous avons


développé en cliquant sur le nœud "+" contient bien
tous les champs de la table Publishers.
Droite-cliquez sur l'icône de l'objet Command1, puis
sur l'item Ajouter une commande fille du menu
contextuel, afin de créer l'objet Command2.
Droite-cliquez sur l'icône de l'objet Command2, puis
sur l'item Ajouter une commande fille du menu
déroulant. Vous obtenez la fenêtre ci-contre.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 10
_____________________________________________________________________________________________________

Cliquez sur l'icône de l'objet Command2, puis sur


l'item Propriétés du menu contextuel. La fenêtre des
propriétés de l'objet Command2 s'affiche.
Renseignez la comme ci-contre, la source de données
étant une table de la base de données courante ayant
pour nom Titles.
Cliquez sur l'onglet Relation.

Nous indiquons dans la boite à cocher de cet onglet


que l'objet Command2 est lié à un objet Command
parent dont nous saisissons le nom, Command1, dans
la TextBox adéquat.
Ayant maintenant nos deux tables, nous pouvons
établir la relation entre elles. Le champ commun par
lequel ces deux tables seront liées est le champ
PubID. Sélectionnez le dans les deux listes puis
cliquez sur le bouton de commande Ajouter.
Cliquez sur le bouton de commande OK et
développez ce niveau en cliquant sur le nœud "+" de
Command2. Tous les champs de la table Titles sont
bien dans l'objet Command2..

Nous avons créé deux objets Command en établissant une relation entre les deux. Dans la seconde
section, nous allons nous en servir dans la section suivante en tant que source de données pour une grille
hiérarchique.

13 – OBJETS COMMAND ET RECORDSETS

En réalité un objet Command sous-tend un recordset. On peut d'ailleurs accéder à ce recordset par une
instruction du genre "dataenvironment1.rsCommand1". Il est intéressant dès maintenant de le vérifier en accédant
à la chaîne SQL qui a été automatiquement construite lors de la création de l'objet Command1.

Affichez donc le DataEnvironment (clic sur DataEnvironment1 de l'explorateur de projets) et cliquez sur le
Command1 pour obtenir le menu contextuel (clic droit). Cliquez alors sur l'item Information de hiérarchie. Vous
obtenez la fenêtre ci-dessous dans laquelle vous pouvez afficher la chaîne SQL et la hiérarchie ADO concernant
nos deux tables sources.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 11
_____________________________________________________________________________________________________

Notez la syntaxe de la chaîne SQL qui est une syntaxe


spécifique à la création d'un recordset hiérarchique,
type de recordset que nous détaillerons utiliserons
directement par la suite.

Rappelez vous simplement pour l'instant qu'il est,


contrairement à ce qui est souvent avancé ici et là,
relativement aisé de créer un recordset hiérarchique,
soit par le biais de l'objet Command, soit en se servant
de l'objet pour obtenir la chaîne SQL nécessaire à la
création d'un tel recordset (ou de tout autre type de
recordset d'ailleurs…)..

On obtient, en sélectionnant le bouton radio idoine, le


schéma de la hiérarchie ADO. Imaginez l'intérêt lors de
l'utilisation de tables enfant multiples ou en cascade.

14 - CONCLUSION

On a pu constater dans cette première section l'efficacité et la facilité de mise en œuvre des objets
Command.

De plus, nous avons vu que ces objets peuvent nous aider grandement dans la création de recordsets
hiérarchiques. Microsoft, dans MSDN, nous indique d'ailleurs que la syntaxe de la mise en forme des données
avec Shape étant relativement complexe, il est préférable de passer par cet objet.

Nous allons maintenant afficher les données dans une MSHFlexGrid, grille qui affiche aussi bien les
enregistrements parents que les enregistrements enfants, exactement comme le ferait un formulaire Access.

2 - LA GRILLE HIÉRARCHIQUE LIÉE À L'OBJET COMMAND

Rappelons que le composant MSHFlexGrid doit être déclaré dans le projet pour pouvoir l'utiliser. Pour
l'installer, cliquez sur le menu Projet/Composants et cochez la case correspondant à Microsoft
Hiérarchical FlexGrid Control 6.0. Ce composant est apparu avec la version 6 de Visual Basic.

Créez une form que vous nommerez objCommand. Faites glisser l'icône de la MSHFlexGrid de la barre
d'outils sur cette feuille. Fixez la propriété WindowsState de la feuille à 2 - Maximized et agrandissez la
MSHFlexGrid au maximum.

Dans la fenêtre des propriétés de la grille, sélectionnez la propriété DataSource. La liste déroulante vous
propose la source de données DataEnvironment1, seule source d'ailleurs actuellement disponible dans notre
application. Sélectionnez la, puis sélectionnez la propriété DataMember. La liste déroulante vous propose les deux
objets Command, Command1 et Command2. Sélectionnez Command1.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 12
_____________________________________________________________________________________________________

L'objet Command1 contient l'objet Command2, du fait que nous avons déclaré le second comme
commande fille du premier. C'est tout l'intérêt des recordset hiérarchiques.

Lancez l'application et regardez votre œuvre (oui, mais quand même un peu celle de VB aussi…). Vous
devriez obtenir quelque chose comme ci-dessous.

Utilisez les ascenseurs, surtout l'horizontal, pour bien voir tout le contenu de la grille. Certes, telle qu'elle se
présente, cette grille est assez indigeste, mais nous allons l'améliorer par la suite (cf. §4). Pour l'instant, contentez
vous de la découvrir telle qu'elle. En premier lieu, vous pouvez constater que c'est bien une grille hiérarchique, et
nous développerons cet aspect §21. Les enregistrements de la table enfant Titles, lorsqu'il y en a, sont bien
affichés en regard de leur enregistrement parent de la table Publishers. Il vous est possible de développer
(afficher tous les éventuels enregistrements enfants d'un l'enregistrement parent sélectionné) ou de réduire
(n'afficher que l'enregistrement parent) chaque enregistrement parent en cliquent respectivement sur le "+" ou le "-"
de la première colonne de la grille. Vous pouvez également (et malheureusement) vérifier qu'il est impossible de
11
saisir, modifier ou supprimer un enregistrement dans la grille, que cet enregistrement soit parent ou enfant .

3 – COMPLÉMENT SUR LA NOTION DE HIÉRARCHIE

Il est important de bien comprendre que la notion de hiérarchie pour un recordset et donc par conséquence
pour une grille hiérarchique dépasse largement la simple notion de tables liées. Pour s'en convaincre, et pour bien
identifier la différence entre un recordset hiérarchique et un recordset "normal" avec deux tables liées, le mieux est
de créer une seconde grille hiérarchique ayant pour source un objet Command obtenu par une instruction SQL
12
classique, avec un INNER JOIN, pour établir la relation entre les deux tables . Le recordset qui en résultera ne
sera pas un recordset hiérarchique, comme vous le constaterez à l'affichage de la grille.

31 - CRÉATION D'UN OBJET COMMAND AVEC UNE COMMANDE SQL INNER JOIN

Créez une seconde feuille, plein écran, ayant pour nom GrilleSQL et pour titre Essai Grille hiérarchique
inner. Insérez dans cette feuille une MSHFlexGrid, comme précédemment (§2).Créez également un second objet
DataEnvironment2 comme précédemment (§1) ainsi qu'un objet Connexion1 (cf §11), ce qui fera un bon exercice.
Conservez les noms proposés par défaut.

11
Rassurez-vous, il y a des solutions pour ajouter ou modifier les enregistrements. Nous les étudierons par la
suite.
12
Nous verrons par la suite qu'il est possible d'utiliser la syntaxe SQL pour obtenir un recordset hiérarchique.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 13
_____________________________________________________________________________________________________

Dans cet objet Connection1, nous créons un objet Command1 en utilisant une instructionSQL avec
WHERE. Pour ce faire, affichez la fenêtre de propriétés de cet objet (clic droit dans la fenêtre de l'objet Command1
(attention, nous sommes dans DataEnvirinment2) puis Propriétés du menu contextuel).

Dans l'onglet Général, sélectionnez l'option SQL, et


dans le champ qui devient accessible, saisissez la
requête SQL comme ci joint. C'est une requête on ne
peut plus classique.
Nous demandons ici de sélectionner tous les
enregistrements des tables Publishers et Tiles pour
lesquels le champ PubID de la table Titles est égal au
champ PubID de la table Publishers, en classant selon
l'ordre du champ PubID de la table Publishers. C'est
une requête classique que vous avez déjà sans doute
utilisée ou au moins vue. Mais le thème n'est pas la
chaîne SQL mais une simple comparaison du résultat
obtenu par rapport à la commande SHAPE.

La requête ci dessus correspond à une jointure interne qui ne sélectionne que les enregistrements des
deux tables dont la valeur des champs joints correspond. Ainsi, si il n'y a pas d'enregistrement dans la
table Titles pour un enregistrement donné de la table Publishers, l'enregistrement de la table
Publisher ne s'affichera pas. La syntaxe ci-dessus correspond à la commande SQL "SELECT
Publishers.*, Titles.* FROM Publishers INNER JOIN Titles ON Publishers.PubID = Titles.PubID ORDER
BY Publishers.PubID".
Pour obtenir tous les enregistrements de la table Publishers, il faut créer une requête RIGHT OUTER
JOIN (jointure externe droite): "SELECT Publishers.*, Titles.* FROM Publishers RIGHT OUTER JOIN
Titles ON Publishers.PubID = Titles.PubID ORDER BY Publishers.PubID".

La clause SQL WHERE ne fait que sous entendre la jointure alors que les jointures internes et externes
précisent exactement au moteur JET ce qu'il doit faire. Il est toujours préférable d'utiliser les jointures
plutôt que la cause WHERE.
De plus, la clause WHERE renvoie un jeu d'enregistrement qui ne peut pas être mis à jour (propriété
Updatable du jeu d'enregistrements), alors que les jointures renvoient un jeu d'enregistrements updatable.

Nous ne saurions trop vous conseiller d'essayer les diverses syntaxes présentées ici et de bien examiner
les résultats produits. N'hésitez pas, vu la facilité de la chose, à créer pour ce faire des objets Command
nouveaux, dans un objet Connexion déjà crée ou dans un nouveau, voir même dans un nouveau
DataEnvrironment. Dans le projet VB, nous vous présentons une feuille (GrilleSQL) avec une MSHFlexGrid dont la
source de données est DataEnvironment2 et la propriété DataMember peut être l'objet Command1 (avec clause
WHERE) ou Command2 (avec clause INNER JOIN). A vous d'essayer la clause RIGHT OUTER JOIN…

Comme nous l'avions annoncé la grille ainsi obtenue est loin d'utiliser une présentation hiérarchique.
Constatez que chaque enregistrement enfant est affiché avec l'enregistrement parent lui correspondant, ce
qui entraîne une redondance dans l'information. Avec une présentation hiérarchique de la grille, comme nous
l'avons réalisée précédemment cf.2, il y a un seul enregistrement parent pour x enregistrements enfants.

En fait, dans un recordset hiérarchique, les enregistrements enfants liés à un enregistrement parent, tous,
mais eux seuls, ne sont qu'un champ supplémentaire ajouté à l'enregistrement parent.

32 – CONCEPTION ASSISTÉE DANS LES OBJETS COMMAND

Dans le paragraphe précédent, nous avons défini des chaînes SQL dans la fenêtre de propriétés de l'objet
Command. Mais, cela implique déjà quelques connaissances en SQL. Or, il existe un assistant permettant de créer
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 14
_____________________________________________________________________________________________________

la requête exactement comme dans Access. Pour y accéder, cliquez sur l'item Conception du menu contextuel de
l'objet Command. Vous obtenez la fenêtre ci-dessous.

Volet 1

Volet 2

Volet 3

Volet 4

Il suffit alors de faire glisser dans le volet 2, depuis le volet supérieur 1, les tables que nous voulons
atteindre pour notre requête, puis de sélectionner les colonnes voulues (ou toutes *) dans chaque table en cliquant
dans les boites à cocher correspondantes. Les colonnes (ou l'astérisque *) s'affichent dans le volet 3, volet dans
lequel nous pouvons définir entre autres un tri (colonne Type de tri). La requête issue de ces manipulations
s'affiche au fur dans le volet 4. Il est possible de définir le type de liaison en cliquant sur le lien situé entre les
tables du volet 2. Ainsi, il devient facile de s'initier au SQL, ou de contrôler une chaîne écrite à la volée.

Avouez qu'il aurait été dommage de passer à côté…

4 - AMÉLIORER LA GRILLE HIÉRARCHIQUE

Nous allons maintenant rendre la grille hiérarchique un peut plus présentable. Pour bien savoir où l'on va,
voilà ci-dessous ce que nous voulons obtenir. Vous avouerez que la grille est ainsi plus sympa et surtout plus
lisible que celle dont nous disposons pour l'instant…

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 15
_____________________________________________________________________________________________________

41 - DISPOSITION DES BANDES

Un peu de vocabulaire. Peut-être ne savez vous pas ce que signifie le terme bande. Dans la MSHFlexGrid,
une bande représente en fait les enregistrements d'une table. Comme nous affichons deux tables dans notre grille,
nous avons donc deux bandes (0 et 1). La bande 0 est pour les enregistrements de la table Publishers et la bande
1 est pour les enregistrements de la table Titles.

Nous avons déjà parlé de développement et de réduction. Ces deux termes s'appliquent dans notre cas à
la bande 0 qui concerne les enregistrements la table parent Publishers dont nous pouvons à loisir afficher
(développer) ou ne pas afficher (réduire) les enregistrements enfants de la table Titles.

Pour l'instant, les deux bandes de la grille sont affichées horizontalement, ce qui fait que le grille a une
largeur excessive d'une part, et d'autre part ne permet pas de voir aisément les ouvrages propres à chaque
éditeur. Il faudrait que les enregistrements enfants (les ouvrages) soient dessous les enregistrements parents
éditeurs (les éditeurs respectifs). Il nous faut donc un affichage vertical des bandes.

Par ailleurs, nous voulons aussi décaler (indenter) les enregistrements Enfants (bande 1) par rapport aux
enregistrement parents (bande 0). Nous définirons donc une indentation de 3 colonnes pour la bande 1. De plus,
pour bien marquer ce décalage, nous colorerons en jaune l'indentation.

Si besoin est, ouvrez le formulaire ObjCom et double cliquez dessus pour afficher la fenêtre de code, puis
saisissez ce qui suit.
Ligne Code Explications
1 Option Explicit Rend la déclaration des variables obligatoire.
2 Private Sub Form_Load() Sur chargement du formulaire, définition des
propriétés de la grille hiérarchique
3 With MSHFlexGrid1 Début du bloc With…EndWith (voir rappel ci dessous)

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 16
_____________________________________________________________________________________________________

4 .CollapseAll (0) Réduction de la bande 0


5 .BandDisplay = flexBandDisplayVertical Affichage vertical des bandes
6 .BandIndent(1) = 3 Indentation de la bande 1 (les ouvrages)
7 .BackColorIndent(1) = vbYellow Coloration en jaune de l'indentation
A suivre…

Le bloc With…End With permet d'accéder aux propriétés et aux méthodes d'un objet, en l'occurrence de
la MSHFlexGrid1, en une seule fois, sans avoir à chaque ligne située entre le début et la fin du bloc à
faire référence au dit objet. On remplace cette référence par un simple "." (point). Outre la facilité
d'écriture, cette syntaxe permet aussi de raccourcir le temps d'exécution du code, car la référence à la
grille n'est exécutée qu'une seule fois et est conservée en mémoire jusqu'à la fin du bloc.

Regardez déjà le résultat. La grille a déjà vraiment meilleure figure. Essayez de développer des
enregistrements de la bande 0 en cliquant sur le nœud "+".
Beaucoup de ces propriétés sont également définissables facilement, sans code, dans la fenêtre des
propriétés (F4 ou menu Affichage/Fenêtre propriétés) ou la page de propriétés (clic droit sur la grille
puis menu contextuel Propriétés). La page de propriétés permet de définir plus de paramètres.

42 - DÉFINITION DES TITRES DE COLONNES ET DE BANDES

421 - TITRES DE LA BANDE 0

Pour l'instant, les titres des colonnes reprennent le nom des champs de l'enregistrement parent. Or, ces
noms sont en anglais et nous les voulons en français. C'est peut-être du chauvinisme mais c'est également un bon
exercice qui vous permettra de définir les nom que vous voulez dans vos en têtes de bandes. Et oui, je dis bien
"bandes", et vous verrez le résultat…

Saisissez le code qui suit après le début de code de la procédure Form_Load.


Ligne Code Explications
Suite…
8 .ColHeader(0) = flexColHeaderOn Pour afficher les en-têtes de la bande 0. Pour ne pas
les afficher, on aurait utilisé flexColHeaderOff.
9 .ColHeaderCaption(0, 1) = "PubID" Nous indiquons ici le titre de la seconde colonne (1)
dans la première bande (0). N'oubliez pas que les
collection colonnes et bandes démarent à 0 (comme
d'ailleurs toutes les collections). La première colonne
est celle qui contient les icônes de réduction ou de
développement.
10 .ColHeaderCaption(0, 2) = "Nom" Nous renouvelons l'opération pour toutes les colonnes
de la bande 0.
11 .ColHeaderCaption(0, 3) = "Société"
Pour ceux qui, par la suite, utiliseront des variables
12 .ColHeaderCaption(0, 4) = "Adresse"
comme paramètres, précisons que ceux-ci sont de
13 .ColHeaderCaption(0, 5) = "Localité" type long.
14 .ColHeaderCaption(0, 6) = "Etat" Rappelez vous que vous êtes toujours à l'intérieur d'un
bloc With…End With qui fait référence à l'objet
15 .ColHeaderCaption(0, 7) = "Zip"
MSHFlexGrid1, d'où le point devant
16 .ColHeaderCaption(0, 8) = "Téléphone" ColHeaderCaption.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 17
_____________________________________________________________________________________________________

17 .ColHeaderCaption(0, 9) = "Fax" Une fois terminé, lancez l'application et allez au


résultat.
18 .ColHeaderCaption(0, 10) =
"Commentaires"
A suivre…

Ce n'est pas encore bien brillant, n'est-il pas? Nous n'avons que faire des deux lignes d'en-têtes. Pourquoi
ces deux lignes? Et bien, celle qui s'est affichées par défaut (avec les titres anglais), c'est l'en-tête des colonnes, la
seconde étant, comme nous l'avons précisé, une ligne d'en-têtes de la bande 0. Débarrassons nous donc des en-
têtes de colonnes.
Ligne Code Explications
Suite…
19 .FixedRows = 0 La ligne d'en-têtes des colonnes est une ligne fixe. Il
suffit de déclarer que le nombre de ligne fixe est égal
à 0 et nous n'aurons plus de titres de colonnes.
A suivre

Regardez le résultat. Ça va nettement mieux, mais… Nous aimerions bien aussi affubler les colonnes de la
seconde bande (1) de titres. Qu'à cela ne tienne, nous savons (presque) faire. Il suffit de prendre exemple sur ce
que nous venons de réaliser.

422 - TITRES DE LA BANDE 1


Ligne Code Explications
Suite…
20 .ColHeader(1) = flexColHeaderOn Même démarche donc que pour la première bande
(lignes 8 à 18), mais maintenant nous traitons de la
21 .ColHeaderCaption(1, 0) = "ISBN"
seconde bande, c'est à dire de la bande 1 (oui, je sais,
22 .ColHeaderCaption(1, 1) = "PubID" ça fini par faire serinage, mais j'ai mis longtemps à me
rappeler que ça commençait à 0, et peut-être en sera-
23 .ColHeaderCaption(1, 2) = "Titre" t-il de même pour certains d'entre vous, d'où l'effet
24 .ColHeaderCaption(1, 3) = "Année serin)
parution"
25 .ColHeaderCaption(1, 4) = "Descriptif"
26 .ColHeaderCaption(1, 5) = "Notes"
27 .ColHeaderCaption(1, 6) = "Sujet"
A suivre…

Quoi? Vous n'êtes pas encore satisfait du résultat? Que voulez vous de plus? Centrer les titres? Qu'à cela
ne tienne, mais permettez moi de vous dire que vous abusez… Bon, puisque c'est cela, nous en profiterons
également pour déterminer l'alignement des données au sein des colonnes des deux bandes.
Ligne Code Explications
Suite…
28 For i = 0 To .Cols - 1 Nous allons parcourir la collection des colonnes de la
bande 0. Leur numérotage commençant à 0, nous
irons donc jusqu'à i = n-1, ce qui nous donnera bien le
nombre de colonnes. La colonne 0 n'ayant pas de
titre, nous aurions pu commencer à i = 1.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 18
_____________________________________________________________________________________________________

29 .ColAlignmentHeader(0, i) = Nous centrons l'en-tête de la ième colonne dans la


flexAlignCenterCenter bande 0. Le paramètre flexAlignCenterCenter est une
constante spécifiant un alignement centré en largeur
et en hauteur. La valeur de cette constante est 4, donc
vous pourriez la remplacer par cette valeur pour le
même effet.
30 Next
31 For i = 0 To .Cols - (.BandIndent(1) + 1) Passons au centrage des titres de colonnes de la
bande 1. Ceci demande un peu de réflexion. Enfin!
(voir ci-après l'explication).
32 .ColAlignmentHeader(1, i) = 4 Nous centrons le titre de la ième colonne de la bande
1, ce en utilisant la valeur 4 et non la constante
comme précédemment, pour le même résultat. Mais
nous vous conseillons d'utiliser les constantes qui sont
quand même plus parlantes.
33 .ColAlignmentBand(0, i) = 9 Nous précisons dans ces deux lignes l'alignement du
contenu des bandes pour les deux bandes. La valeur
34 .ColAlignmentBand(1, i) = 9
9 correspond à la constante flexAlignGeneral, à savoir
"à gauche, au centre" pour les chaînes et "à droite, au
centre" pour les chiffres.
35 Next
A suivre…

Ligne 31 ci-dessus, nous avons annoncé qu'un peu de réflexion s'imposait. En effet, la collection de
colonnes est celle de la grille hiérarchique, et non celle d'une ou l'autre des bandes. Par contre, la première
colonne de la bande 1, dont le numéro "virtuel" est 0 correspond à la colonne 4 de la grille du fait de l'indentation.
Vous suivez?

Donc, si nous initions une boucle "For i = 0 to .cols-1, nous allons exécuter cette boucle 11 fois, la grille
ayant 11 colonnes, dont la colonne 0 (fixe). Vous suivez toujours?

Mais, nous avons vu que la première colonne de la bande 1 correspondait à la colonne 4 de la grille
hiérarchique. Vous tenez?

Donc, la boucle irait virtuellement jusqu'à la colonne 14 de la grille hiérarchique qui correspond à la colonne
11 de la bande 1! Il faut donc aller jusqu'à i - 1 moins le nombre de colonnes de l'indentation, d'où le "to Cols -
(.BandIndent(1) + 1)"

Ouah-hou!!! Si vous n'avez pas décroché, bravo. Cependant, pour vous convaincre de la justesse du
raisonnement, remplacez la ligne 31 par " For i = 0 To .Cols - 1" et constatez le résultat. Vous avez bien 3 colonnes
en plus, et qui sont naturellement vide puisqu'elles ne correspondent à rien.

Revenez donc à la première version de la boucle, et reposez vous, vous en avez sans doute besoin…
Quoi? Des murmures? Vous voulez aussi définir la largeur des colonnes. Bon, au point ou nous en sommes,
allons-y.

Mais avant, une petite information concernant les titres de colonnes de la grille hiérarchiques, ceux qui
étaient dans la ligne fixe (cf. 421 - ligne 19 du tableau de code). Pour en définir les titres et les aligner, créez une
chaîne de caractères comme suit et passez la à la propriété FormatString de la grille.
Code Explications
Dim strNomCol As String La propriété FormatString contient des segments

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 19
_____________________________________________________________________________________________________

strNomCol = "> |<PubID|<Nom séparés par des barres (|). Le texte comprit entre les
|<Société|>Adresse|>Localité |<Etat |<Zip barres définit une colonne et peut éventuellement
|<Téléphone |^Fax |<Commentaires " contenir des caractères spéciaux d'alignement. Ces
caractères alignent l'ensemble de la colonne à
.FormatString = strNomCol gauche (<), au centre (^) ou à droite (>). En outre, le
texte est assigné par défaut à la ligne 0 et la largeur
du texte définit la largeur de chaque colonne par
défaut. (cf. aide en ligne de VB)

43 - DÉFINITION DE LA LARGEUR DES COLONNES

Ligne Code Explications


Suite…
36 .ColWidth(0, 0) = 500 Toujours le même principe pour les paramètres de la
propriété ColWidth: d'abord le numéro de la colonne,
37 .ColWidth(1, 0) = 600
puis le numéro de la bande. Mais est-il encore besoin
38 .ColWidth(2, 0) = 1500 de le préciser?…
39 .ColWidth(3, 0) = 2000
40 .ColWidth(4, 0) = 2000
41 .ColWidth(5, 0) = 750
42 .ColWidth(6, 0) = 750
42 .ColWidth(7, 0) = 1000
44 .ColWidth(8, 0) = 900
45 .ColWidth(9, 0) = 800
46 .ColWidth(10, 0) = 2500
A suivre…

Je vous vois venir. Vous voulez aussi définir la largeur des colonnes de la bande 1. Eh bien, désolé, mais
ce n'est pas possible, ou si ça l'est, j'ai pas trouvé comment. En fait, bien que l'on puisse préciser la bande pour
laquelle on veut définir la largeurs des colonnes, il n'est possible de le faire que pour une seule bande, en tout cas
lorsque que nous avons à faire avec une présentation verticale des bandes. Cela est d'ailleurs logique, car pour les
colonnes communes des différentes bandes, il ne peut y avoir deux largeurs différentes. Ce qui implique d'ailleurs
que pour les colonnes de la seconde bande et des éventuelles suivantes), toutes les colonnes "dépassant" le
nombre de colonne de la première bande pourront être définies en largeur. Il vous est d'ailleurs facile de le vérifier,
ce que je n'ai pas fait (toujours une certaine flemme qui me poursuit) en définissant une indentation supérieure.
Ainsi, vous aurez des colonnes de la seconde bande (1) dont le numéro sera supérieur à celui de la dernière
colonne de la première bande (0) et dont vous pourrez donc définir la largeur.

Voilà, nous en avons fini avec la mise en forme de la MSHFlexGrid. Il nous reste à terminer la procédure.

Suite…
47 End With Fermeture du bloc With
48 End Sub

44 – COLORER LA LIGNE SÉLECTIONNÉE

C'est la cerise sur le gâteau. Comme c'est une question récurrente, autant y répondre une bonne fois pour
toute. La solution exposée ici est également valable pour une MSFlexGrid.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


PRATICIELS INFOGEST SECTION 1 - UTILISATION DU CONCEPTEUR DATAENVIRONMENT Page 20
_____________________________________________________________________________________________________

La première chose à faire est de définir l'évènement qui va déclencher la coloration de la ligne
sélectionnée. Pas besoin de chercher beaucoup pour découvrir que l'évènement idoine est le clic dans la grille.
Vous pouvez soit écrire le code tel que ci dessous, avec la ligne de déclaration, soit sélectionner l'objet
MSHFlexGrid1 dans la liste des objets, puis l'évènement dans Click dans la liste voisine des objets.
Ligne Code Commentaires
1 Private Sub MSHFlexGrid1_Click() Pour colorer la ligne sélectionnée.
2 With MSHFlexGrid1 On commence à connaître, non ?...
3 .Col = 1 On défini la première colonne de la sélection comme
étant la première colonne de la MSHFlexGrid.
4 .ColSel = .Cols - 1 Définition de la dernière colonne de la sélection
comme étant la dernière colonne de la grille. Comme
la collection des colonnes commence à 0, et que Cols
nous renvoie le nombre de colonne, on écrits Cols-1.
5 .RowSel = .Row Définition de la ligne sélectionnée comme étant la
ligne en cours, celle sur laquelle l'utilisateur a cliqué.
6 End With Fin du bloc With.
7 End Sub Fin de la procédure événementielle.

Maintenant, il nous faut définir les couleurs que nous souhaitons affecter à la ligne sélectionnée. Le code
ci-dessous s'ajoutera en fin de la procédure Form_Load(), après la ligne 46 et avant la ligne 47 (pour rester à
l'intérieur du bloc With).
Ligne Code Commentaires
46/a .BackColor = &HFFFFC0 Couleur de fond de la grille. Toutes les lignes sont de
cette couleur (bleu ciel)
46/b .BackColorSel = &HC0FFFF Couleur de fond de la ligne sélectionnée (jaune clair)
46/c .ForeColorSel = &HFF& Couleur du texte de la ligne sélectionnée. Par défaut,
cette couleur est le blanc, mais si in ne la modifie pas,
le texte devient invisible. Faites-en l'expérience.
46/d4 .FocusRect = flexFocusNone On ne veut pas que la cellule active soit signalée
comme ayant le focus. Ainsi, elle sera colorée de la
même couleur que celle définie pour la sélection, et
non en surbrillance.

Un dernier point, pour être "parfait" (oui, les chevilles, çà va…). Vous avez sans doute remarqué que, lors
de l'ouverture de la feuille, aucune ligne n'étant sélectionnée dans la grille, le curseur est positionné ligne 1
colonne1. La cellule ainsi définie est colorée, mais pas toute la ligne, et je ne sais pas vous, mais moi, cela me
gêne. Nous allons donc faire en sorte de colorer la ligne entière. Il nous suffira pour ce faire d'utiliser un code
identique à celui écrit pour l'évènement clic de la grille. Donc pas de problème en la matière. Mais, où écrire ce
code? Dans la procédure Form_Load me direz-vous. Et bien, essayez!

Il y a un petit problème n'est-ce pas? Mais, je vais vous laisser chercher la solution, car je pense qu'au
stade où nous en êtes, vous pourriez la trouver avec très peu (ou un peu) de réflexion, ou alors en consultant
MSDN sur les thèmes utilisés.

En dernier ressort, si vous ne trouvez pas, écrivez moi.

Nous en avons terminé avec cette première section. Dans la section suivante, nous allons utiliser une
DataGrid et des TextBox pour afficher les données que nous obtiendrons depuis un recordset que nous créerons.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 21
_____________________________________________________________________________________________________

SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID

Pour utiliser facilement et pleinement les recordsets hiérarchiques, je pense que l'approche la plus
adaptées dans le cadre d'une application professionnelle est le plus souvent d'utiliser des TextBox dépendantes
pour l'enregistrement principal (parent) et un DataGrid pour les enregistrements secondaires (enfants), ce dès qu'il
s'agit de sortir du cadre strict de la lecture d'enregistrements. En tout cas, c'est mon avis, et je le partage.
L'ensemble ainsi présenté est beaucoup plus esthétique et exploitable, surtout si vous vous rappelez qu'en
principe, il n'est pas possible de modifier le contenu d'une MSHFlexGrid. De plus, les DataEnvironment et les
objets Command pèsent lourd, c'est tout au moins ce que je me suis laissé dire.

Nous allons en profiter pour exposer comment créer et utiliser un recordset hiérarchique par
programmation, avec la commande SHAPE/APPEND dans le cadre de la mise en forme des données. A notre
avis, que nous partageons toujours, c'est encore plus facile et plus rapide qu'avec l'objet Command et, le
recordset hiérarchique ainsi créé offre toutes les propriétés et méthodes d'un objet recordset (rappelons nous que,
comme nous l'avons vu §13, les objets Command sous-tendent un recordset auquel on peut faire référence
comme pour tout recordset).

Nous nous servirons également d'une BindingCollection afin d'établir la relation entre les TextBox et les
données. Ce n'est pas une obligation que de ce servir de cette collection pur établir cette liaison, car nous
pourrions, pour chacune de ces zones de texte, définir les propriétés DataSource et DataField. Mais le faire avec
du code, en une seule fois et un seul endroit est nettement plus opérant et permet certainement une maintenance
plus aisée.

1 – CRÉATION DE LA DATAGRID

Nous allons définir quelque peu la présentation de la DataGrid. Pour l'instant, elle affiche toutes les
colonnes du recordset, avec pour titre le nom de ces colonnes, et pour largeur une valeur prédéterminée, valeur
qu'il n'est pas possible de modifier car il n'existe pas de propriété Width pour les colonnes dns la fenêtre des
propriétés.

Pour accéder aux propriétés qui vont nous permettre de définir les caractéristiques des colonnes de la
grille, il nous faut passer par la page de propriété accessible depuis le menu contextuel de la DataGrid, item
Propriétés.

La page de propriétés s'affiche. L'onglet qui pour


l'instant nous intéresse est l'onglet Colonnes. En
déroulant la combo Column, la liste ne nous apporte
pas grand-chose. Elle contient pour l'instant les deux
colonnes de la grille telle qu'elle a été dessinée par
défaut, et naturellement aucun titre (champ Caption), ni
aucune définition de la colonne source de cette colonne
grille (champ DataField).
De plus, il ne semble pas possible d'ajouter à la liste de
la combo Column quelque colonne que ce soit.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 22
_____________________________________________________________________________________________________

Pour ajouter des colonnes qui soient reconnues dans


cette page de propriétés, il faut passer par le menu
contextuel de la grille, item Edition (image de droite).
Réaffichez ensuite le menu contextuel qui ne présente
plus les mêmes item (image de gauche).
Il y a notamment maintenant un item qui permet
d'ajouter des colonnes. Cliquez dessus quatre fois pour
ajouter quatre colonnes, puis revenez à la page des
propriétés, onglet Colonnes.

Maintenant, la liste de la combo affiche 6 colonnes (0 à


5), pour l'instant sans non et qui ne sont pas reliées à
un champ du recordset. Cliquez sur chaque item de la
combo et renseignez les champs de la boite de
dialogue Caption (pour le titre) et DataField (pour le
champ lié du recordset).
Il ne semble pas exister de propriété pour centrer le
titre des colonnes. J'ai donc inséré des espaces devant
les titres pour ce faire.

Il ne reste plus qu'à définir la largeur de chaque


colonne. Dans l'onglet Disposition, sélectionnez tour à
tour chaque colonne dans la combo Column et
définissez la largeur dans le champ Width. Si le total
des largeurs des colonnes dépasse la largeur de la
grille, il y aura automatiquement un ascenseur
horizontal.

En ce qui nous concerne, nous en avons terminé quant à la définition des caractéristiques de notre
DataGrid, mais je ne doute pas que vous explorerez plus en avant toutes les possibilités de paramétrage qui vous
sont offerte dans cette feuille de propriétés.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 23
_____________________________________________________________________________________________________

2 - CRÉATION DU RECORDSET HIÉRARCHIQUE ET DÉCLARATION DES SOURCES PAR PROGRAMME

Créez une nouvelle feuille que vous nommerez GrilleSimple, et dans cette feuille, créez un groupe de 11
contrôles TextBox de nom TextEdit qui afficheront l'enregistrement principal, une DataGrid que vous nommerez
DataGrid1 pour les enregistrements enfants et un groupe de quatre boutons de commande pour la navigation dans
le jeu d'enregistrements, que vous nommerez btnNav.

Nous ne détaillerons pas ici la création de ces objets, mis à part la DataGrid. Si vous rencontrez quelques
problèmes, ou si vous ne savez pas faire, c'est que vous avez sauté des étapes en commençant par ce praticiel.
Aussi, je vous recommande les divers praticiels que j'ai réalisés et que vous trouverez à l'adresse
http//jacma.developpez.com. Vous y trouverez tout ce qu'il faut concernant la création et l'utilisation de ces objets

21 – LA SECTION DÉCLARATION

Ligne Code Commentaires


1 Option Explicit Selon notre bonne habitude, pour forcer la déclaration
des variables.
2 Dim cn As ADODB.Connection Déclaration de l'objet Connection.
3 Dim rsPub As ADODB.Recordset Déclaration du recordset rsPub, qui sera, rappelons le,
un recordset hiérarchique.
4 Dim colBndBiblio As BindingCollection Déclaration de la collection Binding.
5 Private Enum NavBtn Déclaration d'un type Enum (une énumération).
cmdPremier = 0 Chaque variable de cette énumération permet de faire
cmdPrecedent = 1 correspondre une variable à une constante. Ainsi, il
cmdSuivant = 2 est possible d'utiliser indifféremment la constante ou la
cmdDernier = 3 variable qui lui correspond. Dans notre cas, le chiffre 0
cmdAjouter = 4 correspondait donc à cmdPremier. Nous utiliserons
End Enum ces variables d'énumération pour faire référence
nommément à un bouton de commande, plutôt que
par son index dans la collection des dits boutons.
Quelques précisions. Le recordset rsPub sera utilisé dans plusieurs procédures de la feuille. C'est pour
cela qu'il est déclaré au niveau module, ce qui fait qu'il est lisible depuis toute procédure du dit module.
L'énumération quant à elle doit obligatoirement être déclarée au niveau module. Elle peut être privée (c'est la cas
ici) ou publique. Dans le second cas, elle est visible dans tout le projet, et non seulement depuis le module.

22 – PROCÉDURE FORMLOAD

Dans cette procédure, nous créerons le recordset, la BindingCollection, et nous définirons les sources des
contrôles du formulaire, notamment pour la DataGrid.
Ligne Code Commentaires
1 Private Sub Form_Load() Procédure événementielle (chargement de la feuille)
2 Dim SQL As String Déclaration de la variable SQL en tant que chaîne de
caractères. Cette variable recevra la chaîne SQL pour
la création du recordset.
3 Set cn = New ADODB.Connection Attribue à la variable, déclarée dans la section de
déclaration de la feuille de code (ligne 2 § 11), la
référence à l'objet connection. Sans cette ligne de
code, l'objet connection resterait inconnu de
l'application, la seule déclaration étant insuffisante
(voir remarque ci après)..
4 Set rsPub = New ADODB.Recordset Idem que ligne précédente pour l'objet recordset…
5 Set colBndBiblio = New BindingCollection … et pour la collection binding.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 24
_____________________________________________________________________________________________________

6 cn.Provider = "MSDataShape" On déclare ici le fournisseur MSDataShape pour la


connexion. Ce fournisseur (service Microsoft Data
Shaping Service pour OLE DB) est spécifique à la
mise en forme des recordsets hiérarchiques, c'est-à-
dire en fait à la création et à l'utilisation de tels
recordset. Il convient de le déclarer avant la
connexion.
7 cn.Open "Data Création de la connexion. Remarquez le "Data
Provider=Microsoft.Jet.OLEDB.4.0;Data Provider". Habituellement, on utilise "Provider" seul,
Source=C:\DidactDB\Biblio2000.mdb" mais là, il y a déjà un provider de déclaré pour la mise
en forme des données. Donc, il nous faut spécifier que
ce second provider est relatif aux données.
8 SQL = "SHAPE {SELECT * FROM Création de la chaîne de création du recordset. La
Publishers ORDER BY Name} APPEND " & _ syntaxe, bien qu'inhabituelle, n'est pas très difficile et
"({SELECT ISBN, PubID, Titille, [Year on s'y fait vite. A défaut, rappelez vous que vous
Published], Description, Subject, Notes FROM pouvez utiliser un objet command (voir section 1) pour
Titles} " & _ créer automatiquement cette chaîne et la récupérer
"AS Title RELATE PubID TO PubID)" dans votre code par un copier/coller.
Le premier SELECT spécifie la table parents et le
second la table enfants. Ici, toutes les colonnes de la
table parents seront prises en compte (l'étoile *), alors
que les seules colonnes spécifiées le seront pour la
table enfant. Notez le "AS Title" qui affecte le nom
Title en tant qu'alias des enregistrements enfants de
l'enregistrement parent en cours. C'est une sorte de
colonne supplémentaire au recordset qui contient les
dits enregistrements enfants. Nous verrons à l'utiliser
ligne 23.
9 rsPub.Open SQL, cn, adOpenDynamic, Ouverture du recordset hiérarchique. Si vous ne
adLockOptimistic, adCmdText comprenez pas le sens des paramètres, il vous serait
probablement nécessaire de voir ou revoir les bases
de la création de recordsets.
10 rsPub.MoveFirst C'est toujours une bonne précaution. Ainsi, nous
sommes sûr que l'enregistrement en cours du
recordset que nous venons de créer est bien le
premier du jeu et que c'est donc celui-ci qui sera
affiché.
11 Set colBndBiblio.DataSource = rsPub Définit le jeu d'enregistrements rsPub comme source
de données (DataSource) de la collection binding
colBndBiblio. Une collection binding permet de
définir des contrôles comme étant liés à une source
de données. Donc ici, tous les éléments de la
collection auront pour source le recordset hiérarchique
rsPub.
12 With colBndBiblio Dans ce bloc With, nous ajoutons à la collection
13 .Add TextEdit(0), "Text", "PubID", , "ID" binding les TextBox que nous voulons relier aux
14 .Add TextEdit(1), "Text", "Name", , "Nom" données de rsPub.
15 .Add TextEdit(2), "Text", "Company En l'occurrence, on ajoute le contrôle à lier (ici
Name", , "Société" TextEdit(index), dont on déclare le type (ici "Text"), et
16 .Add TextEdit(3), "Text", "Address", , pour lequel on précise le nom de la colonne source de
"Adresse" données auquel il sera lié. On pourrait en préciser le
17 .Add TextEdit(4), "Text", "City", , "Localité" format, ce que nous n'avons pas fait ici, d'où les deux
18 .Add TextEdit(5), "Text", "State", , "Etat" virgules sans rien entre (après le nom de la colonne).
19 .Add TextEdit(7), "Text", "Telephone", , Le dernier paramètre sert à identifier d'une manière
"Téléphone" unique le membre de la collection, ce qui remplacera

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 25
_____________________________________________________________________________________________________

20 .Add TextEdit(8), "Text", "Fax", , l'utilisation de l'index dans la dite collection.


"Télécopie" Les deux derniers paramètres sont facultatifs.
21 .Add TextEdit(9), "Text", "Zip", , "Zip"
22 .Add TextEdit(10), "Text", "Comments", ,
"Commentaires"
23 End With
24 Set DataGrid1.DataSource = On indique ici la source de la DataGrid. Cette source
rsPub!Title.Value est constituée par les valeurs contenues dans la
"colonne"Title", valeurs qui sont en fait les
enregistrements enfants de l'enregistrement parent en
court. En conséquence, les enregistrements enfants
de l'enregistrement parent en cours seront affichés
dans la grille, tous, mais eux seuls.
25 End Sub

On pourrait faire d'une pierre deux coups en déclarant la variable cn selon la syntaxe
dim cn as New ADODB.Connection
mais cette syntaxe est inutilisable dans la section de déclaration. Elle n'est possible que dans une
procédure. Donc, il nous faut nous y prendre en deux temps ici.

3 – LA NAVIGATION DANS LE RECORDSET

Il s'agit ici d'une navigation sommaire nous permettant simplement de parcourir le jeu d'enregistrements.
Reportez vous aux autres praticiels de la série Praticiels Visual Basic, notamment "Accès aux données ADO" et
"Initiation à l'accès aux données" pour plus de développement et d'explication.
Ligne Code Commentaires
1 Private Sub btnNav_Click(Index As Integer) La procédure évènementielle reçoit en paramètre
l'index du bouton de commande sur lequel il a été
cliqué.
2 Select Case Index Selon cette index…
3 Case cmdPremier
4 rsPub.MoveFirst
5 Case cmdPrecedent
6 If Not rsPub.BOF Then Pour éviter une erreur…
7 rsPub.MovePrevious On teste si on a atteint la limite du recordset, pour le
8 Else début BOF et pour la fin EOF. Si c'est le cas la
9 rsPub.MoveLast navigation se continue respectivement depuis la fin ou
10 End If depuis le début du dit recordset (en boucle donc).
11 Case cmdSuivant
12 If Not rsPub.EOF Then
13 rsPub.MoveNext
14 Else: rsPub.MoveFirst
15 End If
16 Case cmdDernier
17 rsPub.MoveLast
18 End Select
19 End Sub

4 – UTILISATION D'UNE DATACOMBO POUR SÉLECTIONNER UN ENREGISTREMENT

C'est une question récurrente que de sélectionner un enregistrement, qu'il soit issu d'un recordset
hiérarchique ou d'un simple recordset, en cliquant sur un item d'une combo (ou d'une liste, c'est pratiquement
identique). En fait, je devrais dire que c'est un ensemble de questions récurrente du style comment remplir la partie
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 26
_____________________________________________________________________________________________________

liste d'une combo, comment afficher la valeur de l'item sélectionné, comment trouver l'enregistrement
correspondant…

Nous allons donc créer et mettre en œuvre une DataCombo. Ce composant est spécialement adapté pour
une utilisation avec ADO, mais son code et ses propriétés sont compatibles avec une DBCombo (ou DBList).

Un contrôle DataCombo est une liste modifiable dépendante. La liste qu'il présente est constituée
automatiquement à partir des valeurs d'un champ d'une source de données liées. Il permet éventuellement de
mettre à jour un champ d'une table connexe d'une autre source de données, mais nous ne traiterons pas cet
aspect ici. Voyez MSDN qui explique assez bien cette possibilité.

41 – CRÉATION DE LA DATACOMBO ET CODE NÉCESSAIRE

Il vous faut déclarer le composant MicrosoftDataList Controls 6.0 (SP3) (OLEDB), autrement dit
MSDATLST.OCX, dans la boîte à outils. Insérez ensuite le contrôle dans votre form et affectez lui le nom
dcPublishers (dc pour DataCombo, Publishers car c'est leur liste qui sera affichée. Je donne souvent, sinon
toujours, un nom significatif aux objets et variables, nom doté d'un préfixe essayant de respecter certaines
normes).

Dans la procédure Form Load, insérez juste avant la ligne 25 les lignes de code suivantes.
Ligne Code Commentaires
26 Set dcPublishers.RowSource = rsPub Définition de la source des valeurs qui constituerons la
liste du contrôle. Ces valeurs sont dans le recordset
rsPub…
27 dcPublishers.ListField = "Name" … et plus précisément dans la colonne Name du dit
recordset. La propriété ListField précise donc la
colonne du recordset dont les valeurs seront
affichées.
28 dcPublishers.MatchEntry =
dblBasicMatching
29 'dcPublishers.Style = 2 Remarquez que cette ligne est en commentaire, donc
non opérationnelle. J'ai souhaité néanmoins l'afficher,
car la propriété Style de la Combo ne peut être utilisée
qu'en lecture seule au moment de l'exécution; Donc,
dans une ligne de code, elle provoque une erreur!
Il faut donc définir cette propriété dans la fenêtre des
propriétés du contrôle. Faites le tout de suite.
Ah oui… Cette propriété définit le type d'affichage du
contrôle. La valeur 2 ici définie correspond à la
constante VbComboDrop-DownList qui définit un
style permettant seulement de sélectionner un item de
la liste déroulante.
30 End Sub Nouvelle fin de la procédure Form_ Load

Nous aurions pu ici définir également les propriétés DataSource (rsPub) et DataField ("Name") de la
combo, ce qui aurait eu pour effet de la lier au recordset, et plus précisément à la colonne Name. Cela
nous aurait évité d'avoir à synchroniser la Combo avec l'enregistrement courant. Nous préférons
cependant gérer cette synchronisation comme nous allons le faire, en ajoutant une ligne de code dans
la procédure de navigation btnNav_Click ainsi que dans la procédure évènementielle Activate, comme
suit. Ces deux propriétés sont généralement utilisées dans le cadre d'une mise à jour d'un champ d'une
seconde base de donnée, tel que défini dans MSDN rubrique "BoundColumn, propriété".

Dan la procédure btnNav_Click, juste avant la ligne 19, ajoutez la ligne de code suivante

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 27
_____________________________________________________________________________________________________

Ligne Code Commentaires


19 dcPublishers = rsPub!Name On affecte à la DataCombo la valeur contenue dans la
colonne Name de l'enregistrement courant du
recordset. Ainsi, les deux contrôles sont synchronisés.
20 End SUB Nouvelle fin de la procédure btnNav_Click.
La procédure évènementielle Form_Activate ci-dessous se produit quand la fenêtre devient la fenêtre
active. Elle se produit non seulement au chargement de la feuille, mais lorsque elle activée par du code, ou quand
elle reçoit le focus par exemple. Si nous avions écrit le code qu'elle contient dans la procédure évènementielle
Form_Load, la synchronisation et la définition de la DataCombo comme étant le contrôle actif n'auraient pas lieu
lorsque par exemple, la feuille redeviendrait active après avoir été "recouverte" par une autre sans avoir pour
autant été fermée.
Ligne Code Commentaires
1 Private Sub Form_Activate()
2 dcPublishers = rsPub!Name La combo prend pour valeur la valeur de la colonne
Name de l'enregistrement courant du recordset.
3 Me.dcPublishers.SetFocus La combo devient le contrôle actif (elle reçoit le focus).
Ainsi, par défaut, la form est "paramétrée" pour une
recherche, ce pour quoi elle est destinée en premier
lieu dans ce contexte. Cela évitera certaines erreur de
manipulation, à savoir la saisie de caractères de
recherches dans un contrôle inadéquat (les
automatismes nous jouent parfois de mauvais
tours…)..
4 End Sub

Pour finir, ajoutez la procédure évènementielle suivante, qui se produit lors un double clic sur un des item
de la liste de la combo. Cette procédure recherche l'enregistrement du recordset dont la valeur de la colonne
Name correspond à la valeur de la combo.
Ligne Code Commentaires
1 Private Sub dcPublishers_DblClick(Area As
Integer)
2 If dcPublishers <> "" Then Nous testons si la combo n'est pas vide afin d'éviter
une erreur.
3 rsPub.Find "Name = '" & dcPublishers & " La combo contient donc une valeur qui va nous servir
'", , , 0 de critère de recherche. La syntaxe générale la plus
élémentaire de la méthode Find est constituée d'une
chaîne de caractères spécifiant le nom de la colonne,
l'opérateur de comparaison et la valeur à rechercher,
valeur entourée d'une simple quotte..
Dans le cas présent, la valeur à rechercher est
contenue dans le contrôle dcPublishers. Donc, comme
pour l'utilisation d'une variable, il convient de "sortir"
ce nom de la chaîne et de le concaténer avec le nom
de la colonne. De plus, il ne faut pas oublier les
simples quottes qui, elles, "restent" dans la chaîne
Les autres paramètres de la méthode sont facultatifs.
Nous indiquons seulement que la recherche doit
commencer depuis le début du recordset par
l'argument 0, sinon la recherche débute par défaut sur
l'enregistrement en cours. Ce dernier paramètre étant
précédé de deux autres, n'oubliez pas les virgules,
sinon VB y perdrait son latin.
4 End If
5 End Sub
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST SECTION 2 – RECORDSET HIÉRARCHIQUE ET DATAGRID Page 28
_____________________________________________________________________________________________________

La syntaxe de la méthode Find est constituée successivement d'un guillemet double, du nom de la
colonne, de l'opérateur de comparaison, d'une simple quotte, d'un guillemet double, du caractère de
concaténation &, du nom de la combo (contenant la valeur à rechercher), du caractère de concaténation,
d'un guillemet double, d'une simple quotte d'un guillemet double. Le tout, une fois la concaténation
effectuée, constituant une seule chaîne de caractères. J'ai ici détaillé précisément cette syntaxe, car elle
est à l'origine de questions récurrentes la concernant.

Voilà donc notre feuille terminée et qui répond bien aux objectifs que nous nous étions fixés. Elle pourra
être sans doute le point de départ ou d'achoppement pour nombre de vos applications concernant l'accès aux
données.

Dans la section suivante, nous allons rendre une MSHFlexGrid modifiable.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 29
_____________________________________________________________________________________________________

SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE

Comme nous l'avons déjà dit, la MSHFlexGrid en l'état ne permet ni la mise à jour, ni la création
d'enregistrement. Elle ne permet que leur lecture. C'est assez frustrant. Dans le présent paragraphe, nous allons
faire le nécessaire pour passer outre à cette restriction, mais ce sera plus un exercice de style ou un moyen de
s'entraîner qu'une véritable solution pratique pour utiliser un recordset hiérarchique, tout au moins à mon avis (que
je partage encore ).

Cette approche est fortement inspirée de MSDN, chapitre "Édition de cellules dans un tableur Hierarchical
FlexGrid ", tout au moins en ce qui concerne la modification des cellules de la grille. Cependant, nous y avons
ajouté la création et la suppression de lignes et notre grille a pour source un recordset hiérarchique, ce qui pose
certains problèmes, comme nous le constaterons. L'exemple MSDN quant à lui ne traite pas d'une grille
dépendante des données, mais d'une grille vide, et donc encore moins d'une grille affichant des données
hiérarchiques.

1 – DÉMARCHE GÉNÉRALE

Comme il n'est pas possible de saisir directement dans une case de la MSHFlexGrid, quelqu'un (pas bête,
le mec…) a donc pensé qu'il suffisait de "remplacer" la dite case par une TextBox, afin de simuler une cellule. Bien
sur, il faut cette la zone de texte soit toujours positionnée sur la case voulue. Une fois la saisie réalisée, il suffit
alors de copier le contenu de la zone de texte dans la case de la MSHFlexGrid, puis de mettre à jour le recordset.

Deux types de modifications sont pris en compte: un ajout à la fin de la valeur contenue dans une cellule ou
l'effacement de cette valeur et son remplacement par une autre.

La modification d'une cellule sera déclenchée soit par un double clic sur la dite cellule, soit sur l'appui de la
barre d'espace. Dans ce second cas, la cellule à modifier sera la cellule active lors de l'appui sur la barre espace.

Concernant la création ou la suppression d'une ligne, c'est un tout petit peu plus compliqué, car il faut agir
sur le recordset et mettre à jour la MSHFlexGrid d'après le recordset modifié. Mais ce n'est quand même pas la
mort du petit cheval, comme nous allons le constater. Précisons à ce sujet que nous créerons systématiquement
(et automatiquement) une ligne vide à chaque ouverture de la form s'il n'en existe aucune, de façon à ce que
l'utilisateur ait toujours une ligne à sa disposition pour ajouter un enregistrement.

2 - REALISATION

21 – SECTION DE DÉCLARATIONS ET CHARGEMENT DE LA FORM

Créez tout d'abord une nouvelle feuille que vous nommerez MSHSModifiable et insérez une MSHfexGrid
que vous nommerez GrilleMSH. Et, tan que vous y êtes, créez également une TextBox sur la grille que vous
nommerez TextEdit. Vous devriez obtenir une fenêtre comme ci-dessous

Nous allons maintenant créer un recordset hiérarchique et paramétrer la MSHFlexGrid. La démarche pour
ce faire est identique à celle suivie dans les sections précédentes. Aussi, nous ne détaillerons que les points qui
diffèrent.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 30
_____________________________________________________________________________________________________

Ligne Code Commentaires


1 Option Explicit Nous déclarons ces objets dans cette section de
2 Dim cn As ADODB.Connection déclaration afin qu'ils soient accessibles se toutes les
3 Dim rsPub As ADODB.Recordset procédures de la form.
4 Dim bVide As Boolean La variable booléenne bFlag servira lors de la création
5 Dim bFlag As Boolean d'une nouvelle ligne dans la grille.

22 – PROCÉDURES POUR LE CHARGEMENT DE LA FORM

Nous utiliserons deux procédures lors du chargement de la form. Dans la procédure évènementielle
Form_Load, nous établirons la connexion avec la base de données. Cette procédure en appellera une seconde
pour la création du recordset hiérarchique.

Habituellement, ces deux opérations sont regroupées dans la procédure évènementielle elle-même, mais
nous devrons créer ou rafraîchir notre recordset plusieurs fois en dehors de l'ouverture de la feuille, d'où une
procédure spécifique.

221 – PROCÉDURE FORM_LOAD


Ligne Code Commentaires
1 Private Sub Form_Load()
2 Dim SQL As String
3 Set cn = New ADODB.Connection
4 Set rsPub = New ADODB.Recordset
cn.Provider = "MSDataShape"
cn.Open "Data Pensez à modifier éventuellement le chemin de la
Provider=Microsoft.Jet.OLEDB.4.0;Data base.
Source=C:\DidactDB\Biblio2000.mdb"
TxtEdit = "" Initialisation de la zone de texte.
Grille_Recordset Appel de la procédure Grille_Recordset chargée de la
création du recordset.
Grille_Formatage Appel de la procédure Grille_Recordset dans laquelle
nous avons écrit tout ce qui est relatif au formatage de
la grille. Il vaut toujours mieux traiter des procédures
petites et spécialisée que des procédures "énormes".
Cela rend leur écriture et leur maintenance plus facile.
GrilleMSH.CollapseAll (0)
5 End Sub

222 - CRÉATION DU RECORDSET

Comme déjà précisé, cette procédure est appelée non seulement lors de l'évènement Form_Load, mais
aussi lors du rafraîchissement de la grille après création ou suppression d'une ligne et donc d'un enregistrement du
recordset.

Rappelons que nous créons systématiquement une nouvelle ligne lors de l'ouverture de la form, si toutefois
il n'en n'existe aucune. Il nous faudra donc distinguer dans la procédure Grille_Recordset suivante si elle s'exécute
dans un contexte d'ouverture de la form ou dans un contexte de modification de la valeur d'une colonne pour une
ligne existante. De plus, il nous faudra également préciser si la cellule en cours de modification appartient à une
ligne nouvellement créée ou non, car dans le premier cas, nous créerons une nouvelle ligne après sa modification
de manière à avoir toujours une ligne disponible. Oui, je sais, c'est compliqué . Accrochez vous et décomposez
pas à pas…

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 31
_____________________________________________________________________________________________________

Ligne Code Commentaires


1 Private Sub Grille_Recordset()
2 Dim SQL As String
3 Set rsPub = New ADODB.Recordset
4 SQL = "SHAPE {SELECT * FROM Rappelons que le champ Year Published est encadré
Publishers} APPEND ({SELECT ISBN, PubID, de crochets droits car son nom comporte un espace.
Title, [Year Published], Description, Subject, Nous vous conseillons fortement de scinder cette
Notes FROM Titles} AS Title "RELATE PubID chaîne en plusieurs morceaux an utilisant des &,
TO PubID)" caractères de soulignement et retour chariot. Si cette
démarche vous semble absconde, référé vous
notamment aux sources du projet VB dans lesquelles
cette chaîne de caractère est composée de plusieurs
partie, et donc nettement plus lisible.
5 rsPub.Open SQL, cn, adOpenDynamic,
adLockOptimistic, adCmdText
6 Set GrilleMSH.DataSource = rsPub La source du la grille hiérarchique est rsPub.
7 If GrilleMSH.TextMatrix(GrilleMSH.Rows - 1, Ce test permet de déterminer dans quel contexte nous
2) <> "*" And bFlag = False Then sommes.
Si la valeur de la seconde colonne de la dernière ligne
(Rows – 1) de la grille est différente de "*", cela
signifie qu'aucune ligne nouvelle n'a été crée
précédemment (lors d'une ouverture précédente de la
form).
La valeur False du drapeau bFlag signifie qu'aucune
création de nouvelle ligne n'est en cours. En clair,
nous sommes au tout début du processus. Nous y
verrons plus clair ultérieurement (§26).
8 bVide = True Le passage à True de la variable booléenne permettra
ultérieurement de préciser le contexte, en l'occurrence
modification d'une ligne nouvellement créée).
9 bFlag = True
10 Ajouter_Ligne Vu le contexte (pas de ligne vide et aucune création
d'une nouvelle ligne en cours) nous appelons la
procédure Ajouter_Ligne pour ajouter une ligne à la
grille.
11 End If
12 End Sub

223 – FORMATAGE DE LA MSHFLEXGRID

Rien de bien particulier, mais enfoncer le clou est un bon précepte. Alors, astreignez-vous à reproduire ce
code et au besoin, reportez vous aux sections précédentes pour toute explication détaillée.
Ligne Code Commentaires
1 Private Sub Grille_Formatage()
2 Dim i As Long
3 Dim strNomCol As String
4 With GrilleMSH
3 .ColHeader(0) = (flexColHeaderOn) Définition des titres des colonnes pour la première
4 .ColHeaderCaption(0, 1) = "PubID" bande (bande 0).
5 .ColHeaderCaption(0, 2) = "Nom"
6 .ColHeaderCaption(0, 3) = "Société"
7 .ColHeaderCaption(0, 4) = "Adresse"
8 .ColHeaderCaption(0, 5) = "Localité"
9 .ColHeaderCaption(0, 6) = "Etat"
10 .ColHeaderCaption(0, 7) = "Zip"

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 32
_____________________________________________________________________________________________________

11 .ColHeaderCaption(0, 8) = "Téléphone"
12 .ColHeaderCaption(0, 9) = "Fax"
13 .ColHeaderCaption(0, 10) =
"Commentaires"
14 .ColHeader(1) = (flexColHeaderOn) Définition des titres des colonnes pour la seconde
15 .ColHeaderCaption(1, 0) = "ISBN" bande (bande 1).
16 .ColHeaderCaption(1, 1) = "PubID"
17 .ColHeaderCaption(1, 2) = "Titre"
18 .ColHeaderCaption(1, 3) = "Année
parution"
19 .ColHeaderCaption(1, 4) = "Descriptif"
20 .ColHeaderCaption(1, 5) = "Notes"
21 .ColHeaderCaption(1, 6) = "Sujet"
22 .BandIndent(1) = 3 Indentation de la bande 1 (les ouvrages) et coloration.
23 .BackColorIndent(1) = vbYellow
24 For i = 0 To .Cols - 1 Alignement des titres de colonnes pour la bande 0
25 .ColAlignmentHeader(0, i) = 4
26 Next
27 For i = 0 To .Cols - (.BandIndent(1) + 1) Alignement des titres de colonnes pour la bande 1
28 .ColAlignmentHeader(1, i) = 4
29 .ColAlignmentBand(0, i) = 9
30 .ColAlignmentBand(1, i) = 9
31 Next
32 .ColWidth(0, 0) = 500 Définition de la largeur des colonnes première bande
33 .ColWidth(1, 0) = 600 (bande 0)
34 .ColWidth(2, 0) = 1500
35 .ColWidth(3, 0) = 2000
36 .ColWidth(4, 0) = 2000
37 .ColWidth(5, 0) = 750
38 .ColWidth(6, 0) = 750
39 .ColWidth(7, 0) = 1000
40 .ColWidth(0, 1) = 1000 Définition de la largeur des colonnes seconde bande
41 .ColWidth(1, 1) = 1000 (bande 1)
42 .ColWidth(2, 1) = 1000
43 .ColWidth(3, 1) = 1000
44 .ColWidth(4, 1) = 1000
45 .ColWidth(5, 1) = 1000
46 .ColWidth(6, 1) = 1000
47 .ExpandAll Développement des bandes.
48 .Col = 1 Définition de la cellule active: première colonne de la
49 .Row = 1 première ligne.
50 End With
51 End Sub

23 – INTERCEPTION ET TRAITEMENT DES APPUIS DES TOUCHES CLAVIER (ANSI)

L'idée générale des procédures de ce chapitre est d'intercepter une action de l'utilisateur telle que appui sur
une touche de clavier ou double clic afin de déclencher l'action voulue. En fait, nous voulons traiter soit l'appui sur
la barre d'espace, soit un double clic (qui sera assimilé à l'appui sur la barre espace) afin de déclencher la
modification de la cellule active.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 33
_____________________________________________________________________________________________________

Ligne Code Commentaires


1 Sub GrilleMSH_KeyPress(KeyAscii As Procédure évènementielle se produisant sur l'appui
Integer) d'une touche. Cette procédure intercepte tout appui de
touche afin de déclencher une action en
conséquence.
2 MSHFlexGridEdit GrilleMSH, TxtEdit, Appel de la procédure MSHFlexGridEdit avec
KeyAscii transmission en tant que paramètres des contrôles
(grille et zone de texte) et du code ASCII de la
touches actionnée.
3 End Sub

Dans la procédure précédente, nous utilisons l'évènement KeyPress, qui se produit sur l'appui d'une
touche ANSI du clavier.Le jeu de caractère ANSI prend en compte" les 128 premiers caractères (de 0 à
127) correspondent aux lettres et aux symboles du clavier nord-américain standard. Les 128 caractères
suivants (de 128 à 255) représentent les caractères spéciaux, comme les lettres de certains alphabets,
les accents, les symboles monétaires et les fractions" (tiré de MSDN).

Ligne Code Commentaires


1 Sub GrilleMSH_DblClick() Procédure évènementielle se produisant sur un
double clic dans la grille. Cette procédure intercepte
un double clic afin de déclencher une action en
conséquence.
2 MSHFlexGridEdit GrilleMSH, TxtEdit, 32 Appel de la procédure MSHFlexGridEdit avec
transmission en tant que paramètres des contrôles
(grille et zone de texte). Le code ASCII 32 simule un
espace.
3 End Sub

Cette procédure initialise la zone de texte. Le focus passe de la grille à la zone de texte, puis que c'est
dans cette zone de texte que sera effectuée la saisie. Le contenu de cette zone sera ensuite ajouté au contenu de
la cellule ou l'écrasera, selon la touche ayant été actionnée.
Ligne Code Commentaires
1 Sub MSHFlexGridEdit(MSHFlexGrid As Cette procédure reçoit en paramètre les contrôles
Control, Edt As Control, KeyAscii As Integer) grille et zone de texte, et la valeur ASCII de la touche
appuyée.
2 Select Case KeyAscii
3 Case 0 To 32 Correspond à un appui sur la barre espace ou un
double clic. Le contenu de la case sera complété par
la saisie.
4 Edt = MSHFlexGrid Le contrôle Edt(c'est toujours TxtEdit, reçut en
paramètre) reçoit la valeur de la case en cours de la
grille MSHFlexGrid (GrilleMSH passé en paramètre).
5 Edt.SelStart = 1000 Modification en fin de texte du contenu de la zone de
texte. La propriété SelStart indique le point d'insertion
pour un ajout. Étant définie à 1000, valeur sans aucun
doute supérieure à la longueur du texte déjà présent
dans la case de la grille, cela place le point d'insertion
juste à la fin de la chaîne contenue dans la dite
cellule.
6 Case Else L'utilisateur a appuyé sur une autre touche que les
deux précédentes. Le contenu de la case sera donc
écrasé et remplacé par la saisie.
7 Edt = Chr(KeyAscii) La zone de texte reçoit la valeur Ascii de la touche
actionnée.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 34
_____________________________________________________________________________________________________

8 Edt.SelStart = 1 Le point d'insertion (voir ligne 5 ci-dessus) est défini à


1. Donc en fait, la saisie remplacera la totalité de la
chaîne de caractères contenue dans la zone de texte.
9 End Select
10 Edt.Move (MSHFlexGrid.Left + Déplacement et dimensionnement de la zone de texte
MSHFlexGrid.CellLeft), (MSHFlexGrid.Top + qui vient "recouvrir" la cellule en cours de la grille. La
MSHFlexGrid.CellTop), formule peut paraître quelque peu complexe. En effet,
(MSHFlexGrid.CellWidth - 8), elle doit tenir compte non seulement de la position de
(MSHFlexGrid.CellHeight - 8) la cellule, mais aussi de la position de la grille elle-
même.
Ainsi par exemple, MSHFlexGrid.Left +
MSHFlexGrid.CellLeft fixe la position horizontale de
la zone de texte à la valeur de l'abscisse de la grille
plus la valeur de l'abscisse de la cellule en cours.
Quant aux dimensions de la zone de texte, elles sont
légèrement inférieures (-8) que celles de la cellule
active de la grille.
11 Edt.Visible = True La zone de texte devient visible…
12 Edt.SetFocus … et reçoit le focus.
13 End Sub

24 – INTERCEPTION ET TRAITEMENT DES APPUIS DES TOUCHES DE FONCTION

Ligne Code Commentaires


1 Sub txtEdit_KeyDown(KeyCode As Integer,
Shift As Integer)
2 EditKeyCode GrilleMSH, TxtEdit, KeyCode,
Shift
3 End Sub

La procédure précédente utilise l'évènement KeyDown (touche enfoncée). Cet évènement, comme
l'évènement KeyUp, permet de traiter des touches en dehors du jeu de caractère Ansi, telles que les
touches de fonction ou de navigation, ainsi que les combinaisons de touches (avec ALT, MAJ et CTRL).

Ligne Code Commentaires


1 Sub EditKeyCode(MSHFlexGrid As Control, La procédure reçoit en paramètres la grille, la zone de
Edt As Control, KeyCode As Integer, Shift As texte, le code de la touche utilisée et le code indiquant
Integer) si c'est un caractère majuscule. Seuls les trois
premiers paramètres nous seront utiles.
2 Select Case KeyCode
3 Case 27 Appui sur ECHAP. Annulation de l'opération en cours.
4 Edt.Visible = False La zone de texte devient invisible…
MSHFlexGrid.SetFocus … et la grille reçoit le focus. Elle redevient le contrôle
actif.
Case 13 Appui sur ENTER pour validation de la saisie.
MSHFlexGrid.SetFocus La grille reçoit le focus.
Case 38 Appui sur FLECHE HAUT pour atteindre la ligne
précédente..
MSHFlexGrid.SetFocus La grille reçoit le focus.
DoEvents On permet au système de terminer l'opération.
If MSHFlexGrid.Row > Si la ligne atteinte est une ligne fixe, on passe à la
MSHFlexGrid.FixedRows Then ligne précédente.
MSHFlexGrid.Row = MSHFlexGrid.Row -
1
End If

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 35
_____________________________________________________________________________________________________

Case 40 Appui sur FLECHE BAS pour atteindre la ligne


suivante.
MSHFlexGrid.SetFocus Retour à la grille.
DoEvents
If MSHFlexGrid.Row < MSHFlexGrid.Rows Si la ligne suivante est "hors limite" (index supérieur
- 1 Then au nombre de lignes de la grille – 1(l'index commence
MSHFlexGrid.Row = MSHFlexGrid.Row + à 0)), on revient à la ligne précédente. Sinon,une
1 erreur serait générée.
End If
End Select
End Sub

25 - MISE À JOUR DE LA GRILLE

Ligne Code Commentaires


1 Sub GrilleMSH_GotFocus() Procédure évènementielle sur réception du focus par
la grille.
2 If TxtEdit.Visible = False Then Exit Sub Si la zone de texte n'est pas visible, ce qui signifie
qu'aucune saisie n'est en cours et donc qu'il n'y aura
pas de mise à jour a effectuer, la procédure se termine
là.
3 GrilleMSH = TxtEdit La cellule active de la grille reçoit la valeur contenue
dans la zone de texte.
4 TxtEdit.Visible = False La zone de texte repasse invisible.
5 End Sub

Dans la procédure précédente, aucune mise à jour n'est nécessaire. La zone de texte peut être renseignée
ou non, de toute façon les opérations se poursuivront selon el contexte. Il n'est donc pas fait appel à la procédure
de mise à jour, contrairement à la procédure évènementielle qui suit (ligne 5).
Ligne Code Commentaires
1 Sub GrilleMSH_LeaveCell() Procédure évènementielle se produisant avant un
changement de la cellule active de la grille.
2 If TxtEdit.Visible = False Then Exit Sub
3 GrilleMSH = TxtEdit
4 TxtEdit.Visible = False
5 MiseAJour Appel à la procédure de mise à jour.
6 End Sub

26 - AJOUT D'UNE NOUVELLE LIGNE À LA GRILLE

261- PRINCIPE

Jusqu'à maintenant, il n'a été question que de modifications de valeurs contenues dans des cellules de la
MSHFlexGrid. L'ajout de ligne(s) supplémentaire(s) est légèrement plus compliqué, du fait de deux raisons:
 Il n'existe pas de ligne vide dans la grille, puisque le nombre de ses lignes correspond au nombre
d'enregistrements du recordset.
 Il n'est pas possible d'ajouter une ligne à une MSHFlexGrid dont la source est un recordset hiérarchique.
La ligne de code GrilleMSH.Rows = GrilleMSH.Rows + 1 renvoie "Erreur 30021 – Commande
non disponible lorsqu'elle est liée à des données hiérarchiques".
Comme il ne semble pas possible d'agir directement sur la grille, nous ajouterons dans un premier temps
un enregistrement (que nous qualifions de "bidon", car ne correspondant encore à rien) au recordset et
exécuterons un refresh de la grille. Nous aurons alors une nouvelle ligne ajoutée à la fin de la grille hiérarchique,

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 36
_____________________________________________________________________________________________________

ligne dont les colonnes seront vides, si nous ne tenons pas compte de la valeur "*" que nous avons attribué à la
colonne Name du recordset, l'étoile étant plus repérable qu'un simple espace (que nous aurions pu utiliser).

Dans un second temps, nous saisirons dans les colonnes de cette nouvelle ligne les valeurs voulues. Cette
seconde phase est en fait une phase de modification, traitée comme telle dans le code.

262 – PHASE D'OUVERTURE DE LA FORM

Au risque de me répéter, car il est nécessaire de bien appréhender la situation, à l'ouverture de la form, la
grille ne présente pas de ligne vide disponible. Nous allons donc faire en sorte d'en créer une.

Logiquement, il conviendrait probablement mieux de ne créer cette nouvelle ligne que si elle est vraiment
nécessaire, et non systématiquement. Mais vous pourrez très bien adapter le code pour qu'il ne s'exécute que sur
le clic d'un bouton de commande par exemple.

La procédure suivante peut être appelée dans deux contextes différents:


 une phase d'ouverture d'une form (depuis la procédure Grille_Recordset);
 une phase de mise à jour d'une colonne pour une ligne existante (depuis la procédure MiseAJour).
Le contexte est déterminé par la variable booléenne bVide, dont la valeur True signifie que la modification
en cours porte sur une ligne nouvellement créée (voir § 222 et notamment la ligne 7 et suite du code).

Ligne Code Commentaires


1 Private Sub Ajouter_Ligne()
2 If bVide = True Then Création d'un enregistrement vide, le précédent étant
mis à jour
3 GrilleMSH.MousePointer = vbHourglass Affichage d'un sablier pendant la durée de l'opération.
4 With rsPub
5 rsPub.AddNew Mise en mode ajout pour le recordset.
6 rsPub!Name = "*" Ajout d'un enregistrement "bidon". Nous avons affecté
la valeur "*" à la colonne Name du recordset. On
aurait pu simplement mettre un espace, mais ainsi, on
voit mieux ce qui se passe. Et comme de toute façon,
cette valeur va être fatalement modifiée quand elle
sera affichée dans la grille, cela n'a aucune
importance.
7 rsPub.Update Mise à jour du recordset.
8 End With
9 Grille_Recordset Appel à la procédure Grille_Recordset. Si vous vous
rappelez, cette procédure a déjà servi lors du
chargement de la form (voir §222), et nous avions
expliqué pourquoi la création du recordset était traitée
en dehors de la procédure Form_Load. Nous recréons
le recordset afin de
10 With GrilleMSH
11 .TopRow = .Rows - 1 Définition de la cellule active en tant que première
12 .Row = .Rows - 1 colonne de la dernière ligne de la grille.
13 .Col = 1
14 .Refresh
15 End With
16 GrilleMSH.MousePointer = vbDefault Le pointeur reprend une apparence "normale" (il avait
été défini comme Sablier ligne 3).
17 End If
18 End Sub

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 37
_____________________________________________________________________________________________________

263 - MISE À JOUR DU RECORDSET

La procédure ci-après peut être appelée dans deux contextes différents, comme déjà vu.
 mise à jour d'une ligne nouvellement crée;
 mise à jour d'une ligne existante.
Comme nous l'avons vu précédemment, d'autre procédure on besoin de connaître ce contexte. Nous le
préciserons donc en affectant la valeur ad hoc à la variable booléenne bVide.

Ligne Code Commentaires


1 Private Sub MiseAJour()
2 Dim i As Long
3 With GrilleMSH
4 i = .Col On mémorise la colonne en cours, afin de pouvoir y
revenir.
5 .Col = 1 La première colonne de la ligne encours est définie
comme cellule active. Dans notre cas, elle contient la
valeur de PubID qui, rappelons le, est le champ clé de
la table (et du recordset).
6 rsPub.Find ("PubID = " & GrilleMSH) On recherche dans le recordset un enregistrement
dont le champ PubID est égal à la valeur contenue
dans la cellule active de la grille.
Notez qu'il n'y aura forcément qu'un seul
enregistrement correspondant au critère de sélection,
puisque celui-ci porte sur un champ clé.
7 If rsPub!Name = "*" Then On vérifie si la ligne en cours de modification est une
ligne nouvellement crée. Cette vérification se fait par
le biais du recordset.
8 bVide = True Si il s'agit d'une ligne nouvellement crée, on affecte à
9 Else la variable booléenne bVide la valeur True. Si il s'agit
10 bVide = False d'une ligne déjà créée précédemment, on lui affecte la
11 End If valeur False.
Cela commence à s'éclairer, non?
12 .Col = i On revient à la colonne qui était active (ligne 5).
13 rsPub.Fields(i - 1) = GrilleMSH La (petite) difficulté de cette ligne est de bien se
rappeler que la collection des champs du recordset
commence à 0, alors qu'ici, la première colonne
contenant des données est la colonne 1. Autrement,
pas de problème: on affecte au champ du recordset
dont le numéro est celui de la colonne active moins 1
le contenu de la colonne active.
14 rsPub.Update Mise à jour du recordset.
15 Ajouter_Ligne Appel à la procédure Ajouter ligne afin d'ajouter
éventuellement une nouvelle ligne si la modification
qui vient d'être effectuée porte sur une ligne qui vient
d'être crée.
16 End With
17 End Sub

Voilà, nous en sommes quand même venus au bout. Mais je vous assure que pour ma part, j'ai eu
quelques difficultés, non pas vraiment pour le faire, mais pour l'expliquer .

Bon, maintenant, il ne nous reste plus qu'à supprimer une ligne de la grille. J'espère que ce ne sera pas
celle que nous avons eu tant de mal à créer .

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 38
_____________________________________________________________________________________________________

27 – SUPPRESSION D'UNE LIGNE DANS LA GRILLE

Compte tenu de ce que nous avons réalisé, ceci n'est plus qu'une simple formalité .
Ligne Code Commentaires
1 Private Sub GrilleMSH_KeyDown(KeyCode Procédure évènementielle qui détecte l'appui sur une
As Integer, Shift As Integer) touche et qui reçoit en paramètre le code ascii de la
dite touche, et si la touche MAJ est enfoncée
simultanément.
2 Dim Response As Integer Variable qui contiendra la réponse à la question du
message ci après.
3 Dim intRow As Integer Variable qui contiendra le numéro de la ligne à
supprimer.
4 If KeyCode = 46 Then Le code ascii 46 correspond à la touche Suppr. Ça
tombe bien, c'est la touche que nous voulions
intercepter .
5 rsPub.Find "PubID = '" & On recherche dans le recordset l'enregistrement dont
CLng(GrilleMSH.TextMatrix(GrilleMSH.Row, la valeur de la colonne PubID correspond à celle de
1)) & " ' " la première colonne de la ligne en cours de la grille.
6 Response = MsgBox("Etes vous sûr de Il faut toujours demander confirmation pour une
vouloir supprimer l'enregistrement de " & suppression. C'est tout du moins mon avis. Le
rsPub!Name, vbYesNo + vbDefaultButton2) message de la MsgBox permet à l'utilisateur de
répondre oui ou non, et c'est le non qui est sélectionné
par défaut. La constante renvoyée est sauvegardée
dans la variable.
7 If Response = vbNo Then Exit Sub Si la réponse est non, on arrête les frais…
8 intRow = GrilleMSH.Row La réponse est donc oui si on arrive à cette ligne. On
mémorise dans la variable le numéro de la ligne qui va
être supprimée.
9 rsPub.Delete On supprime l'enregistrement en cours du
recordset… . Mais si, l'enregistrement en cours est
celui que nous avons trouvé ligne 5
10 Set GrilleMSH.DataSource = rsPub On redéfinit la source de la grille, ce qui permettra de
la rafraîchir.
11 GrilleMSH.CollapseAll (0) Le rafraîchissement qui sera exécuté ligne 16 entraîne
le développement de toutes les lignes de la grille, ce
que nous voulons éviter. On reprécise donc la
propriété CollapseAll à 0.
12 GrilleMSH.TopRow = intRow – 2 Définition de la ligne supérieure visible de la grille (voir
ci après) après suppression. La variable intRow
contient le numéro de la ligne qui vient d'être
supprimée. La ligne en cours devient donc la ligne
précédente. Mais de plus, rappelez vous, la
numérotation des lignes de la grille commence à 0.
Donc, il faut soustraire 2 pour obtenir le numéro de la
ligne qui devient celle en cours.
13 GrilleMSH.LeftCol = 1 Définition de la première colonne visible à gauche de
la grille.
14 GrilleMSH.Row = intRow - 2 Définition de la ligne en cours (ne pas confondre avec
la définition de TopRow, ligne 12 précédente).
15 GrilleMSH.Col = 1 Définition de la première colonne comme étant celle
en cours (ne pas confondre avec LeftCol, ligne 13
précédente).
16 GrilleMSH.Refresh Rafraîchissement de la grille. Les modifications du
recordset sources sont ainsi prise en compte.
17 End If
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 Praticiels InfoGest SECTION 3 - RÉALISATION D'UNE GRILLE HIÉRARCHIQUE UPDATABLE Page 39
_____________________________________________________________________________________________________

18 End Sub

Le nombre maximum de lignes que vous pouvez utiliser lors de la définition de TopRow correspond au
nombre total de lignes moins le nombre de lignes visibles dans le contrôle MSHFlexGrid. Si cette
propriété est définie sur un nombre de lignes supérieur, le contrôle MSHFlexGrid sera réinitialisé à sa
valeur la plus grande possible. (MSDN)

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com


 PRATICIELS INFOGEST CONCLUSION Page 40
_____________________________________________________________________________________________________

CONCLUSION

Avec ce praticiel, vous avez je l'espère progressé dans la mise en œuvre et l'utilisation des recordsets
hiérarchiques et des grilles et autres listes nécessaires à la recherche, la lecture, la modification, la création et la
suppression d'enregistrements.

La première section vous a notamment montré comment utiliser les objets Command afin de créer et
utiliser un recordset hiérarchiques, mais aussi comment vous servir du concepteur DataEnvironment et des objets
Command afin de vous aider à concevoir, voire tester, une chaîne SQL pour la création d'un recordset
hiérarchique. Vous avez constatez à quel point la mise en œuvre de ces objets est facile, et combien ils sont
puissants, même si nous sommes loin d'avoir épuisé toutes les possibilités qu'ils nous offrent dans le cadre de
l'accès aux données hiérarchiques.

Dans cette même première section, vous avez vu comment mettre en œuvre une MSHFlexGrid et la
paramétrer. Vous avez peut être perçu à quel point l'usage de cette grille était malaisé et surtout limité à la lecture.

Dans la seconde section, une alternative à l'utilisation de la MSHFlexGrid vous a été présentée pour traiter
des données hiérarchiques. Vous avez constaté probablement que le trio DataGrid, Zones de Texte dépendantes
et DataCombo (ou DataList) est probablement le moyen le plus efficace pour ce faire, et que leur mise en œuvre
était facile.

La troisième section était plus un exercice de style qu'une démarche facilement intégrable dans le cadre
d'une application. Vous avez pu appréhender le code supplémentaire nécessaire pour faire de la MSHFlexGrid un
composant plus pratique d'emploi. Cela vous a sans doute convaincu que l'approche présentée dans la seconde
section était quand même plus "civilisée".

Néanmoins, bien qu'exercice de style, cette section vous a peut-être été également profitable dans le cadre
d'une bonne utilisation de ce composant. Et puis, cela pourrait être le point de départ pour la réalisation d'un OCX
plus performant que l'actuelle MSHFlexGrid. Pourquoi pas?

J'espère que ce praticiel vous a été utile et d'une utilisation pas trop rebutante. N'oubliez pas les autres
praticiels de cette série qui pourront je pense compléter valablement celui-ci. Et pour finir, il me serait agréable de
savoir si vous avez employé ce praticiel et les sources du projet Visual Basic qui lui sont jointes, et de connaître
vos réactions, suggestions et éventuellement modification à apporter. Je vous en remercie.

_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]

Created by Neevia Personal Converter trial version http://www.neevia.com

Vous aimerez peut-être aussi