Bonjour à tous,
Le contrôle ListView est un outil formidable pour l'affichage de données, contrairement à d'autres contrôles, il accepte le défilement via la molette de la souris et chaque colonne peut être classée en ordre croissant ou décroissant. L'extraction de données après une sélection est relativement aisée.
Pour les férus de ce contrôle (comme moi), le problème du classement des colonnes de données n'est pas simple à traiter.
En effet, les données stockées dans une ListView sont du type "Texte", ce qui veut dire que le classement sera Alphanumérique.
Pour le classement d'une colonne censée contenir des dates au format "JJ/MM/AAAA" , le classement, bien que logique, sera plutôt désordonné. Idem pour les colonnes contenant des valeurs numériques.
Pour pallier à ce souci, on sera obligé d'utiliser une programmation spécifique pour classer correctement ces colonnes.
Si l'on utilise plusieurs ListViews dans le même (ou différents) formulaire, il faudra adapter la programmation à chaque liste. Soit bien du travail en perspective.
Les deux procédures que je vous propose, permettent de classer n'importe quelle ListView de n'importe quel formulaire avec un minimum de code à rédiger.
Une fois ces procédures implémentées dans votre projet, il vous suffit de paramétrer l'évènement "ListView?_ColumnClick".
L'initialisation de vos ListViews devra également être revue, notamment pour l'ajout de la colonne "Origine" qui sera utilisée par les procédures de classement.
Principe de fonctionnement :
Après initialisation de la ListView d'un formulaire et chargement des données, le formulaire est affiché. Pour classer une des colonnes, l'utilisateur va cliquer sur un des entêtes de colonnes, déclenchant ainsi l'évènement "ListView?_ColumnClick".
Le code placé dans cette procédure (après contrôle), fera appel à la procédure "ListView_Classe" au moyen de différents paramètres que vous aurez spécifiés.
Cette dernière, fera appel à la procédure "ListeView_Prépare_Col" pour préparer la colonne de tri. Cette colonne, invisible pour l'utilisateur, sera la base du classement.
Une fois le classement effectué, la colonne de tri est supprimée.
Démonstration avec le classeur ListView.xlsm (fichier joint) :
Celui-ci est composé de 3 feuilles de calcul et côté VBA : D'un module comportant les différentes procédures, dont celles sus mentionnées, et de 2 formulaires avec dans chacun une ListView dont l'architecture est différente.
La procédure "Initialisation_Liste1", initialise la ListView1 du formulaire "UserForm1" et charge les données issues des feuilles "Janvier" & "Février". Feuilles de données comptables comportant de nombreuses anomalies (voulues pour l'exemple).
La procédure "Initialisation_Liste2", initialise la ListView1 du formulaire "UserForm2" et charge les données issues de la feuille "Agents" (Liste des agents d'une société fictive).
Les boutons, placés sur chaque feuille, permettent de lancer les procédures d'initialisation et l'affichage des listes.
Les données sont affichées dans l'ordre de chargement (appelé classement d'origine). Ce classement est sauvegardé dans une colonne, invisible pour l'utilisateur et servira au retour à l'affichage de départ, ou bien en tant que sous-critère de classement (voir procédures d'initialisation).
Classement des colonnes :
Un clic sur un entête de colonne déclenche l'évènement "ListView?_ColumnClick".
Le code placé dans cette procédure est spécifique à chaque ListView et comporte le paramétrage pour l'appel de la procédure "ListeView_Classe".
Ici on contrôle la colonne cliquée, le classement de la colonne "Origine" est interdit. Bien qu'invisible, elle peut avoir été ouverte par un utilisateur curieux !
Dans cette procédure, on définira également le retour au classement d'origine :
La variable publique "Initiale" positionnée à True et une sélection de la colonne 1 (après classement Croissant & Décroissant) replacera les données dans l'ordre d'affichage d'origine.
Ensuite on paramètre l'appel à la procédure "ListeView_Classe" en fonction de la colonne sélectionnée.
Paramètres = ListView concernée, N° de la colonne cliquée, Type de colonne et N° de la colonne servant de sous critère de classement.
Le type de colonne définit la nature de la colonne :
=1 pour une colonne supposée ne contenir que des dates (elle peut contenir des données "Non dates" ou des des données vides),
=2 pour une colonne supposée ne contenir que des données numériques (elle peut contenir des données "Non numériques" ou des données vides),
=3 pour une colonne supposée ne contenir que des données Texte.
Le sous-critère servira à classer les doublons entre eux. Pour l'exemple, on se limite à un seul sous-critère, mais l'ajout de sous-critères supplémentaires est très simple à programmer.
La procédure "ListrView_Classe" est appelée, elle fera appel à la procédure "ListeView_Prépare_Col" pour la préparation de la colonne de tri (nouvelle colonne invisible). Les données sont classées et l'affichage est actualisé. La colonne de tri est supprimée;
Les colonnes sont classées de façon à placer les données significatives en haut de liste (ce qu'attend l'utilisateur en général).
A savoir :
Colonnes Type Date : Dates en 1er, non-dates* à suivre et vides* pour finir,
Colonnes Type Numérique : Numériques en 1er, non numériques* à suivre et vides* en dernier,
Colonnes Type Texte : Texte en 1er et vides* à suivre.
(* Si présence dans la colonne)
Sans cela, le classement croissant d'une colonne placerait les données vides en 1er. C'est le cas, par exemple, pour les feuilles 1 et 2, où les recettes sont vides lorsque des dépenses sont présentes (et inversement).
Pour cela, on place devant les données concernées (dans la colonne de tri), un code Ascii spécifique permettant de diriger le classement :
Ascii 254 ou 255 pour un classement croissant et Ascii 46 ou 47 pour un classement décroissant.
Pour le classement des dates, on convertit la date en n° de série auquel on associe le sous-critère (pour classement des doublons).
Pour les données numériques, on procède au classement des données, converties en valeur, et on ajoute le sous-critère.
Pour les données de type texte, aucun traitement particulier, si ce n'est l'adjonction du sous-critère.
Tout cela est largement commenté dans les différentes procédures du classeur.
Les procédures "ListeView_Classe" & "ListeView_Prépare_Col" sont prêtes à l'emploi, seules les procédures "ListView?_ColumnClick" de chaque ListView sont à adapter.
Quant aux procédures d'initialisation, propres à vos projets, il vous faudra juste ajouter la colonne invisible "Origine" et la renseigner.
De nombreux tests ont été effectués sur des ListViews de structures très différentes. Avec un nombre d'items plus ou moins importants. Ils se sont révélés concluants.
Cependant, on ne peut pas tout envisager. L'anomalie reste possible.
En fonction de vos applications, et de vos besoins, vous serez peut-être amené à modifier telle ou telle procédure voire à les améliorer.
Quoi qu'il en soit, le code fourni dans le classeur joint, permettra à certains d'entre vous, de se familiariser avec les ListViews.
Suggestions d'améliorations
Ajouter d'autres sous-critères :
Il suffit de créer d'autres paramètres d'appel (Col_SC1, Col_SC2, ...), de modifier les paramétrages et de rajouter, dans la procédure "ListeView_Prépare_Col"', le code nécessaire.
Eviter d'utiliser les colonnes du type "Date" ; les données ne sont pas au bon format (idem pour les données numériques). Il faudrait les classer au préalable.
Pour limiter la taille des sous-critères, on pourra se contenter de quelques caractères. Par exemple les 5 premiers caractères du nom pour une colonne "Noms".
Améliorer la vitesse de classement (pour les valeurs numériques) :
J'ai testé la procédure avec 5000 lignes de valeurs numériques différentes. Le temps de classement était satisfaisant. Bien sûr cela dépend en partie de l'ordinateur utilisé.
Si nécessaire, on pourra remplacer la méthode de classement (Recherche et insertion dans Tabl()) par une méthode dichotomique ou bien utiliser une colonne libre d'une feuille de calcul et laisser Excel faire le boulot (via une macro).
Remplacer les données Origine par la source réelle de la ligne :
La colonne "Origine" (invisible) est alimentée par un numéro correspondant à l'ordre d'insertion dans la ListView. On pourra remplacer ce numéro par la référence de la ligne chargée.
Par exemple, N° feuille et N° de ligne sous la forme "060045" (06=Feuil(6) , 0045=Row). Ajouter un 0 si + de 9999 lignes.
Le classement (retour à l'origine) restera inchangé sous réserve que la référence soit ordonnée.
Cette méthode permettra, après sélection d'une ligne et via un bouton placé sur le formulaire, de retourner à la ligne source. J'utilise personnellement cette option dans mon application "Gestion de ses comptes et Budget prévisionnel annuel".
L'utilisateur à la possibilité, lors de l'affichage des écritures (Recherche, vérif banque, etc.), de sélectionner une ligne et de cliquer sur le bouton "Aller à l'écriture" présent sur le formulaire (ou double-clic). Cette action referme la fenêtre d'affichage, active la feuille concernée et met l'écriture en surbrillance.
Il y a surement d'autres améliorations possibles, je vous laisse le soin de les mettre en œuvre.
Bonne programmation.
Le contrôle ListView est un outil formidable pour l'affichage de données, contrairement à d'autres contrôles, il accepte le défilement via la molette de la souris et chaque colonne peut être classée en ordre croissant ou décroissant. L'extraction de données après une sélection est relativement aisée.
Pour les férus de ce contrôle (comme moi), le problème du classement des colonnes de données n'est pas simple à traiter.
En effet, les données stockées dans une ListView sont du type "Texte", ce qui veut dire que le classement sera Alphanumérique.
Pour le classement d'une colonne censée contenir des dates au format "JJ/MM/AAAA" , le classement, bien que logique, sera plutôt désordonné. Idem pour les colonnes contenant des valeurs numériques.
Pour pallier à ce souci, on sera obligé d'utiliser une programmation spécifique pour classer correctement ces colonnes.
Si l'on utilise plusieurs ListViews dans le même (ou différents) formulaire, il faudra adapter la programmation à chaque liste. Soit bien du travail en perspective.
Les deux procédures que je vous propose, permettent de classer n'importe quelle ListView de n'importe quel formulaire avec un minimum de code à rédiger.
Une fois ces procédures implémentées dans votre projet, il vous suffit de paramétrer l'évènement "ListView?_ColumnClick".
L'initialisation de vos ListViews devra également être revue, notamment pour l'ajout de la colonne "Origine" qui sera utilisée par les procédures de classement.
Principe de fonctionnement :
Après initialisation de la ListView d'un formulaire et chargement des données, le formulaire est affiché. Pour classer une des colonnes, l'utilisateur va cliquer sur un des entêtes de colonnes, déclenchant ainsi l'évènement "ListView?_ColumnClick".
Le code placé dans cette procédure (après contrôle), fera appel à la procédure "ListView_Classe" au moyen de différents paramètres que vous aurez spécifiés.
Cette dernière, fera appel à la procédure "ListeView_Prépare_Col" pour préparer la colonne de tri. Cette colonne, invisible pour l'utilisateur, sera la base du classement.
Une fois le classement effectué, la colonne de tri est supprimée.
Démonstration avec le classeur ListView.xlsm (fichier joint) :
Celui-ci est composé de 3 feuilles de calcul et côté VBA : D'un module comportant les différentes procédures, dont celles sus mentionnées, et de 2 formulaires avec dans chacun une ListView dont l'architecture est différente.
La procédure "Initialisation_Liste1", initialise la ListView1 du formulaire "UserForm1" et charge les données issues des feuilles "Janvier" & "Février". Feuilles de données comptables comportant de nombreuses anomalies (voulues pour l'exemple).
La procédure "Initialisation_Liste2", initialise la ListView1 du formulaire "UserForm2" et charge les données issues de la feuille "Agents" (Liste des agents d'une société fictive).
Les boutons, placés sur chaque feuille, permettent de lancer les procédures d'initialisation et l'affichage des listes.
Les données sont affichées dans l'ordre de chargement (appelé classement d'origine). Ce classement est sauvegardé dans une colonne, invisible pour l'utilisateur et servira au retour à l'affichage de départ, ou bien en tant que sous-critère de classement (voir procédures d'initialisation).
Classement des colonnes :
Un clic sur un entête de colonne déclenche l'évènement "ListView?_ColumnClick".
Le code placé dans cette procédure est spécifique à chaque ListView et comporte le paramétrage pour l'appel de la procédure "ListeView_Classe".
Ici on contrôle la colonne cliquée, le classement de la colonne "Origine" est interdit. Bien qu'invisible, elle peut avoir été ouverte par un utilisateur curieux !
Dans cette procédure, on définira également le retour au classement d'origine :
La variable publique "Initiale" positionnée à True et une sélection de la colonne 1 (après classement Croissant & Décroissant) replacera les données dans l'ordre d'affichage d'origine.
Ensuite on paramètre l'appel à la procédure "ListeView_Classe" en fonction de la colonne sélectionnée.
Paramètres = ListView concernée, N° de la colonne cliquée, Type de colonne et N° de la colonne servant de sous critère de classement.
Le type de colonne définit la nature de la colonne :
=1 pour une colonne supposée ne contenir que des dates (elle peut contenir des données "Non dates" ou des des données vides),
=2 pour une colonne supposée ne contenir que des données numériques (elle peut contenir des données "Non numériques" ou des données vides),
=3 pour une colonne supposée ne contenir que des données Texte.
Le sous-critère servira à classer les doublons entre eux. Pour l'exemple, on se limite à un seul sous-critère, mais l'ajout de sous-critères supplémentaires est très simple à programmer.
La procédure "ListrView_Classe" est appelée, elle fera appel à la procédure "ListeView_Prépare_Col" pour la préparation de la colonne de tri (nouvelle colonne invisible). Les données sont classées et l'affichage est actualisé. La colonne de tri est supprimée;
Les colonnes sont classées de façon à placer les données significatives en haut de liste (ce qu'attend l'utilisateur en général).
A savoir :
Colonnes Type Date : Dates en 1er, non-dates* à suivre et vides* pour finir,
Colonnes Type Numérique : Numériques en 1er, non numériques* à suivre et vides* en dernier,
Colonnes Type Texte : Texte en 1er et vides* à suivre.
(* Si présence dans la colonne)
Sans cela, le classement croissant d'une colonne placerait les données vides en 1er. C'est le cas, par exemple, pour les feuilles 1 et 2, où les recettes sont vides lorsque des dépenses sont présentes (et inversement).
Pour cela, on place devant les données concernées (dans la colonne de tri), un code Ascii spécifique permettant de diriger le classement :
Ascii 254 ou 255 pour un classement croissant et Ascii 46 ou 47 pour un classement décroissant.
Pour le classement des dates, on convertit la date en n° de série auquel on associe le sous-critère (pour classement des doublons).
Pour les données numériques, on procède au classement des données, converties en valeur, et on ajoute le sous-critère.
Pour les données de type texte, aucun traitement particulier, si ce n'est l'adjonction du sous-critère.
Tout cela est largement commenté dans les différentes procédures du classeur.
Les procédures "ListeView_Classe" & "ListeView_Prépare_Col" sont prêtes à l'emploi, seules les procédures "ListView?_ColumnClick" de chaque ListView sont à adapter.
Quant aux procédures d'initialisation, propres à vos projets, il vous faudra juste ajouter la colonne invisible "Origine" et la renseigner.
De nombreux tests ont été effectués sur des ListViews de structures très différentes. Avec un nombre d'items plus ou moins importants. Ils se sont révélés concluants.
Cependant, on ne peut pas tout envisager. L'anomalie reste possible.
En fonction de vos applications, et de vos besoins, vous serez peut-être amené à modifier telle ou telle procédure voire à les améliorer.
Quoi qu'il en soit, le code fourni dans le classeur joint, permettra à certains d'entre vous, de se familiariser avec les ListViews.
Suggestions d'améliorations
Ajouter d'autres sous-critères :
Il suffit de créer d'autres paramètres d'appel (Col_SC1, Col_SC2, ...), de modifier les paramétrages et de rajouter, dans la procédure "ListeView_Prépare_Col"', le code nécessaire.
Eviter d'utiliser les colonnes du type "Date" ; les données ne sont pas au bon format (idem pour les données numériques). Il faudrait les classer au préalable.
Pour limiter la taille des sous-critères, on pourra se contenter de quelques caractères. Par exemple les 5 premiers caractères du nom pour une colonne "Noms".
Améliorer la vitesse de classement (pour les valeurs numériques) :
J'ai testé la procédure avec 5000 lignes de valeurs numériques différentes. Le temps de classement était satisfaisant. Bien sûr cela dépend en partie de l'ordinateur utilisé.
Si nécessaire, on pourra remplacer la méthode de classement (Recherche et insertion dans Tabl()) par une méthode dichotomique ou bien utiliser une colonne libre d'une feuille de calcul et laisser Excel faire le boulot (via une macro).
Remplacer les données Origine par la source réelle de la ligne :
La colonne "Origine" (invisible) est alimentée par un numéro correspondant à l'ordre d'insertion dans la ListView. On pourra remplacer ce numéro par la référence de la ligne chargée.
Par exemple, N° feuille et N° de ligne sous la forme "060045" (06=Feuil(6) , 0045=Row). Ajouter un 0 si + de 9999 lignes.
Le classement (retour à l'origine) restera inchangé sous réserve que la référence soit ordonnée.
Cette méthode permettra, après sélection d'une ligne et via un bouton placé sur le formulaire, de retourner à la ligne source. J'utilise personnellement cette option dans mon application "Gestion de ses comptes et Budget prévisionnel annuel".
L'utilisateur à la possibilité, lors de l'affichage des écritures (Recherche, vérif banque, etc.), de sélectionner une ligne et de cliquer sur le bouton "Aller à l'écriture" présent sur le formulaire (ou double-clic). Cette action referme la fenêtre d'affichage, active la feuille concernée et met l'écriture en surbrillance.
Il y a surement d'autres améliorations possibles, je vous laisse le soin de les mettre en œuvre.
Bonne programmation.
- Auteur
- Eric