IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VBA Access Discussion :

collection de variables typées


Sujet :

VBA Access

  1. #1
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Par défaut collection de variables typées
    salut à tous,

    j'ai une collection de variables typées à faire mais prb:
    je n'arrive pas à ajouter de variables et je ne vois pas comment les récupérer dans la collection.
    en clair: je sais pas comment faire une collection de variables typées.
    (je ne parle pas de collection d'objet ou de type classic:variant,string...)

    voilà un exemple du code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    Option Compare Database
    Option Explicit
     
    Type ta
        unephrase1 As String
        unephrase2 As String
    End Type
     
    Type tc
        uneCollection As Collection
        uneVariableLocal As Variant
    End Type
     
    Public c As tc
     
    Sub essai2()
    Dim a As ta
    a.unephrase1 = "phrase1"
    a.unephrase2 = "phrase2"
     
    c.uneCollection.Add Item:=a, Key:="1"  '<- erreur ici sur le type de a
    End Sub
     
    Public Sub essai1()
    Set c.uneCollection = New Collection
    Dim n As ta
     
    essai2
     
    For Each n In c.uneCollection
        MsgBox n.unephrase1                '<- problème aussi ici
    Next n
    End Sub
    tc est une variable typée contenant la collection.
    ta est le type que je veux mettre dans collection.

    merci de votre aide

  2. #2
    Expert confirmé
    Avatar de LedZeppII
    Homme Profil pro
    Maintenance données produits
    Inscrit en
    Décembre 2005
    Messages
    4 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Maintenance données produits
    Secteur : Distribution

    Informations forums :
    Inscription : Décembre 2005
    Messages : 4 485
    Par défaut
    Salut Vodiem,

    J'ai bien peur que ça ne soit pas possible (VBA ne convertit par les types définis par l'utilisateur en Variant)
    et que le seul moyen soit de convertir ton type de données personnalisé (ta) en module de classe.
    Du coup ta variable a sera typée objet et non plus 'type de donnée défini par l'utilisateur'.

    Mais un avange quand même, tu peux instancier (New ta) au fur et à mesure, et alimenter ta collection.
    Avec une variable non objet tu serai obligé de créer un tableau pour avoir plusieurs variables du même type.

    A+

  3. #3
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Par défaut
    je te remercie LedZeppII pour ta réponse,

    je suis parti de l'aide sur "add, méthode de collection" qui dit:
    Ajoute un membre à un objet Collection.
    avec liaison sur la définition de membre:
    membre:
    Élément d'une collection, d'un objet ou d'un type défini par l'utilisateur.
    mais le message d'erreur dit:
    Erreur de compilation:
    Seuls les types définis par l'utilisateur et qui sont définis dans les modules d'objets publics peuvent être convertis depuis ou vers un variant, ou passés à des fonctions à liaison tardive
    donc: j'ai essayé de déclarer dans un module de classe mais en vain sans le typer objet.

    Mais un avange quand même, tu peux instancier (New ta) au fur et à mesure, et alimenter ta collection.
    Avec une variable non objet tu serai obligé de créer un tableau pour avoir plusieurs variables du même type.
    effectivement j'ai été surpris de constater que la méthode add n'instancie pas l'objet.
    avec une variable non objet: on peut aussi l'instancier, et si je pouvais mettre dans une collection le problème du tableau ne se poserais pas.

    en tous cas: je te remercie LedZeppII.

    je laisse encore la discution ouverte qq temps, pour être sur de pas passer à côté d'une solus.
    même les avis confortant l'impossibilité de créer une collection de variables typées sont les bienvenus.

  4. #4
    Expert confirmé

    Profil pro
    Inscrit en
    Mai 2005
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 419
    Par défaut
    ceci fonctionne

    crée un module de classe nommé maclasse
    contenu
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Public phrase1 As String
    Public phrase2 As String
    et insére un module de code avec ce sub
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
     
    Sub tcoll()
    Dim u As Variant
    Dim utilcl As New maclasse
    Dim macoll As New Collection
    utilcl.phrase1 = "Souvent pour s'amuser"
    utilcl.phrase2 = "les hommes d'équipage"
    macoll.Add Item:=utilcl
    Set utilcl = Nothing
    utilcl.phrase1 = "Prennent des albatros,"
    utilcl.phrase2 = "vastes oiseaux des mers"
    macoll.Add Item:=utilcl
    Set utilcl = Nothing
    For Each u In macoll
    MsgBox (u.phrase1 & " " & u.phrase2)
    Next u
    End Sub
    sinon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Sub bis()
    Dim var1(1 To 2) As String
    Dim macoll As New Collection
    Dim boucle
    var1(1) = "coucou"
    var1(2) = "de Bavière"
    macoll.Add var1
    var1(1) = "pond"
    var1(2) = "au printemps"
    macoll.Add var1
    For Each boucle In macoll
    MsgBox (boucle(1) & " " & boucle(2))
    Next boucle
    End Sub
    je confirme ne pas savoir ajouter à une collection un type défini par un utilisateur
    plusieurs essais infructueux

  5. #5
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Par défaut
    random:
    je confirme ne pas savoir ajouter à une collection un type défini par un utilisateur
    plusieurs essais infructueux
    ben ca va être chaud si toi aussi tu n'y arrive pas

    LedZeppII m'avait proposé aussi en MP un module de classe, que j'ai du aussi faire entre temps pour palier au pb.

    mais je reste très perplexe sur ton exemple, car j'avais fait un essai, en gros comme tcoll() mais j'avais omis le "Set utilcl = Nothing" ce qui m'a donné un collection avec que le dernier objet. j'ai conclu que add n'instanciais pas l'objet mais ajoutait le pointeur de l'objet dans la collection. sinon dois je conclure que le "Set utilcl = Nothing" libère l'objet et l'affectation de utilcl.phrase1 crée une nouvelle instance de l'objet?
    mais dans bis() là c'est clair qu'il n'y a pas de nouvelle instanciation du tableau.
    dois je conclure que add instancie l'item?
    je ne comprends alors pas pourquoi le "Set utilcl = Nothing" qui semble indispensable...

    ps: merci à tous deux pour vos codes.

  6. #6
    Expert confirmé

    Profil pro
    Inscrit en
    Mai 2005
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 419
    Par défaut
    En fait c’est tout simple tant que l’objet est instancié la collection gère un pointeur (une référence vers cet objet).
    Quand l’instance disparaît (set ma var=nothing) ou est remplacée (set mavar=new objectype)
    Elle est remplacée dans la collection (lorsque c’est possible par sa valeur)

  7. #7
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    Bjr,

    Personnellement je n'utilise pas de classe dans une collection pour ce genre de code.
    Je stocke tout dans des tableaux, au moins ce sont les valeurs qui sont stockées et non pas un pointeur vers un objet qui sera détruit à la sortie de la procédure d'ajout.
    L'utilisation des tableaux est par contre un peu gênante parce que moins facile à lire, surtout si on a besoin de nombreuses valeurs.
    Attaquer chaque valeur avec son indice dans le tableau devient illisible alors qu'avec un type on voit clairement le nom de la valeur lue dans le code et on profite de l'intellisense pour choisir la valeur dans une liste déroulante.
    On peut alors ajouter deux petites fonctions pour convertir le type en tableau et vice-versa.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
     
    Type ta
        unephrase1 As String
        unephrase2 As String
    End Type
     
    Type tc
        uneCollection As Collection
        uneVariableLocal As Variant
    End Type
     
    Public c As tc
     
    Public Function TaToArray(pTa As Ta) As Variant
    TaToArray = Array(pTa.unephrase1 , pTa.unephrase2)
    End Function
    Public Function ArrayToTa(pArray As Variant) As Ta
    Dim lLBound As Long
    lLBound = LBound(pArray)
    ArrayToTa.unephrase1 = pArray(lLBound)
    ArrayToTa.unephrase2 = pArray(lLBound + 1)
    End Function
    Ensuite on utilise ces fonctions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    Sub essai2()
    Dim a As ta
    a.unephrase1 = "phrase1"
    a.unephrase2 = "phrase2"
     
    c.uneCollection.Add Item:=TaToArray(a), Key:="1"
    End Sub
     
    Public Sub essai1()
    Set c.uneCollection = New Collection
    Dim n As ta
    Dim lCpt As Long
     
    essai2
     
    For lCpt = 1 To c.uneCollection.Count
        n = ArrayToTa(c.uneCollection.Item(lCpt))
        MsgBox n.unephrase1                '<- problème aussi ici
    Next
    End Sub

  8. #8
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Par défaut
    donc 'collection' ajoute à sa liste des pointeurs, qui s'ils sont libérés, 'collection' leur créent une instanciation.
    dans le cas de bis(): l'affectation d'une nouvelle valeur pour le tableau crée automatiquement une instanciation dans collection.

    mouais , je trouve pas ca logique que 'collection' n'instancie pas automatiquement aussi pour les objets et seulement quand ils sont libérés.

    ... (<- là j'ai réfléchi )

    d'un autre coté collection ne connait pas le type de l'objet, on l'instancie et l'initialise pour lui, à ce moment il ne fait que conserver l'objet. de fait: c'est ce qu'il fait...
    quand il connait le type: il l'instancie quand c'est un objet il nous laisse le faire.
    oui là, c'est logique.

    oups, j'ai manqué le post de Arkham46 ...

  9. #9
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Par défaut
    ok super Arkham46,

    ca m'avait effleuré l'esprit le 'transtypage' du pointeur de l'objet.
    en fait: je voyais pas comment le faire en vba.

    donc j'ai repris ton code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    c.uneCollection.Add Item:=Array(a.unephrase1, a.unephrase2), Key:="1"
    avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Dim n As Variant
    Dim m As ta
     
    For Each n In c.uneCollection
        m.unephrase1 = n(LBound(n)): m.unephrase2 = n(LBound(n) + 1)
        MsgBox m.unephrase1 + " " + m.unephrase2
    Next n
    le passage par fonction c'est pas mal non plus.

    merci

  10. #10
    Expert confirmé
    Avatar de Arkham46
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    5 865
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Septembre 2003
    Messages : 5 865
    Par défaut
    bon alors j'ai quand même fait des tests et en fait ça marche très bien avec une collection de classe même si le remplissage de la collection se fait dans une procédure et la lecture dans une autre. ...

    Je crée un module de classe nommée Classe1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Option Explicit
     
    Public unephrase1 As String
    Public unephrase2 As String
    Je modifie ensuite le code du premier message comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    Type tc
        uneCollection As Collection
        uneVariableLocal As Variant
    End Type
     
    Public c As tc
     
    Sub essai2()
    Dim a As Classe1
    Set a = New Classe1
    a.unephrase1 = "phrase1"
    a.unephrase2 = "phrase2"
     
    c.uneCollection.Add Item:=a, Key:="1"  
    Set a = Nothing
     
    Set a = New Classe1
    a.unephrase1 = "phrase3"
    a.unephrase2 = "phrase4"
    c.uneCollection.Add Item:=a, Key:="2"  
    Set a = Nothing
     
    End Sub
     
    Public Sub essai1()
    Set c.uneCollection = New Collection
    Dim n As Classe1
    Dim lCpt As Long
     
    essai2
     
    For lCpt = 1 To c.uneCollection.Count
        Set n = c.uneCollection.Item(lCpt)
        MsgBox n.unephrase1
    Next
    End Sub
    Lors de l'instruction <Set a = New Classe1> il crée un nouvel objet.
    Lorsqu'on ajoute cet objet à la collection il incrémente le compteur de référence de l'objet.
    Ensuite on peut libérer l'objet avec <Set a = Nothing>, le compteur de référence de lobjet est décrémenté.
    Mais il reste 1 dans ce compteur de référence (vu que l'objet est aussi dans la collection), donc l'objet n'est pas détruit.
    Pour preuve l'événement Terminate de la classe n'est pas levé.
    Par contre si on supprimer l'objet de la collection avec <c.uneCollection.Remove("1")>, alors le compteur de référence tombe à zéro et l'objet est détruit (l'événement Terminate se déclenche alors).

    On peut regarder le pointeur de chaque objet :
    Debug.print ObjPtr(a)
    pour constater que le New crée un objet avec un nouveau pointeur et n'écrase donc pas l'objet précédent.
    On peut également regarder le pointeur de l'objet dans la collection :
    Debug.print ObjPtr(c.uneCollection.item("1"))
    C'est le même pointeur que l'objet a.

    Attention quand même à la libération des objets, il ne sont libérés qu'à la desctruction de la collection ou lorsqu'on les retire de cette collection.

  11. #11
    Expert confirmé

    Profil pro
    Inscrit en
    Mai 2005
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 419
    Par défaut
    après vérification on ne peut pas affecter à une collection les types crées par l'utilisateur
    pour apporter une variante à la méthode arhkam
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Function parkey()
    Dim macoll As New Collection
    Dim boucle As Integer
    For boucle = 1 To 12
    macoll.Add Item:=DateSerial(2007, boucle, 1), key:=boucle & "fdate"
    macoll.Add Item:=Format(DateSerial(2007, boucle, 1), "mmmm"), key:=boucle & "nom"
    Next boucle
    MsgBox (macoll("1nom"))
    For boucle = 1 To 12
    MsgBox (macoll(CStr(boucle) & "fdate"))
    MsgBox (macoll(boucle & "nom"))
    Next boucle
    End Function

  12. #12
    Expert confirmé
    Avatar de vodiem
    Homme Profil pro
    Vivre
    Inscrit en
    Avril 2006
    Messages
    2 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Vivre
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2006
    Messages : 2 895
    Par défaut
    merci random,
    c'est une possibilité aussi.

    j'ai continué à faire aussi des recherches de mon côté mais en vain.
    si en VB cela semble possible en VBA cela ne le semble pas.

    je ne suis pas non plus parvenu à comprendre le mécanisme de Add, pour un objet ok, mais comme dans l'exemple bis() de random, une collection de VarPtr, les items ont les mêmes adresse de pointeur dans la collection et pourtant les valeurs sont bien différentes.

    enfin, je vais conclure: collection de variables typées = pas possibles.

  13. #13
    Expert confirmé

    Profil pro
    Inscrit en
    Mai 2005
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 419
    Par défaut
    c'est dailleurs ce que dit microsoft
    une collection peut recevoir tous les types de données contenus dans un variant

    un variant ne peut pas recevoir de variable à défini par l'utilisateur

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Collection et variable non instancié
    Par david06600 dans le forum Langage
    Réponses: 1
    Dernier message: 17/08/2006, 15h23
  2. Récupération de variable type texte
    Par flambo88 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 28/01/2006, 18h21
  3. DEBUTANT Lire dans une variable type CString
    Par Hokagge dans le forum MFC
    Réponses: 2
    Dernier message: 01/12/2005, 11h53
  4. variable type tableau (vector) statique / constants
    Par Kaktus dans le forum SL & STL
    Réponses: 5
    Dernier message: 13/10/2005, 23h46
  5. Réponses: 1
    Dernier message: 27/07/2005, 18h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo