Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Charly88

XLDnaute Occasionnel
Une "belle" découverte ce soir dont je n'arrive pas à trouver d'équivalent sur le net : la lecture accompagné d'un Format d'un élément Empty d'un tableau-array le transforme en Null.
En plus court : la lecture d'une donnée impacte la donnée !


Au départ, j'ai une variable tableau de type non défini donc variant qui, après un Redim, reçoit certaines informations chiffrées. Les valeurs possibles sont soit rien (=Empty) soit une décimale allant de 0 à 1. Je traite dans cet array des calculs que je faisais initialement dans un tableau sur une feuille excel.

Lors d'un test, l"envoi final de l'array vers une feuille se met à planter :
Code:
.Cells(y, DecaL3 + 1).Resize(UBound(tTab3, 2), UBound(tTab3, 1)).Value = Application.Transpose(tTab3)

J'inspecte et je découvre que le Tableau contient des Null qui plantent cette ligne de code.
D'où vient le Null ? Au moment de sa création ? Non tout est ok, il y a un Redim puis des infos sont envoyées, rien = Empty.
Par contre, avant l'envoi sur feuille, il est possible que j'affiche les données de ce tableau dans un listview dans un userform. Comme il s'agit de pourcentage, je les formate comme tel... C'est à ce moment que cet abruti va modifier le contenu de mon array sans rien me demander :
Code:
With UserForm3.ListView2
for i = 1 to 10
'(tTab3(i, 1) = Empty
.ListItems(.ListItems.Count).ListSubItems.Add , ,Format(tTab3(i, 1), "0.00%")
'(tTab3(i, 1) = Null
next i
end with

Voilà, si vous avez déjà rencontré cela, si vous connaissez l'explication fondamentale... N'hésitez pas.

Côté conséquences et solutions, j'ai rajouter un condition "if not isempty..." pour m'adapter mais globalement, j'y vois une sacrée pierre dans le beau mais piégeux jardin des Arrays.
 

MichD

XLDnaute Impliqué
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Bonjour,

Je te suggère de donner un exemple complet.

à titre d'exemple :

Même si un élément du tableau est vide la variable est sans valeur, cela n'empêche pas
de renvoyer le tableau dans une feuille de calcul. Au besoin, publie un classeur qui
évoque bien la situation que tu décris.

VB:
Sub test()

Dim T(1 To 2), X As Variant

T(1) = s
T(2) = 5
X = TypeName(T(1))
MsgBox X
Range("A1").Resize(UBound(T, 1)) = Application.Transpose(T)

End Sub
 

Charly88

XLDnaute Occasionnel
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Salut,
Le problème c'est que justement la valeur n'est plus vide, elle est Null.
A cause de l'instruction "lecture-format" de la listview en amont, les Empty (inoffensifs) sont deviennent des Nulls (bloquants).

Dans le cadre de mon programme, j'ai contourné en lui demandant de ne pas lire-formater si le contenu est Empty.
J'essaierai de faire un exemple oui, pour voir au moins si cela se produit dans un contexte plus basique.
 

ROGER2327

XLDnaute Barbatruc
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Bonjour à tous

Ben oui ! C'est comme ça et pis c'est tout !
Code:
Sub tata()
Dim x$, y As Variant
    MsgBox VarType(y)
    x = Format(y, "0.00%")
    MsgBox VarType(y)
End Sub

Comprenne qui pourra...


ROGER2327
#5995


Lundi 9 Gidouille 139 (Sainte Outre, psychiâtre - fête Suprême Quarte)
5 Messidor An CCXX, 3,7564h - mulet
2012-W25-6T09:00:55Z
 

MichD

XLDnaute Impliqué
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Voici ce qui est possible de faire si tu as une valeur nulle dans un item d'un tableau

VB:
Sub Test()
Dim X(1 To 3), Y As Variant, A As Variant
 
'Affecter la valeur nulle à une variable
Y = Null

'Affecte à un élément du tableau, la variable
'dont le contenu est nulle
X(1) = "toto"
X(2) = Y
X(3) = "titi"

'Vérification que le contenu de x(2) est vraiment nul.
MsgBox "Le contenu de X(2) est nul. " & IsNull(X(1))

'Si on veut affecter à une plage de cellules le tableau
'Cette ligne de code est inexploitable
'Range("A1").Resize(UBound(X)) = Application.Transpose(X)

'Cette boucle affecte à la plage A1:A3 le contenu du tableau
'sans aucun problème
For A = LBound(X) To UBound(X)
    Range("A" & A) = X(A)
Next

's'assure que le listbox est vide
Me.ListBox1.Clear

'Cette ligne de code charge le contenu du listbox
'avec le contenu de la plage de cellules
Me.ListBox1.List = Application.Transpose(Range("Feuil1!A1:A3").Value)
    
'Le type du contenu de 3 items du listbox
MsgBox TypeName(Me.ListBox1.List(0, 0))
MsgBox TypeName(Me.ListBox1.List(1, 0))
MsgBox TypeName(Me.ListBox1.List(2, 0))

'Cette façon de faire ne fonctionne pas à cause
Me.ListBox1.Clear
Me.ListBox1.List = Application.Transpose(X)

'On peut utiliser ceci pour charger le Listbox
Me.ListBox1.Clear
For A = LBound(X) To UBound(X)
    If Not IsNull(X(A)) Then
        Me.ListBox1.AddItem X(A)
    End If
Next

End Sub
 

mapomme

XLDnaute Barbatruc
Supporter XLD
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Bonjour à tous,

C'est comme si la fonction "Format" avait un passage d'argument en référence et non en valeur. L'exécution de Format donnerait un type à Y pendant le traitement donc passage de empty à null et retournerait donc un variant null.

En reprenant l'exemple de ROGER2337 et en construisant une nouvelle fonction formatX, on constate que vartype(Y) reste à 0 (empty).

Mais "variant" est-il bien un type ? (en tout cas pas au sens des langages fortement typés, selon moi)

Code:
Sub tata2()
Dim x$, y As Variant
    MsgBox VarType(y)
    x = formatX(y, "0.00%")
    MsgBox VarType(y)
End Sub

Function formatX(ByVal Quoi, ByVal Comment)
  formatX = Format(Quoi, Comment)
End Function

Sub tata()
Dim x$, y As Variant
    MsgBox VarType(y)
    x = Format(y, "0.00%")
    MsgBox VarType(y)
End Sub
 
Dernière édition:

ROGER2327

XLDnaute Barbatruc
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Bonjour à tous


(...)
Mais "variant" est-il bien un type ?
(...)

Oui !

Bill dit clairement :
VarType, fonction
Voir aussi Exemple Particularités

Renvoie une valeur de type Integer qui indique le sous-type d'une variable.

Syntaxe

VarType(varname)

L'argument varname est une valeur de type Variant pouvant contenir toute variable à l'exception d'une variable de type défini par l'utilisateur.

Valeurs renvoyées

Constante Valeur Description
vbEmpty 0 Empty (non initialisée)
vbNull 1 Null (aucune donnée valide)
vbInteger 2 Entier
vbLong 3 Entier long
vbSingle 4 Nombre à virgule flottante en simple précision
vbDouble 5 Nombre à virgule flottante en double précision
vbCurrency 6 Valeur monétaire
vbDate 7 Valeur de date
vbString 8 Chaîne
vbObject 9 Objet
vbError 10 Valeur d'erreur
vbBoolean 11 Valeur booléenne
vbVariant 12 Variant (utilisée seulement avec des tableaux de variants)
vbDataObject 13 Objet d'accès aux données
vbDecimal 14 Valeur décimale
vbByte 17 Octet
vbLongLong 20 Entier LongLong (Valide uniquement sur les plateformes 64 bits.)
vbUserDefinedType 36 Variant contenant des types définis par l'utilisateur
vbArray 8192 Tableau
(...)
La parenthèse est importante ! Le type Variant n'a de sens qu'avec un tableau.
Un tableau de type Variant reste un tableau de type Variant, mais une variable de type Variant prend le type de son contenu.
Le problème n'est pas le typage des variables, mais la documentation sommaire de certaines fonctions. On s'attend généralement à ce qu'une fonction renvoie le résultat du traitement de son (ou ses) argument(s) sans modifier son (ou ses) argument(s). On imagine mal, par exemple, que demander le calcul de sinus(x) avec x=pi/2 entraîne ipso facto que la valeur de x soit transformée en 90° sans que ce comportement étrange soit signalé. C'est pourtant, mutatis mutandis, ce que fait la fonction Format en remplaçant la valeur de son argument de type Empty en valeur de type Null, sans que mention de ce comportement aberrant soit faite dans la documentation de la dite fonction. Ce comportement va peut-être de soi dans la logique microsoftienne[SUP](1)[/SUP], mais est suffisamment éloigné de la logique commune pour mériter d'être signalé.

Ceci dit, un remède possible pour prévenir la modification intempestive de la nature ou de la valeur de l'argument consiste à passer par une variable intermédiaire :​
VB:
Sub tata()
Dim x$, u As Variant, y As Variant
    MsgBox VarType(y)
    u = y
    x = Format(u, "0.00%")
    MsgBox VarType(y)
End Sub

L'attrait principal d'Excel et de son langage associé n'est-il pas dans le dépistage et le traitement de ses bogues ?​

___________
Note :
[SUP](1)[/SUP] Un des plus beaux exemples de cette logique est que, numérotant les jours en commençant par 1 pour le lundi premier janvier 1900, le lendemain du jour 59 est le jour 61...
Rassurons-nous, ce bogue a été immédiatement corrigé par l'introduction d'un jour n°60 entre le n°59 et le n°61. Le fait que ce jour n'a existé dans aucun calendrier n'est pas de nature à ébranler l'assurance de son inventeur : on trouve par exemple dans l'aide d'Excel2010 sur la fonction DATE que le numéro de série qui représente 8/7/2008 (un mardi) est 39637, fausseté évidente. Que cette fausseté soit répétée dans les versions successives d'Excel ne suffit pas à en faire une vérité.

(L'évidence résulte de ce que le numéro de série 1 représentant un lundi, tous les numéros de série des lundis sont congrus à 1 modulo 7. Par conséquent le numéro de série du mardi 8 juillet 2008 est congru à 2 modulo 7. Ce ne peut donc être 39637, qui est congru à 3 modulo 7.)





ROGER2327
#5997


Mardi 10 Gidouille 139 (Saint Boudin, recteur - fête Suprême Quarte)
6 Messidor An CCXX, 0,5583h - romarin
2012-W25-7T01:20:23Z
 

MichD

XLDnaute Impliqué
Re : Lecture d'une variable Tableau (Array) avec Format transforme Empty en Null.

Un autre petit exemple : un listbox dans la feuille "Feuil1"

Une variable de type tableau(array) de UN élément.

Lorsque cet élément soit vide, la ligne de code s'exécute correctement : Feuil1.ListBox1.AddItem T(1)

Si j'affecte par la suite, la valeur Null ou Empty à l'élément du tableau,
la ligne de code suivante s'exécute sans problème : Feuil1.ListBox1.AddItem Format(T(1), "0.00%")

Après exécution de cette ligne de code, T(1) est Nul.

Si on regarde la définition de "IsNull" dans l'aide d'Excel,
Renvoie une valeur de type Boolean qui indique si une expression ne contient aucune donnée valide (Null).

On peut se poser la question : Est-ce que l'application d'un format à un expression = vide retourne une valeur valide???

Quoi qu'il en soit, cela ne bloque pas l'ajout de l'élément dans le listbox. (Excel 2010)


VB:
Sub test()

Dim T(1)

If IsEmpty(T(1)) Then
    Feuil1.ListBox1.AddItem T(1)
End If

T(1) = Null  'Ou Empty
Feuil1.ListBox1.AddItem Format(T(1), "0.00%")

End Sub
 

Discussions similaires

Réponses
1
Affichages
938

Statistiques des forums

Discussions
312 237
Messages
2 086 489
Membres
103 234
dernier inscrit
matteo75654548