ListBox (2/2)

Jean-Yves FOCK-HOON

La partie 1 de la note technique présentait les attributs des ListBox tels que vous pouvez les définir en Mode Structure. Cette seconde partie explore les multiples possibilités offertes par les manipulations des ListBox avec la programmation. ♪

- Titre : ListBox (2/2)

- Auteur : Jean-Yves FOCK-HOON

- Parution : 1 juin 2006

- Licence : Ce document est issu de https://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Sommaire

- Construire une ListBox

- Déplacer lignes et colonnes

- Glisser-déposer simple

- Glisser-déposer entre process

- Éditer une cellule

- Événements formulaire

- L'événement formulaire « Sur déplacement colonne »

- L'événement formulaire « Sur redimensionnement colonne »

- L'événement formulaire « Sur clic en-tête »

- L'événement formulaire « Sur après tri »

- L'événement formulaire « Sur avant saisie »

- L'événement formulaire « Sur déplacement ligne »

- Multipage

- Puzzle

- Conclusion

- Télécharger la base exemple

Construire une ListBox

Dans cet exemple, nous allons utiliser un formulaire avec une ListBox qui inclut plusieurs colonnes et montre l'utilisation des commandes 4D pour mettre en place les colonnes dans la ListBox.

Sélectionnez « Construire une ListBox » dans le Menu Démonstration, un dialogue est alors affiché, qui utilise le formulaire [Contacts]Dial1.

Le bouton « Réinitialiser » permet les valeurs par défaut sur la zone.

Nous commencerons par cliquer sur le bouton « Tout effacer ». Ce bouton utilise la commande Lire nombre colonnes listbox pour obtenir le nombre de colonnes dans la ListBox (invisible ou visible). Nous utilisons alors la commande SUPPRIMER COLONNE LISTBOX pour supprimer toutes les colonnes. La zone ListBox est maintenant vide.

Vous pouvez cliquer sur le bouton suivant : « Insérer valeurs défauts ». Ce bouton va réinsérer les quatre colonnes supprimées. Ceci implique l'insertion d'une colonne et de son en-tête. Ceci est fait en appelant la méthode-projet M_InsertColonne qui utilise les commandes INSERER COLONNE LISTBOX et TITRE BOUTON. Les commandes sont insérées, avec les paramètres par défaut pour la police, taille et couleur.

Lorsque l'on clique sur le bouton suivant, « + de colonnes », ce bouton insérera quatre colonnes de plus en utilisant la même méthode-objet M_InsertColonne .

Vous devez insérer toutes les colonnes avant de définir leurs attributs quand le code s'exécute dans la même méthode. Vous ne pouvez pas insérer une colonne, définir ses attributs et insérer la colonne suivante, etc., à l'intérieur d'une même méthode.

Une fois que toutes les colonnes ont été ajoutées, vous pouvez cliquer sur le bouton « Attributs ». Ce bouton appelle la méthode M_InstallColonne, une méthode générique qui utilise les commandes FIXER COULEURS RVB, CHANGER JEU DE CARACTERES, CHANGER TAILLE et CHANGER STYLE. Cette méthode change les attributs comme la couleur d'arrière-plan pour chaque colonne dans la liste. La méthode-objet change alors l'arrière-plan de la colonne at_city à l'affichage.

Le bouton suivant est le bouton « Grille ». Ce bouton utilise les commandes FIXER COULEUR GRILLE LISTBOX et MONTRER GRILLE LISTBOX pour cacher et montrer la grille ou l'afficher avec différentes couleurs. Vous pouvez cliquez plusieurs fois pour voir les cinq paramétrages possibles.

Vous pouvez maintenant aller vers le bouton suivant : « Réorganisé ». Ce bouton va réorganiser nos colonnes. Il n'y a pas de commandes pour déplacer les colonnes à l'intérieur d'une ListBox. Nous devons simuler cela. L'astuce est très simple.
Nous avons besoin de :

- garder le nombre de colonnes ;

- garder leur information et leur largeur courante ;

- réorganiser les colonnes ;

- supprimer toutes les colonnes ;

- revenir à l'ordre d'origine ;

- retrouver les noms des objets et les noms des variables utilisés dans la ListBox,

ce qui peut être fait avec la commande LIRE TABLEAUX LISTBOX.

Pour retrouver la largeur courante pour chaque colonne, nous utilisons la commande Lire largeur colonne listbox. Dans la même boucle, nous pouvons aussi initialiser un tableau qui sera utilisé plus tard pour la réorganisation. Nous pouvons supprimer toutes les colonnes dans la ListBox et commencer à insérer à nouveau chacune d'elle. Nous utilisons un tableau local $al_newOrder dans lequel nous allons trouver le nom de l'objet Colonne et assigner un numéro de colonne. Si la colonne n'a pas été trouvée, rien n'est fait. Si une colonne a été appelée, l'ordre courant reste le même, comme à l'initialisation avec le nombre de colonnes.

Une fois que l'ordre a été défini, nous pouvons trier tous les tableaux en nous basant sur un nouvel ordre et lancer une simple boucle pour insérer chaque colonne avec INSERER COLONNE LISTBOX. Une fois que les colonnes ont été insérées, nous pouvons assigner leur en-tête et restaurer leur largeur.

Notre dernière étape est de définir les couleurs et les polices.

Le dernier bouton sera le bouton « Taille objet optimale ». Nous pouvons utiliser la commande LIRE TABLEAUX LISTBOX à nouveau pour retrouver toutes les colonnes et lancer une boucle sur chaque colonne. TAILLE OBJET OPTIMALE nous retournera la meilleure largeur pour l'en-tête et pour la colonne. La plus grande largeur est alors appliquée à la colonne de manière à contenir la valeur la plus longue.

Déplacer lignes et colonnes

L'objectif de cet exemple est de montrer comment déplacer ou redimensionner les colonnes et comment implémenter un total des lignes en dessous de la ListBox. Cet exemple utilise le formulaire [Contacts]Dial2.

Le concept est de toujours contrôler la largeur de chaque colonne après redimensionnement ou déplacement d'une colonne. Nous devons connaître la position de la ListBox. Ceci peut être retrouvé en utilisant la commande LIRE RECT OBJET sur la ListBox. Nous connaissons le nombre de colonnes et pouvons retrouver la largeur courante de chacune en utilisant la commande Lire largeur colonne listbox. Avec les coordonnées courantes de la ListBox, nous pouvons déduire la position exacte pour chaque colonne.

Nous connaissons la hauteur de notre ligne Total. Sinon, nous pouvons toujours utiliser LIRE RECT OBJET. Basé sur les coordonnées de notre ListBox, nous pouvons conclure les coordonnées verticales de notre Total ligne sur le dialogue. La largeur de Total Ligne correspond à la largeur de la colonne. Nous pouvons maintenant retrouver les coordonnées horizontales de notre Total dans le dialogue.

La difficulté est maintenant de déplacer le Total chaque fois que la ListBox est modifiée. Nous pouvons déplacer la ligne en utilisant la commande . Nous avons juste besoin de connaître quand déclencher cela. Cela signifie que nous avons besoin de détecter quand une colonne a été redimensionnée ou déplacée. Cela peut être fait en testant l'événement courant. Si une colonne a été redimensionnée ou déplacée, nous devons détecter ce qui a été redimensionné et où elle a été déplacée pour déplacer et redimensionner notre total. C'est pourquoi la méthode-objet est déclenchée seulement sur ces deux événements.

Si une colonne est déplacée, nous devons recalculer les coordonnées horizontales de chaque colonne de façon à déplacer la ligne des totaux correspondants aux colonnes appropriées. Nous devons aussi connaître avec quelle colonne nous devons faire correspondre les totaux. Nous pouvons utiliser la commande NUMERO COLONNE LISTBOX DEPLACEE pour réinsérer le pointeur sur notre tableau de colonne de la colonne déplacée dans l'ordre approprié, recalculer la largeur pour toutes les colonnes et réactualiser la position des totaux.

Si une colonne a été redimensionnée, l'ordre des colonnes ne change pas. Seulement les largeurs des deux colonnes affectées par le redimensionnement ont été changées. Il n'y a pas de commandes qui peuvent nous dire quelles colonnes ont été redimensionnées, il est plus prudent de recalculer toutes les largeurs à nouveau, et mettre à jour les positions des totaux.

Comme vous avez dû le noter, le dialogue peut être redimensionné. La ligne des totaux est verticalement déplaçable, mais horizontalement fixe. Si vous redimensionnez le dialogue verticalement, 4D déplace automatiquement les objets. L'attribut de redimensionnement horizontal a été désactivé pour des raisons techniques : augmenter la taille est très facile. Une fois que le curseur a été libéré, vous pouvez recalculer les largeurs de chaque colonne et redimensionner la ligne des totaux.

Cette partie fonctionne parfaitement. Un problème survient lorsque vous essayez de diminuer la taille du dialogue. Vous ne pouvez pas diminuer du dialogue à cause de la largeur fixe de la ligne total. Un contournement rapide serait de faire en sorte que ces variables puissent être augmentées horizontalement. Avec ce paramétrage, vous pouvez diminuer la taille du dialogue plus loin, mais nous sommes toujours collés puisque nous ne pouvons redimensionner t définir la ligne « Subjets » d'une largeur inférieure à quelques pixels. Puisque cette solution n'est pas parfaite, c'est pourquoi le redimensionnement horizontal automatique a été désactivé.

Glisser-déposer simple

L'objectif de cet exemple est de monter comment implémenter un simple glissé-déposé entre deux ListBox à l'intérieur d'un même dialogue. Cet exemple utilise le formulaire [Contacts]« Dial3 ». Dans ce dialogue nous avons deux ListBox, MyListBox et MyListBox2.

Nous voulons glisser et déposer/insérer des éléments de MyListBox2 vers MyListBox.

Pour faire cela, nous devons activer l'option « Glissable » pour MyListBox2. Si cette case à cocher n'est pas cochée, l'objet MyListBox ne recevra pas les événements de glissé-déposé. MyListBox doit aussi avoir l'option « déposable » cochée pour recevoir ces événements. Une fois ceci fait, MyListBox peut maintenant tester les deux événements formulaires Sur glisser et Sur deposer.

Durant l'événement formulaire Sur glisser, vous pouvez exécuter la commande PROPRIETES GLISSER DEPOSER et voir d'où vient le « déposer » et ce qui est déposé. Puisque nous voulons seulement autoriser un déposé à partir de la seconde ListBox, nous pouvons tester le pointeur courant pour voir s'il vient réellement de MyListBox2. Si l'élément vient bien de MyListBox2, nous pouvons maintenant vérifier si la valeur courante a déjà été déposée. Si oui, nous refusons le « déposé ». Pour faire cela, nous refusons tout « déposé » en comportement standard. Si la valeur vient bien de MyListBox2 et n'est pas un doublon, nous pouvons alors autoriser le « déposé ». Pour autoriser le « déposé », passez simplement $0 à 0. Pour interdire le déposé, passez $0 à 1. Si vous refusez le déposé, l'objet ne sera pas redessiné avec un effet visuel « zone déposable ».

Glisser-déposer entre process

L'objectif de cet exemple est de montrer comment glisser et déposer des éléments entre deux ListBoxes situées dans deux process séparés. Cet exemple utilise les formulaires [COMMANDES]Input et [CONTACTS]DialProduct. Cet exemple est très semblable à l'exemple précédent. Le premier process est le process de la liste des produits, une ListBox très simple qui contient tous les produits disponibles de nos données. Le second process exécute la commande AJOUTER ENREGISTREMENT avec une ListBox. Nous pouvons glisser et déposer un élément dans cette ListBox. En utilisent les commandes PROPRIETES GLISSER DEPOSER, RESOUDRE POINTEUR et LIRE VARIABLE PROCESS, nous pouvons retrouver les valeurs à insérer dans la ListBox. Cette partie est très facile et demande peu de code, contrairement au code pour la synchronisation de la facture elle-même.

Une fois qu'une valeur a été insérée, vous pouvez changer la quantité. Saisissez « 0 » pour supprimer cet élément de la facture et saisissez une autre valeur. Si vous saisissez une valeur non nulle, vous devez recalculer la ligne des totaux. Si vous saisissez « 0 », nous devons supprimer tous les éléments relatifs à ce produit dans notre produit. Dans les deux cas, nous devons recalculer les totaux.

Pour cela, nous devons calculer les totaux sans la ligne courante. Ceci peut être fait à partir de l'événement Sur gain focus lorsque l'on édite la quantité. Si vous supprimez une ligne ou si vous changez la quantité, il sera alors facile de calculer les totaux de la facture. Si la ligne a été supprimée, le total courant est le total précédent. Si la quantité a été changée, le total courant est le total précédent plus le nouveau total de la ligne. Tout ceci peut être calculé durant l'événement formulaire Sur données modifiées sur votre ListBox.

Éditer une cellule

L'objectif de cet exemple est de montrer comment déplacer l'ascenseur ou éditer une ligne dans une ListBox. Cet exemple utilise le formulaire [CONTACTS]Dial5. Notre formulaire a une ListBox avec 4 colonnes. 2 colonnes sont visibles et 2 sont invisibles. Nous allons afficher dans cette ListBox la sélection des contacts à partir du fichier de données.

À l'affichage du dialogue, vous pouvez seulement voir 2 colonnes. Vous pouvez essayer d'éditer/modifier un nom. Dès que vous avez édité un nom, vous pouvez voir que les deux autres colonnes sont visibles. Cela est fait en testant l'événement formulaire Sur gain focus et en utilisant la commande CHOIX VISIBLE. À l'affichage du dialogue, l'événement Sur gain focus est aussi déclenché. Voici pourquoi nous utilisons la variable vOnLoad pour prévenir l'affichage de ces colonnes lorsqu'on affiche le dialogue pour la première fois.

Après modification, nous avons besoin de cacher ces colonnes à nouveau. Nous pouvons utiliser la commande à partir des événements Sur données modifiées ou Sur perte focus. Il y a deux façons pour arrêter l'édition. Vous pouvez actionner la touche ENTER pour valider votre saisie ou vous pouvez changer le focus courant en cliquant n'importe où ailleurs comme sur un bouton, sans changer aucune donnée. C'est pourquoi nous exécutons les deux événements formulaires.

Si nous cliquons sur un de ces boutons, nous allons réorganiser les tableaux et trouver le premier nom qui commence par la lettre courante. Le tri peut être fait avec TABLEAU MULTI TRI. Ce n'est pas obligatoire, mais logique si vous voulez éditer le premier nom commençant par ce qui contient la première valeur. Cela peut être fait en exécutant la commande DEFILER LIGNES. Nous pouvons maintenant éditer la valeur en utilisant la commande EDITER ELEMENT. Les deux commandes DEFILER LIGNES et EDITER ELEMENT nécessite le numéro de la colonne, retourné par la commande Chercher dans tableau. Comme nous éditons un élément, nous ne devons pas oublier de mettre en place nos deux autres colonnes à visibles.

Si nous cliquons sur le bouton « J » pour éditer un nom, nous pouvons voir qu'il n'y a pas de nom commençant par « J » et aucun nom n'est édité. C'est parce que nous avons perdu le focus lorsque nous cliquons sur ce bouton et parce nous n'avons pas trouvé de nom dans notre tableau, nous n'exécutions ni DEFILER LIGNES ni EDITER ELEMENT.

Événements formulaire

L'objectif de cet exemple est de démontrer comment utiliser les six nouveaux événements formulaires spécifiquement implémentés pour les ListBox. Cet exemple utilise le formulaire [CONTACTS]Dial6.

L'événement formulaire « Sur déplacement colonne »

Cet événement formulaire est utilisé avec la commande NUMERO COLONNE LISTBOX DEPLACEE. Nous pouvons détecter quelle colonne a été déplacée d'où vers où. Cet événement formulaire et commande est très pratique pour connaître l'ordre des colonnes. Dans cet exemple, nous pouvons garder l'ordre des colonnes et calculer leur largeur. En fonction des données, nous pouvons déplacer une variable au bas de la ListBox, la variable SumAmount, suivant la position de la colonne Montants.

L'événement formulaire « Sur redimensionnement colonne »

Cet événement formulaire nous permet de détecter le redimensionnement de chaque colonne. Dans notre exemple, l'ordre des colonnes n'a pas été changé, mais leur largeur oui. Nous pouvons les calculer et déplacer ou redimensionner la variable SumAmont ; le redimensionnement de la colonne peut avoir déplacé la colonne Montants.

Le déplacement de cette variable peut devenir très complexe à exécuter. Dans les deux cas, la colonne Montants peut être très petite ou peut même être en dehors de la partie visible de la ListBox. Dans les deux cas, la variable doit être affichée. C'est pourquoi nous exécutions les commandes LIRE RECT OBJET et LIRE PROPRIETES FORMULAIRE pour retrouver la position de la ListBox et la taille du formulaire. Nous avons la nouvelle largeur de la colonne de la colonne Montants et sa position. Si cette position est plus grande que la largeur de la ListBox, cela signifie que la colonne est cachée. Dans ce cas, nous allons déplacer notre variable en dehors de la zone visible du dialogue. C'est pourquoi nous devons connaître la largeur de notre formulaire. Le problème est que ceci aussi demande de ne pas afficher la barre de défilement horizontale. S’il y a une barre de défilement horizontale, nous ne pourrons pas détecter son utilisation. Si la colonne devient maintenant visible, nous ne pourrons pas détecter cela et afficher la variable.

Un contournement serait d'afficher la variable avec des coordonnées fixes quand la colonne Montant devient cachée ou quand la variable devient trop petite et a toujours la barre de défilement horizontale. Aussi, cela signifie que cette variable sera déplacée sous la colonne Montant seulement quand la barre de défilement horizontale sera déplacée par 4D.

Note :
Dans le cade, $x1 et $x2 seront les coordonnées de notre variable. Elles sont calculées en fonction de la position de la colonne et de la taille de la ListBox. Nous avons supprimé 15 pixels de la largeur de la ListBox à cause de l'affichage de la barre de défilement verticale.

L'événement formulaire « Sur clic en-tête »

Cet événement formulaire nous permet de détecter le clic sur l'en-tête de chaque colonne. À partir de cet événement, vous pouvez exécuter votre propre code comme changer des attributs de texte. Si la colonne est triable, le clic sur l'en-tête de la colonne triera cette colonne. Vous pouvez empêcher ce tri en exécutant $0:=1.

Si vous cliquez sur l'en-tête de la colonne Montants, vous pouvez voir que l'événement formulaire est exécuté parce que le titre devient bleu. La méthode-objet test aussi le nom de la variable et s'il s'agit de la variable vAmount, le code $0:=1 est exécuté. Le tri de la colonne est alors refusé. Comme le tri n'a pas été exécuté, l'événement formulaire Sur après tri n'est pas déclenché.

L'événement formulaire « Sur après tri »

Cet événement formulaire est exécuté une fois le tri effectué après un clic sur l'en-tête de la colonne. Cet événement peut être utilisé pour exécuter du code spécifique comme une sélection automatique de la première nouvelle ligne ou utiliser les valeurs de la première ligne pour des calculs spécifiques. Dans notre cas, nous avons auparavant défini un tableau de pointeurs sur chaque variable de l'en-tête colonne. Vous pouvez aussi générer ce tableau en exécutant la commande LIRE TABLEAUX LISTBOX. Si la variable contient 0, elle n'a pas été cliquée. Si elle contient 1 ou 2, un clic, pour un tri ascendant ou descendant, a été fait sur cette variable. Nous savons quel en-tête de colonne a été cliqué. Dans ce cas, nous allons changer le style du texte de l'en-tête : italique ou gras.

L'événement formulaire « Sur avant saisie »

Cet événement est exécuté lorsque vous êtes en train d'éditer une cellule. Dans notre exemple, nous allons voir quelle ligne nous sommes en train d'éditer et interdire l'édition si c'est l'une des premières lignes en envoyant le caractère ECHAP (ESC) au process courant.

L'événement formulaire « Sur déplacement ligne »

Cet événement formulaire est exécuté lorsqu'une ligne est déplacée. Vous pouvez détecter quelle ligne a été déplacée en utilisant la commande NUMERO LIGNE LISTBOX DEPLACEE. Dans notre exemple, nous avons juste affiché l'ancienne et la nouvelle position de la ligne déplacée.

Multipage

L'objectif de cet exemple est de montrer comment afficher plusieurs ListBox sur plusieurs pages d'un formulaire. Cet exemple utilise le formulaire [CONTACTS]Dial7. Nous avons les ListBox MyListBox, MyListBoxP1, MyListBoxP2 et MyListBoxP3 respectivement sur la page 0, page 1, page 2 et page 3.

L'utilisation de cet exemple est très simple. Sélectionnez un élément de la ListBox sur la page 0 et toutes les autres ListBox seront mises à jour. Vous pouvez cliquer sur un élément de l'onglet pour changer de page. Vous pouvez afficher autant de ListBox que vous le souhaitez. Mais il y a un point que vous ne devez pas oublier : les variables doivent être uniques. Vous ne pouvez pas utiliser les mêmes variables ou les mêmes tableaux dans une même ListBox ou dans différentes ListBox sur la même page (page courante ET page 0). Afficher plusieurs fois la même variable sur la même page peut fonctionner, mais il s'agit d'une fonctionnalité qui n'est pas supportée.

Cet exemple aussi montre tous les types de tableaux que les ListBox peuvent afficher et réutilise quelques fonctionnalités déjà décrites dans l'exemple précédent comme la définition d'une petite icône à côté de l'en-tête de colonne, ou l'utilisation d'une énumération sur la colonne Voitures.

En changeant de page, un appel à la méthode M_TailleObjetOptimale est exécuté. Cette méthode calcule la meilleure taille de l'objet pour les colonnes kilométrage, total et marges et redéfinit la largeur de ces colonnes basée sur leur taille.

Puzzle

L'objectif de cet exemple est de montrer une autre façon d'utiliser les ListBox. Cet exemple utilise le formulaire [CONTACT]DialPuzzle. C'est un puzzle avec une image faite de 15 autres images.

Cliquez sur le bouton « Jouez » pour mélanger les images et essayer de reconstruire le logo.

Cette ListBox contient 8 colonnes. 4 colonnes contiennent une image chargée à partir de la Bibliothèque d'Images. Les quatre autres colonnes sont des colonnes d'entiers longs qui contiendront la position de ces images dans la matrice, plus particulièrement la position de la partie vide qui permet le déplacement des autres pièces du puzzle.

Le code utilisé pour suivre chaque mouvement est très simple. Nous cherchons simplement où se trouve l'emplacement vide, de façon à échanger les deux éléments. Comme vous pouvez le voir, aucune autre commande spécifique à la ListBox n'est requise. Tout est une affaire d'échange. La ListBox a simplement été utilisée comme un cadre, un affichage pour nos tableaux.

Conclusion

La ListBox est un objet très puissant qui vous permet d'afficher vos tableaux avec plus de contrôle que les zones de défilement.

La partie 1 de la note technique a exploré les attributs des ListBox tels que vous pouvez les définir en Mode Structure.

La partie 2 a exploré les multiples possibilités offertes par les manipulations des ListBox avec la programmation.

Télécharger la base exemple

Télécharger la base exemple.