Un bug inextricable

Bonsoiir à tous,

Cette fois ci je me heurte à un bug inexplicable et j'en reste sur le c....
Voici, je suis en train d'aider un Forumeur qui désire remplir des cellules d'un tableau en fonction de 2 choix, choix d'un article et choix d'u mois

image

je lui ai donc proposé, par le biais d'un Userform contenant des ListBox et des Textbox, d'abord de choisir l'article afin de déterminer la ligne qu'il faudra utiliser, et ensuite de choisir le mois afin de déterminer la colonne à utiliser, je mets donc en évidence un couple de varaiables lg et cl qui me permet de déterminer la cellule située en haut à gauche des 6 cellules correspondantes aux choix faits. Enfin il me suffit de remplir mes cellules avec le contenu des 6 textbox de l'userform.

Tout marchait bien, voir l'image danc laquelle mon code a été utilisé plusieurs fois et puis d'un seul coup un bug
La ligne Cells(lg, cl) = .textbox1.Value ne fonctionne plus, si je remplace cl par un nombre aucun problème, mais ce qui est encore plus bizare c'est que les lignes suivantes fonctionnent Cells(lg, cl+1) = .textBox2 et Cells(lg, cl + 2) = .textbox 3, elles reconnaissent la valeur attribuée à cl

Je n'y comprends plus rien
Je vous joins mon fichier

13essai-6-2.xlsm (46.66 Ko)

Bonsoir,

vous avez d'un côté "café en grain" et de l'autre "café en grainS" !
Ensuite enlevez moi tous ces guillemet !

Et ATTENTION !
lorsque vous faites Dim lg, cl, rg As Integer seul rg est considéré comme Integer !
donc : Dim Lg As Long, Cl As Integer, Rg As Long

j'ai mis Long pour tout ce qui concerne les lignes sait-on jamais le Integer est limité à 32 767 ! en positif et négatif me semble t il...

Le fichier en retour :

12essai-6-2.xlsm (34.51 Ko)

@ bientôt

LouReeD

Bonsoir LouReed,

Je ne comprends pas pourquoi il faut définir mes variables en Long et non Integer sachant que les valeurs les concernant ne dépasseront jamais 20
Quant au "s" de trop dans "Café en grain" je m'en étaiis rendu compte et croyais avoir mis en ligne le fchier où ce "S" n'existait plus
Oui les guillemets n'ont aucune raison d'exister

je reste quand même perplexe
Un grand merci et au plaisir de te retrouver

Alors si vous regardez le fichier fourni j'ai laissé le Integer, car en effet au vu du fichier cela est suffisant voir le byte...
Sinon le typage "collectif" a permis une incompatibilité de type. En effet vu que le typage collectif ne marche pas, alors cl et lg pouvait recevoir des valeur "alphanumérique" (chiffre avec guillemet = du texte), donc pas d'erreur à ce niveau.

Après je reste perplexe également si le code fonctionnait sur les autres ligne et colonnes...

Toujours est-il qu'il vaut mieux prendre des patates quand on veux des patates plutôt que de laisser choisir VBA...

Bonne soirée @ vous et n'hésitez pas à revenir.

@ bientôt

LouReeD

Bonsoir à tous,

Quand on utilise une combobox (ou listbox) on ne s'intéresse généralement pas aux libellés des articles pour savoir lequel des articlés a été sélectionné.

L'avantage c'est qu'on se libère des fautes de frappe et d'orthographe et ça diminue la taille du code.

Il y a une une propriété de Combobox qui s'appelle ListIndex.

Si un élément a été sélectionné, alors Listindex contient un entier qui est l'index de l'élément choisi avec pour règle :

  • si aucun élément de la ComboBox n'a été sélectionné, alors ListIndex vaut -1
  • si c'est le premier élément qui a été sélectionné, alors ListIndex vaut 0
  • si c'est le deuxième élément qui a été sélectionné, alors ListIndex vaut 1
  • si c'est le troisième élément qui a été sélectionné, alors ListIndex vaut 2
  • ...
  • si c'est le N ème élément qui a été sélectionné, alors ListIndex vaut N-1
  • ...
  • si c'est le dernier élément qui a été sélectionné, alors ListIndex vaut ListCount - 1

Ainsi on connait l'élément sélectionné (aucun le cas échéant) sans connaitre son libellé.

En connaissant ListIndex, on peut retrouver le libellé si on en a besoin : Combox.List(Combox.ListIndex)

Les codes sont en général du type ci-dessous (il faut toujours traiter le cas où aucun élément n'a été sélectionné) :

If ComboBox.ListIndex = -1 Then
   ' Code pour faire ce qu'on doit faire quand rien n'a été sélectionné
   ...
Else
   ' Code pour faire ce qu'on doit faire quand un élément est sélectionné
   ...
Endif

nota : en cas de ComboBox à plusieurs colonnes, Listindex reste tel qu'il est décrit. C'est juste comment retrouver une valeur de la ligne sélectionnée qui est modifié.

Si on veut la valeur de 3ème colonne de la ligne sélectionnée , on écrira : Combox.List(Combox.ListIndex , 2). La numérotation des colonnes commence aussi à 0 et non pas à 1.

@LouReeD,

Je reviens sur les remarques que tu as faites

j'ai laissé le Integer, car en effet au vu du fichier cela est suffisant voir le byte...

c'est bien ce qu'il me semblait

cl et lg pouvait recevoir des valeur "alphanumérique" (chiffre avec guillemet = du texte), donc pas d'erreur à ce niveau.

toujours d'accord avec toi

Après je reste perplexe également si le code fonctionnait sur les autres ligne et colonnes.

que puis-je dire, si ce n'est que j'en suis dépassé. Je serais heureux de pouvoir en connaître la raison. Que l'on puisse m'expliquer pourquoi avec

    Cells(lg, cl) = .TextBox1.Value
    Cells(lg, cl + 1) = .TextBox2.Value
    Cells(lg, cl + 2) = .TextBox3.Value
    Cells(lg + 1, cl) = .TextBox4.Value
    Cells(lg + 1, cl + 1) = .TextBox5.Value
    Cells(lg + 1, cl + 2) = .TextBox6.Value

on se plante sur la première et la quatrième ligne, mais avec

    Cells(lg, 2) = .TextBox1.Value
    Cells(lg, cl + 1) = .TextBox2.Value
    Cells(lg, cl + 2) = .TextBox3.Value
    Cells(lg + 1, 2) = .TextBox4.Value
    Cells(lg + 1, cl + 1) = .TextBox5.Value
    Cells(lg + 1, cl + 2) = .TextBox6.Value

ça fonctionne, les textbox 1 et 4 se postionnent en Janvier (cl remplacé par 2), mais les textebox 2, 3, 5 et 6 se positionnent en Avril au cas où on aurait choisi Avril pour le mois (donc cl = 11)

Encore un grand merci LouReed d'avoir passé un peu de temps sur ce mystère, au plaisir de te retrouver

@mafraise,

En effet pour éviter la pseudo faute d'orthographe que j'avais faite avec "Café en grain(S)" un ListIndex est recommandé
Mais mon problème (le bug) ne se situe pas à ce niveau, regardes ce que j'ai écrit à LouReed dans le message précédent
Encore merci, mafraise, de t'être penché sur ma question et au plaisir de te retrouver sur le Forum

En ces heures maintenant estivales, bonjour Jacky et bonjour LouReed,

Une tentative d’expliquer le pourquoi de la perplexité de Jacky.

...

Il y a des choses qu’on ignore au sujet d’Excel :

  • Le fonctionnement et codage interne des propriétés et procédures de VBA et des objets manipulés.
  • La manière avec laquelle VBA fait ses conversions implicites tout seul comme le grand garçon qu'il veut être.

Cela entraîne des répercussions quelque fois inattendues et surprenantes sur l'exécution des codes qu’on écrit et leurs résultats.

---

La propriété Cells( lig , col ) s’attend :

  • À ce que lig soit un entier (de préférence de type long) et pas un string
  • À ce que col soit un entier ou un string. Si c’est un entier alors Cells considère que c’est le numéro d’une colonne. Si c’est un string, alors Cells s’attend à un en-tête textuel de colonne comme "A", "H", "AE" ou "xfd".

---

Que se passe-t-il avec Cells( lig , col + 1) quand col vaut le string "2" ?

  • VBA tente un retourné acrobatique de conversion implicite dont le résultat est le nombre 2.
  • Ensuite, il y ajoute 1 pour trouver 3.
  • Puis il injecte ce nombre 3 dans l’expression Cells( lig, 3).

Cells voit un nombre pour la colonne (3) et ça lui va bien. Cells considère que 3 désigne un numéro de colonne (la 3ème en l’occurrence).

---

Et que se passe-t-il avec Cells( lig , col ) quand col vaut le string "2" ?

  • VBA ne fait pas de conversion avec col (pas d'opération arithmétique)
  • Il injecte donc directement le contenu de col dans Cells soit Cells( lig , "2")

Cells considère que la colonne est désignée par un string. Mais ce string "2" n’est pas un en-tête textuel de colonne.

On ne sait pas ce que Cells va en faire puisqu’on ne connait pas son fonctionnement interne.

Cela explique pourquoi quand il y a une opération arithmétique, ça fonctionne et sans opération arithmétique ça échoue.

---

VBA n’est pas un langage fortement typé. Il se permet des choses (conversion implicite) qu’un langage fortement typé refuserait dès la compilation.

Pour pallier cela, on peut s’obliger à déclarer et à typer toutes les variables du code. Typer au plus près c’est-à-dire ne pas déclarer toutes les variables comme étant de type variant (ça ne servirait à rien).

Les avantages :

  • Pour chaque variable, on se pose la question de son type.
  • On évite les fautes de frappe dans l’utilisation des noms de variables (par exemple grain = 999 et grains = 999)

Mais (il y a toujours un mais), la tendance naturelle que j’ai à en faire le moins possible me pousse, de temps à autres, à oublier « Option Explicit » et à laisser faire les conversions implicites de VBA. Je m’en suis déjà cruellement mordu les doigts.

En toute rigueur, on pourrait écrire pour tout contrôler : Dim col as Long et ensuite col = Clng("2") + 1 mais ça n'empêchera pas col = "2" de fonctionner car VBA fera une conversion implicite. Un langage fortement typé refuserait col = "2"

---

En tout cas, j’utilise un maximum Option Explicit avec un typage au plus proche de ce que je crois être nécessaire. Mais chacun fait comme il veut et souvent comme il peut.

Bonjour Mafraise,

Ouah! quelle explication complète et très explicite, bravo!
Comment peux-tu être un expert de cette taille avec Excel ?

Je te remercie énormément, et il est vrai que ce que tu nous dis, nous permet de comprendre le bug auquel je me heurtais

Et que se passe-t-il avec Cells( lig , col ) quand col vaut le string "2" ?

VBA ne fait pas de conversion avec col (pas d'opération arithmétique)

Il injecte donc directement le contenu de col dans Cells soit Cells( lig , "2")

Cells considère que la colonne est désignée par un string. Mais ce string "2" n’est pas un en-tête textuel de colonne.

On ne sait pas ce que Cells va en faire puisqu’on ne connait pas son fonctionnement interne.

Cela explique pourquoi quand il y a une opération arithmétique, ça fonctionne et sans opération arithmétique ça échoue.

Désormais je ferai très attention au type à utiliser

Encore un grand merci et surtout bonne journée

En ces heures maintenant estivales, bonjour Jacky et bonjour LouReed,

Une tentative d’expliquer le pourquoi de la perplexité de Jacky.

......[0

T.O.P.


EDIT : j'ajouterai que pour comprendre un peu mieux les conversions de VBA on peut suivre le raisonnement suivant :

Le code va toujours essayer de faire des conversions de types (nombre vers texte, texte vers date etc.) là où il a besoin d'un certain type (par exemple un nombre) et qu'on lui en donne un autre (par exemple du texte).

MAIS : le code ne va jamais essayer de "comprendre" ce qu'on lui demande. Dans le bon exemple du numéro de colonne de @mafraise, si le code a besoin d'un type [texte ou nombre] et qu'on lui donne l'un des 2, il va le garder tel quel, sans faire la moindre conversion. Càd qu'en effet, même si "2" se convertit très bien en nombre, comme la fonction Cells(a,b) accepte b en texte, alors le code va faire ceci :

Qu'est-ce que b :

  • Un nombre (entier) ? -> parfait je l'utilise tel quel
  • Un texte ? -> parfait je l'utilise tel quel
  • Autre chose ? -> j'essaie de le convertir

Donc avec "2" on est dans le 2e cas, et il lève une erreur car la colonne "2" n'existe pas, elle s'appelle "B".

Et c'est valable pour toutes les fonctions !

Donc, comme déjà dit, il est primordial de bien déclarer ses variables en fonction de comment on veut les utiliser, et de réduire l'utilisation des Variant au maximum. Ils ont leurs avantages, mais c'est pour un usage avancé du VBA. On peut faire 99% du code sans.

Bonjour à tous ,

saboh12617 : Très beau complément qui éclaire bien l’objet de la discussion. La dernière remarque de ton intervention sur le fait que le type variant peut être utile m’a donné l’idée de la fonction suivante (juste pour le fun).

Cette fonction s’appelle Cellx et prend comme argument une référence de ligne (xlig), une référence de colonne (ycol) et une référence de feuille de calcul (xFeuil). xlig et ycol sont de type Variant. XFeuil est de type Worksheet. xlig et xcol peuvent être des nombres ou des String.

La fonction renvoie une cellule appartenant à xFeuil avec pour ligne xlig et avec pour colonne ycol.

  • xlig : c’est un variant. C’est un numéro de ligne (3) ou bien un String représentant un numéro de ligne "3"
  • ycol : c’est un variant. C’est un numéro de colonne (5) ou bien un String représentant un numéro de ligne "5" . Ça peut être aussi un string d’en-tête textuel de colonne ("K" ou "BD")
  • xFeuil : c’est la feuille de calcul contenant la cellule renvoyée par Cellx. Si cet argument est omis alors la feuille cible sera la feuille active.
  • Si la fonction n'arrive pas à construire la cellule qu'elle doit retourner (par exemple le numéro de ligne est -5 ou 9 999 999) alors la fonction retourne Nothing.

Exemple :

  • Set cellule = Cellx("3" , "5") renvoie la cellule E3 de la feuille active
  • Set cellule = cellx(10, "H", Worksheets(“Feuil2”) renvoie la cellule H10 de la feuille "Feuil2"

Le code (commenté dans le classeur) :

Function Cellx(ByVal xlig As Variant, ByVal ycol As Variant, Optional zFeuil As Worksheet) As Range
Dim cellule As Range
On Error GoTo Erreur
   If zFeuil Is Nothing Then Set zFeuil = ActiveSheet
   xlig = Fix(CLng(xlig))
   If IsNumeric(ycol) Then
      ycol = Fix(CLng(ycol))
      Set cellule = zFeuil.Cells(xlig, ycol)
   Else
      Set cellule = zFeuil.Range(ycol & xlig)
   End If
   Set Cellx = cellule
Erreur:
End Function

Hello,

Ça fait du bien de tomber sur des conversations intéressantes !

Merci @mafraise !

Bonsoir à tous,

Pour converser il faut au minimum être deux !

Ok je sort...en plus rien d'intéressant...oui oui je suis déjà dehors...

@ bientôt

LouReeD

Allez LouReed, tel que je te connais tu sors par la porte comme tu le dis, mais je suis sûr que tu rentreras très vite par la fenêtre

A la prochaine

bien sûr !

@ (très) bientôt

LouReeD

Rechercher des sujets similaires à "bug inextricable"