Académique Documents
Professionnel Documents
Culture Documents
RECORDSETS HIERARCHIQUES
GRILLES & LISTES
Praticiel
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
_____________________________________________________________________________________________________
Sommaire
PRÉAMBULE
1 - OBJECTIF
2 - PRÉ REQUIS
3 - CONVENTIONS
4 - ENVIRONNEMENT ET PRÉALABLES
INTRODUCTION
1 - INTRODUCTION
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
_____________________________________________________________________________________________________
1 - CRÉATION DE LA DATAGRID
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]
_____________________________________________________________________________________________________
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
Cette icône annonce un point important. La teneur de ce point important 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]
_____________________________________________________________________________________________________
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]
_____________________________________________________________________________________________________
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.
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]
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.
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]
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).
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.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
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.
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]
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.
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]
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 .
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]
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).
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.
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]
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.
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]
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]
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.
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…
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.
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]
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]
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)
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
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]
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.
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]
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.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
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]
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
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]
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
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.
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
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]
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é.
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]
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]
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.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
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
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]
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.
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]
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]
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
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]
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).
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]
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).
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
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
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]
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.
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.
_________________________________________________________________________________________________________________
© INFOGEST - JACQUES MALATIER - Pour demander un renseignement sur ce praticiel, envoyez un message à
mailto:jacma@redaction-developpez.com?subject=[rsmshflex]
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.
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]
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]
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]
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]