[VBA EXCEL] besoin d'aide pour une macro

Bonjour,

voila je suis super débutant en VBA et j'essaie de programmer une fonction complémentaire.
Mon but est de prendre comme argument une plage de cellules (plusieurs cellules sur une meme ligne ou sur une meme colone), de déterminer le nombre de cellules. A partir de là, je construis un vecteur colonne en prenant les données de la plage de cellules et une matrice.
On termine ensuite par un ou 2 petits calculs.

Je vous mets ce que j'ai écrit pour me dire ce qui ne va pas ...

Function Note(E)
' E correspond à une plage de cellules

Dim n As Integer
Dim an
Dim A, Am
Dim i As Integer, j As Integer
Dim lg As Integer, cl As Integer

Set P = Range("E")
lg = P.Rows.Count
cl = P.Columns.Count
'mes données sont sur une meme ligne ou sur une meme colonne
' et je souhaite le déterminer
If cl = 1 Then
n = lg
ElseIf lg = 1 Then
n = cl
End If

an = 2 * Pi / n

'définition de ma matrice et de mon vecteur
Dim M(n - 1, n - 1)
Dim X(n - 1, 0)

If cl = 1 Then
For i = 0 To n - 1
X(i - 1, 0) = R(i - 1, 0)
Next i
ElseIf lg = 1 Then
For i = 0 To n - 1
X(i - 1, 0) = R(0, i - 1)
Next i
End If

For i = 0 To n - 1
For j = 0 To n - 1
M(i, j) = 0
Next j
Next i

M(n - 1, 0) = 1
For i = 0 To n - 2
M(i, i + 1) = 1
Next i

'quelques petits calculs
A = 1 / 2 * Sin(an) * Transpose(X) * M * X
Am = 1 / 2 * Sin(an) * 100 ^ 2 * n
Note = A / Am

End Function

merci bp
Configuration: Windows XP
Internet Explorer 6.0

26 réponses

Résumé de la discussion

La problématique porte sur une fonction VBA Note qui prend une plage de cellules en argument et construit un vecteur colonne et une matrice avant d’effectuer quelques calculs. Des corrections essentielles consistent à remplacer les accès et boucles avec des index 0-based par des références directes, et à utiliser des tableaux dynamiques avec Redim pour les dimensions variables. La meilleure réponse recommande d’alimenter X via ActiveSheet.Cells(lg, Rng(i)) et de passer Rng() en Variant, puis d’adapter la signature en Function fNote(lg As Integer, Rng() As Variant) As Double. En complément, il faut noter que la gestion des dimensions dynamiques et des valeurs non numériques nécessite des vérifications et des conversions appropriées pour éviter des erreurs d’exécution et des résultats incorrects.

Bobot (l’IA à votre service)
  1. "variable ou procédure attendue et non un module"
    ça ne voudrait pas dire que tu aurais nommé un module Note dans ton application ? auquel cas, tu n'as pas le droit d'appeler une fonction Note aussi
    2
    1. Bonjour,

      Set P = Range("E") 

      avec ça, tu travailles sur la colonne E et non pas sur la plage E passée en paramètre
      travaille directement avec E si c'est un objet range ou à la rigueur fais set P=E
      0
      1. j'ai donc supprimé la ligne

        Set P = Range("E")

        et je travaille directement avec E, c'est à dire que j'ai remplacé P par E partout (d'ailleurs je ne rends compte que dans les lignes de code il ne faut pas lire R mais P)

        le message d'erreur est alors le suivant : "constante requise" en me surlignant le second n dans :

        Dim M(n - 1, n - 1)
        0
        1. quand je sélectionne une ou plusieurs plages de cellules en argumant de ma fonction, est-ce qu'elle le comprend ? Mon argument est bien un objet de type Range ? parce que j'ai essayé un truc tout simple :

          Function Test(Z)

          Test = Z.Areas.Count

          End Function

          et çà marche pas ...
          0
          1. Bonjour,

            Quel erreur as tu ?
            0
          2. @ShaBoosoit il me renvoie 0 quand il devrait me sortir 1 et #valeur pour 2 ou plus
            0
        2. Bonjour,

          Dim M(n - 1, n - 1) ne marche pas, les dimensions doivent être constantes. Pour céer un tableau de dimensions variables il faut faire :
          Dim M()
          Redim M(n-1,n-1)

          Quand à savoir si l'argument passé est bien de type range... Il n'y a que toi qui peux le savoir, c'est toi qui sais comment tu appelles ta fonction ! Comment fais-tu pour l'appeler ?

          S'il te plaît quand tu dis "ça ne marche pas", précise : as-tu un message d'erreur,lequel, le résultat est-il faux ?...
          1
          1. mais si n est correctement défini avant, les dimensions sont constantes.

            Bien sur que je sais comment j'appelle ma fonction, ce que je voulais c'était m'assurer qu'une plage de données est bien un objet de type range et savoir comment l'utiliser après.
            0
          2. Bonjour,

            Je viens de tester l'utilisation d'une constante dans la definition de dimension d'un tableau et ça marche (idem pour 2 dimensions)

            Const cN = 10
            
            
            Sub test()
            
            Dim aTab(cN - 1, cN)
            
            Debug.Print UBound(aTab())
            
            End Sub
            


            (Je suis en Excel 2000)
            0
          3. @Nyck0lasA quel niveau est défini ton n ? Feuille, Module, ... ???
            0
          4. @Nyck0lasBonjour,

            Mais si n est correctement défini avant, les dimensions sont constantes.

            Dans ton exemple initial Dim M(n-1, n-1) n est une variable puisque tu définis n par Dim n as integer.
            Attention, en informatique, une variable dont on ne change jamais la valeur n'est pas la même chose qu'une constante.
            0
          5. @ShaBooBonjour,

            ça ne marche même QUE avec des constantes
            0
        3. je définis n comme constante mais je lui affecte une valeur avant de l'utiliser donc normalement çà ne devrait pas poser de problème ...

          j'ai modifié un peu mon code, voici la nouvelle version. A mon avis je crois qu'il y a un pb avec la plage de données en argument, son traitement ...

          Function Note(P)
          ' P correspond à une plage de cellules

          Dim n As Integer
          Dim an
          Dim A, Am
          Dim i As Integer, j As Integer
          Dim E As Range

          E = P.Select

          n = 0

          For i = 1 To E.Areas.Count
          n = n + E.Areas(i).Columns.Count
          Next i

          an = 2 * Pi / n

          'définition de ma matrice et de mon vecteur
          Dim M(n - 1, n - 1)
          Dim X(n - 1, 0)

          If cl = 1 Then
          For i = 0 To n - 1
          X(i - 1, 0) = E(i - 1, 0)
          Next i
          ElseIf lg = 1 Then
          For i = 0 To n - 1
          X(i - 1, 0) = E(0, i - 1)
          Next i
          End If

          For i = 0 To n - 1
          For j = 0 To n - 1
          M(i, j) = 0
          Next j
          Next i

          M(n - 1, 0) = 1
          For i = 0 To n - 2
          M(i, i + 1) = 1
          Next i

          'quelques petits calculs
          A = 1 / 2 * Sin(an) * Transpose(X) * M * X
          Am = 1 / 2 * Sin(an) * 100 ^ 2 * n
          Note = A / Am

          End Function
          0
          1. Quelques petites réflexions ... ;p

            Function Note(P)
            ' P correspond à une plage de cellules
            
            Dim n As Integer
            Dim an
            Dim A, Am
            Dim i As Integer, j As Integer
            Dim E As Range
            
            E = P.Select 'est ce bien utile ?
            
            n = 0
            
            'je ne vois pas pourquoi tu fais une boucle ici
            ' si P est une plage tu n'auras qu'un Area
            For i = 1 To E.Areas.Count
              n = n + E.Areas(i).Columns.Count
            Next i
            
            an = 2 * Pi / n
            
            'définition de ma matrice et de mon vecteur
            Dim M(n - 1, n - 1)
            Dim X(n - 1, 0) ' tu devrais le définir comme ceci : Dim X(n - 1)
            
            If cl = 1 Then  'comment est initialisé cl ?
              For i = 0 To n - 1
                X(i - 1, 0) = E(i - 1, 0)  
              Next i
            ElseIf lg = 1 Then 'comment est initialisé lg ?
              For i = 0 To n - 1
                X(i - 1, 0) = E(0, i - 1)
              Next i
            End If
            
            For i = 0 To n - 1
              For j = 0 To n - 1
                M(i, j) = 0
              Next j
            Next i
            
            M(n - 1, 0) = 1
            For i = 0 To n - 2
              M(i, i + 1) = 1
            Next i
            
            'quelques petits calculs
            A = 1 / 2 * Sin(an) * Transpose(X) * M * X
            Am = 1 / 2 * Sin(an) * 100 ^ 2 * n
            Note = A / Am
            
            End Function


            Sinon, quels sont les erreurs que tu as ??
            0
        4. en fait çà peut etre un ensemble de plages du type A1:C1;G1:J1 donc il peut y avoir plusieurs areas

          pour lg et cl, c'est une erreur de ma part, il faut remplacer le paragraphe par

          For i = 0 To n - 1
          X(i - 1, 0) = E(0, i - 1)
          Next i
          0
          1. en fait çà peut etre un ensemble de plages du type A1:C1;G1:J1 donc il peut y avoir plusieurs areas

            Peut etre ... mais un ensemble de plage fait une plage.

            Fais un :

            Debug.Print E.Areas.Count


            Pour t'en rendre compte
            0
          2. @ShaBooj'ai fait cette petite macro

            Sub Try()

            Dim z As Range

            Worksheets("Feuil1").Activate

            Set z = ActiveSheet.Range("B2:C2", "E2")

            Debug.Print z.Rows.Count

            End Sub

            et quand je la lance çà semble fonctionner mais rien ne s'affiche ...
            0
        5. Remplace :

          Debug.Print z.Rows.Count

          Par :

          MsgBox z.Rows.Count
          0
          1. hiihaaaaaaaaaaaaaa

            enfin quelque chose qui marche !!!!!!!!!!!

            il m'affiche bien 1 comme résultat donc tu as raison un ensemble de plage = 1 plage
            0
            1. lol
              0
            2. Tu aurais pu voir l'affichage de :

              Debug.Print z.Rows.Count


              Dans la fenetre "Execution" (si elle est affichée bien sur ;p) de ton editeur vba ...
              0
            3. @ShaBooj'ai pas trouvé ...
              0
            4. @Nyck0laslol ...

              quand tu es dans l'editeur vba, tu fais "CTRL+G"
              0
            5. @ShaBooçà marche !!
              0
          2. j'ai fait quelques tests de rows et columns.count
            et je me rends compte que lorsque je prends un ensemble de plage, il considère la plage qui recouvre tout.
            En gros si je choisis
            Range("B2:C3", "E5:F5")
            il comprend
            Range("B2:F5")
            0
            1. il faudrait une liste de range en argument dont la taille n'est pas définie
              0
              1. La "taille" d'un Range n'est définie que par ce que tu veux bien lui mettre dedans.
                0
              2. @ShaBoomais encore ....?????...????

                moi ce que je voudrais c'est que lorsque j'indique
                B2:C3;E5:F5
                il comprenne
                B2:C3 + E5:F5
                et non
                B2:F5
                et ce qu'il y ait 2 plages ou plus
                0
              3. @Nyck0lasIl faudrait voir les fonctions Union ou bien Intersect pour voir ce cela peut resoudre ton pb.

                Sinon tu fais 2 objets Range ...
                0
            2. je ne vois pas du tout comment faire pour avoir en argument d'une fonction un ensemble de plage.

              Dans la fonction SOMME par ex, je peux mettre en argument tout un ensemble de cellules contigues ou non et çà marche. Je voudrais faire la même chose ...
              0
              1. Tu met un bouton sur ta feuille, tu double-click dessus et tu arrives sur l'editeur vba.

                Private Sub CommandButton1_Click()
                
                Debug.Print flNomDeTaFonction(ActiveSheet.Range("B2:C2"),ActiveSheet.Range("E5:C5")
                  
                End Sub


                Dans un module tu mets ceci :

                Function flNomDeTaFonction(Dim oPlg1 As Range, Dim oPlg2 As Range) As Long
                
                Dim lRes As Long
                
                'ici tu mets ta petite bidouille de calcul avec oPlg1 et oPlg2 (noublie pas : ce sont des ranges)
                'avec lRes qui stocke le resultat
                
                
                fNomDeTaFonction = lRes
                End Function
                0
                1. ok c'est cool
                  mais comment je peux faire si je veux un nombre n de range, avec n non défini ?????????
                  that is the question ...
                  0
                  1. Ok ...

                    Ceci devrait te ravir :

                    Private Sub CommandButton1_Click()
                    
                    Debug.Print flNomDeTaFonction(Union(ActiveSheet.Range("B2:C3"), ActiveSheet.Range("E5:F5")))
                    
                    End Sub


                    Function flNomDeTaFonction(oPlg As Range) As Long
                    
                    Dim lRes As Long
                    
                    Debug.Print oPlg.Areas(1).AddressLocal
                    Debug.Print oPlg.Areas(2).AddressLocal
                    
                    'ici tu mets ta petite bidouille de calcul avec oPlg.Areas(1) et oPlg.Areas(2)  (noublie pas : ce sont des ranges)
                    'avec lRes qui stocke le resultat
                    
                    
                    flNomDeTaFonction = lRes
                    End Function
                    
                    0
                2. j'ai peut-etre trouvé une solution à mon pb avec :

                  Public Function Test(ParamArray Rng() As Variant) As Long
                  Dim I As Integer, CellCount As Integer

                  For I = 0 To UBound(Rng)
                  CellCount = CellCount + Rng(I).Cells.Count
                  Next

                  Test = CellCount
                  End Function

                  ce qui permet d'avoir un ensemble de plages en argument.
                  0
                  1. par contre j'ai un autre problème et oui ....

                    cette fois par rapport à du calcul matriciel.

                    J'ai défini
                    le vecteur X(n-1) et la matrice M(n-1,n-1)
                    et je voudrais calculer tX*M*X avec tX représentant "transposé de X".
                    J'ai marqué :
                    Transpose(X) * M * X
                    mais çà ne marche pas

                    çà indique
                    "erreur de compilation : sub ou function non définie" en surlignant la fonction "transpose" dans le code
                    0
                    1. j'ai fait quelques modifs dans le programme et voici le résultat :

                      Sub Notation()

                      Dim min As Integer, max As Integer
                      Dim PE(1), EE(0), SE(1)
                      Dim PA(0), EA(1), SA(1)
                      Dim i As Integer

                      Worksheets("Feuil1").Activate

                      min = 2
                      max = 9

                      EE(0) = "B"
                      PE(0) = "C"
                      PE(1) = "d"
                      SE(0) = "E"

                      SA(0) = "f"
                      EA(0) = "g"
                      PA(0) = "h"
                      EA(1) = "i"

                      SE(1) = "j"
                      SA(1) = "j"

                      For i = min To max
                      If Cells(i, "a") = "Eau" Then
                      Cells(i, "k").Value = Note(i, PE())
                      Cells(i, "l").Value = Note(i, EE())
                      Cells(i, "m").Value = Note(i, SE())
                      ElseIf Cells(i, "a") = "Ass" Then
                      Cells(i, "k").Value = Note(i, PA())
                      Cells(i, "l").Value = Note(i, EA())
                      Cells(i, "m").Value = Note(i, SA())
                      Next

                      End Sub
                      ______________________________________________________

                      Function Note(lg As Integer, ParamArray Rng() As Variant) As Long

                      Dim i As Integer, j As Integer, n As Integer
                      Dim alpha, pi
                      Dim A, Am

                      'calcul du nombre de cellules
                      n = UBound(Rng) + 1

                      'calcul de l'angle
                      pi = 4 * Atn(1)
                      alpha = 2 * pi / n

                      Debug.Print n

                      'définition de ma matrice M
                      Dim M()
                      ReDim M(n - 1, n - 1)

                      For i = 0 To n - 1
                      For j = 0 To n - 1
                      M(i, j) = 0
                      Next
                      Next

                      M(n - 1, 0) = 1

                      For i = 0 To n - 2
                      M(i, i + 1) = 1
                      Next

                      'definition du vecteur X
                      Dim X()
                      ReDim X(n - 1, 0)

                      For i = 0 To n - 1
                      X(i, 0) = ActiveSheet.Cells(lg, Rng(i).Value)
                      Next

                      'création de la tranposé de X
                      Dim TX()
                      Call Tvect(X, TX)

                      'quelques petits calculs
                      Dim p1(), p2()

                      Call PMAT(M(), X(), p1())
                      Call PMAT(TX(), p1(), p2())

                      A = 1 / 2 * Sin(alpha) * p2(0, 0)
                      Am = 1 / 2 * Sin(alpha) * 100 ^ 2 * n

                      Note = A / Am

                      End Function
                      __________________________________________________
                      Sub PMAT(A(), B(), C())

                      Dim i As Integer, j As Integer, k As Integer
                      Dim n As Integer, M As Integer, p As Integer

                      n = UBound(A, 2)
                      M = UBound(A, 1)
                      p = UBound(B, 2)

                      ReDim C(M, p)

                      For i = 0 To M
                      For j = 0 To p
                      For k = 0 To n
                      C(i, j) = C(i, j) + A(i, k) * B(k, j)
                      Next
                      Next
                      Next

                      End Sub
                      __________________________________
                      Sub Tvect(X(), TX())

                      Dim i As Integer, n As Integer

                      n = UBound(X, 1)

                      ReDim TX(0, n)

                      For i = 0 To n
                      TX(0, i) = X(i, 0)
                      Next

                      End Sub

                      Quand je le lance, le message d'erreur est le suivant :
                      "variable ou précédure attendue et non un module"
                      et la première occurence de "note" est surlignée dans la procédure notation

                      perso je ne vois pas trop où çà coince ....
                      0
                      1. Bonjour,

                        Essaye ceci :

                        Function Note(lg As Integer, Dim Rng() As Variant) As Long
                        0
                        1. non il ne veut pas du dim çà me donne

                          "erreur de compilation : attendu : identificateur"
                          0
                        2. pfff ... naouak (chui fatigué moi)
                          Function Note(lg As Integer, Rng() As Variant) As Long
                          0
                        3. @ShaBoodsl mais c'est pas mieux on est reparti sur l'erreur "variable ou procédure attendue et non un module"
                          0
                        4. @Nyck0lassur quelle ligne l'erreur ???
                          0
                        5. @ShaBootoujours pareil sur la première occurence de "note" est dans la procédure "notation"
                          0
                      2. ouais en fait j'avais appelé un module Note, d'où la confusion ..
                        0
                        1. çà compile !!!

                          mais je crois que le résultat est faux :-(
                          il doit y avoir un bug quelque part ....
                          0
                          1. Met des points d'arrêts (F9) et fais le tourner ligne par ligne en appuyant sur F8.

                            Dans la fenetre "Variables locales" tu verras le résultat de chacune de tes variables.
                            0
                        • 1
                        • 2