Aidez-moi !!! je trime sur un truc qui doit être super simple mais j'ai pas le d

Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 - 25 juin 2004 à 15:32
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005 - 29 juin 2004 à 16:27
Bonjour tout le monde,

Je cherche à créer une fonction qui a pour paramètre d'entrée le nom de la colonne Excel.

La colonne choisi par l'utilisateur subira ensuite un traitement qq.

Comment pourrai-je coder ceci.

public function toto (row as ?) ????

Merci d'avance.

:)

18 réponses

cs_ITALIA Messages postés 2169 Date d'inscription vendredi 20 avril 2001 Statut Membre Dernière intervention 30 juin 2009 9
25 juin 2004 à 15:38
A mon avis c plus une procedure qu'une Fonction

Public Sub TraitementExcel(ByVal MaColonne As integer)

End Sub

It@li@
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
25 juin 2004 à 15:43
Voila ce que j'ai écrit :

Public Sub lissage(ByVal Row As Integer)
Dim i As Integer
Dim Cellule As Range

Cellule.Row = Row
Cells(Cellule.Row, 1).Activate
While Not ActiveCells.Offset(Cellule.Row, 0).Value = ""
ActiveSheet.Cells(Row + 1, i) = (ActiveSheet.Cells(Row, i) + ActiveSheet.Cells(Row, i + 1)) / 2
i = i + 1
Wend
End Sub

En fait je fait une moyenne 2 à 2 des cellules de la colonne choisi par l'utilisateur. D'une part, je ne suis pas sûr de mon code et d'autre part, je ne sais pas quoi écrire dans Excel pour lancer cette fonction.

En conclusion je débute vraiment sur VB et je trime.

:)
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
25 juin 2004 à 16:29
effectivement il y a quelques petites erreurs :

tout d'abord, il faut initialiser i (après les dim par exemple)
i = 1 


Ensuite ta boucle est infinie :
ActiveCells.Offset(Cellule.Row, 0) ne change pas : si Cellule.Row vaut 1, alors ActiveCells.Offset(Cellule.Row, 0) sera toujours calé à A1. Il faut ajouter l'incrément :
while not ActiveCells.Offset(Cellule.Row, i)...

D'autre part, avec ce test de sortie, tu vas avoir un pb à la dernière itération : si la dernière valeur se trouve en A3, une fois arrivé à i=3 tu vas tester le contenu de ActiveCells.offset(cellule.row, 3), soit A3, qui va s'avérer non nul, donc tu vas calculer la moyenne entre A3 et A4, A4 etant nul -> ca n'a pas d'intérêt, donc je te conseillerais de tester :
while not ActiveCells.Offset(Cellule.Row, i+1).value=""

ou encore mieux :
while not ActiveCells.Offset(Cellule.Row, i+1).value="" and not ActiveCells.Offset(Cellule.Row, i).value=""

comme ca tu teste que les deux champs necessaires pour le calcul sont remplis

Enfin, si tu veux calculer les moyennes de A1 et A2, puis A2 et A3 (en supposant que tu aies choisi la colonne A) alors c'est bon. Mais si tu veux calculer la moyenne de A1 et A2, puis A3 et A4, dans ce cas la il faut remplacer i=i+1 par i=i+2

voila
Sinon un dernier petit truc (mais ca releve plus de l'esthetique qu'autre chose) : il faudrait uniformiser ta méthode d'accès aux cellules : dans le test de sortie de boucle tu utilises activecells.offset, et dans la boucle, tu passes par activesheet.cells. Ca ne pose pas de problème mais je pense que c'est plus compréhensible de tout faire de la même manière (soit l'un soit l'autre, je n'ai pas assez de conaissances pour dire quelle méthode et préférable). Mais je chipote ;-)
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 08:03
ok, merci beaucoup.

Mais ensuite, dans Excel, comment je fait l'appel de cette fonction. Je me place par exemple dans une cellule de la colonne C et j'y écrit =lissage(1) ????

La question peut sembler un peu débile mais c'est la première fois que je programme une fonction en VBA...

Merci d'avance à celui ou à celle qui me répondra.
:)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 08:25
Pour plus de précisions :

J'ai écrit ceci pour mon programme et à priori je pense que ça devrait marcher :

Option Explicit

Public Sub lissage(ByVal Row As Integer)
' Déclaration des variables
Dim i As Integer
Dim Cellule As Range
i = 1

Cellule.Row = Row
Cells(Cellule.Row, 1).Activate
While Not ActiveCells.Offset(Cellule.Row, i + 1).Value = "" And Not _
ActiveCells.Offset(Cellule.Row, i).Value = ""
ActiveSheet.Cells(Row + 1, i) = (ActiveSheet.Cells(Row, i) + ActiveSheet.Cells(Row, i + 1)) / 2
i = i + 2
Wend
End Sub

Mais comme je suis un débutant en VBA, je ne sais pas comment le tester. Je me suis placé au début de la colonne C, dans la première cellule et là, j'ai écrit : =lissage(2)
2 car je veux faire la moyenne sur la colonne B. Mais, losque j'écris ceci, dans la colonne C, en résultat, j'au un magnifique #Name?. HAAAAAAAAAA mon Dieu que faire ????

Si tu as une idée, n'hésite pas, car commencer comme ça un Lundi matin ça vous fait froid dans le dos... lol

@+ et bonne journée.

:)
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
28 juin 2004 à 09:01
Typiquement, une fonction en VBA s'appelle lors d'un evenement, par exemple clic sur un bouton. Il doit surement exister un moyen pour ajouter une fonction à la bibliothèque excel, mais je ne pense pas que ca passe par VBA.
Donc : effectivement ca ne marche pas comme ca. Le plus simple pour commencer, c'est de créer un bouton et de lancer ta procédure lorsque l'utilisateur va cliquer sur le bouton. Pour faire ca, c'est tout bete : après avoir crée le bouton, tu double clique dessus et ca t'écris la procédure qui gère l'évènement "clic sur le bouton" puis ca te positionne directement dedans. Et là tu peux faire appel à ta procedure lissage, par exemple lissage(1). Maintenant, si le clic sur un bouton ne te convient pas, il existe plein d'autres évènements (ouverture du document, ...), à toi de trouver celui qui te convient le mieux
Ensuite, si tu veux donner le choix à l'utilisateur de spécifier la colonne à traiter, tu peux commencer avec une boite de dialogue simple en appelant inputbox. Ca va t'ouvrir une boite de dialogue dans laquelle tu pourras donner la valeur de la colonne à traiter. Pour l'appel, tu écris quelque chose comme ca :

dim colonne as variant
colonne = inputbox("Colonne à traiter :")
lissage(colonne)

Note : j'ai mis colonne en variant car il me semble que inputbox renvoie une chaine de caractère, ce qui n'irait pas avec le paramètre de ta procédure. Plutot que de faire une conversion (et parce que je ne me souviens pas de la fonction qui fais ca !!!) je declare ma variable en variant, comme ca ca passe tout seul. Attention tout de même, avec cet exemple tu peux donner "A" comme valeur à colonne, et dans ce cas, l'appel à lissage(colonne) va effectuer le traitement sur la colonne qui a pour numéro le code ascii de la lettre "A". Donc ce code permet quelques dérives, à manipuler avec précaution.
Enfin, si une inputbox ne te suffit pas (c'est vrai que c'est moche) tu peux faire une fenêtre toi même, mais je te laisse découvrir

En esperant avoir répondu à tes questions
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 11:42
non ça marche :

Option Explicit
Option Base 1
Public Function Lissage(col As Range)
' Déclaration des variables
' cells (ligne,colonne)
Dim i As Double, j As Double, rt, nRow As Double
On Error GoTo errFound
i = 1
While col.Cells(i, 1) <> ""
i = i + 1
Wend
nRow = i - 1
ReDim rt(1 To nRow, 1)
For i = 1 To nRow - 1
rt(i, 1) = (col(i, 1) + col(i + 1, 1)) / 2
Next
rt(nRow, 1) = col(nRow, 1)
Lissage = rt
Exit Function
errFound:
Lissage = Err.Description
End Function

c'est la fontion que j'ai faite.
Ensuite pour l'utiliser, tu créés une colonne A avec 10 chiffres par exemple, ensuite dans la colonne B tu vas sélectionner 10 cases, dans la partie fx tu écris lissage(la sélection des 10 chiffres de la colonne A) puis tu cliques à la fois sur Ctrl Shift Entrée et là tu as ta moyenne. En fait je raisonne en terme de vecteur verticaux.

:)
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 13:08
Par contre, j'ai testé ce prog avec des nombres négatifs, et là, ça ne marche plus, si qq'un voit pourquoi, je suis prenneur.

:)
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
28 juin 2004 à 13:42
Ok avec une fonction ca marche (c'est toujours bon à savoir ;-)
j'ai essayé ta fonction (sous open office, linux oblige) et je suis pas sur qu'elle soit vraiment adaptée : je sais pas ce que fais ctrl+shift+entrée sous excel mais si c'est comme sous OOo (c'est à dire que ca copie la formule que tu à écrit dans toutes les cases sélectionnées), alors tu perds beaucoup de temps : chaque fois que tu appelle ta fonction, tu fais les calculs pour toute ta colonne A. Donc en appelant 10 fois ta fonction, tu calcule 10 fois tes moyennes -> 100 calculs contre 10, c'est pas top optimisé
Donc si tu veux l'utiliser comme ca, autant la mettre dans une seule case puis l'executer, ca fera pareil
Ensuite je ne sais pas si l'objet range est adapté : si tu ne selectionnes pas toutes les valeurs à traiter plus au moins une case vide, je ne sais pas si tu vas pas sortir en erreur : la boucle a une seule condition d'arrêt : trouver une case vide. Si ton objet range n'ene a pas, alors arrivé à la dernière valeur, je pense que tu vas faire un dépassement d'index sur ton objet range -> plantage (à ce propos, c'est bien d'avoir ajouté une gestion d'erreur). Pour ma part, je choisirais plutot comme paramètre un numéro de colonne (ou alors recupérer le numéro de colonne de ton objet range), comme proposé dans les premières solutions de l'algo, comme ca tu n'as pas à tout selectionner, ca limite les risques d'erreur
voila
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
28 juin 2004 à 14:03
Qu'est ce qui plante avec les negatifs ?

EDIT msg prec : autant pour moi pour le dépassement d'index, j'ai mal compris l'accès par col.cells. Ceci dit, la remarque reste valable, surtout si il y a beaucoup de nombres à traiter (c'est un peu lourd de tout selectionner)
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 14:04
ok, je vois ce que tu veux dire mais je ne sais pas le coder. Tu peux m'aider s'il te plait ? Je viens de remarqué aussi que ma fonction de marchée correctement que pour la colonne que je lui ait défini, pour une autre colonne c'est rapé, as-tu une idée pour remédier à ce genre de limitation, surtout que dans la feuille Excel que je dois traiter, il y a du texte au début de chaque colonne et puis des blancs, donc effectivement ça plante et j'ai un magnifique out of range comme message.

merci d'avance.
:)
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 14:05
ok, je vois ce que tu veux dire mais je ne sais pas le coder. Tu peux m'aider s'il te plait ? Je viens de remarqué aussi que ma fonction ne marchée correctement que pour la colonne que je lui ait défini, pour une autre colonne c'est rapé, as-tu une idée pour remédier à ce genre de limitation, surtout que dans la feuille Excel que je dois traiter, il y a du texte au début de chaque colonne et puis des blancs, donc effectivement ça plante et j'ai un magnifique out of range comme message.

merci d'avance.
:)
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
28 juin 2004 à 14:05
ok, je vois ce que tu veux dire mais je ne sais pas le coder. Tu peux m'aider s'il te plait ? Je viens de remarqué aussi que ma fonction ne marchée correctement que pour la colonne que je lui ait défini, pour une autre colonne c'est rapé, as-tu une idée pour remédier à ce genre de limitation, surtout que dans la feuille Excel que je dois traiter, il y a du texte au début de chaque colonne et puis des blancs, donc effectivement ça plante et j'ai un magnifique out of range comme message.

merci d'avance.
:)
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
28 juin 2004 à 14:34
Ok voila mon idée : je repars sur un paramètre de type entier
Public Function Lissage(col As integer)

' Déclaration des variables
' cells (ligne,colonne)
Dim i As Double, j As Double, rt, nRow As Double
On Error GoTo errFound

'si comme tu dis tu as du texte au début des colonnes, deux possibilité : soit tu peux
'toujours dire le nombre de lignes inutiles avant les données (mieux c'est toujours la
'même) dans ce cas tu modifies la valeur d'init de i, et sinon tu codes une deuxième
'boucle pour te positionner sur la première valeur
i = 1
'il suffit d'indiquer le numéro de colonne plutot que 1 pour le 2e paramètre
While Cells(i, col) <> ""
i = i + 1
Wend

'le reste est bon, j'ai juste enlevé des param pour la manipulation de rt (pour plus de
'simplicité)
nRow = i - 1
ReDim rt(1 To nRow)
For i = 1 To nRow - 1
rt(i) = (cells(i, col) + cells(i + 1, col)) / 2
Next
rt(nRow) =  cells(nRow, col)
Lissage = rt
Exit Function
errFound:
Lissage = Err.Description
End Function


Je crois que c'est bon. Je reste ici si tu as besoin de plus
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
29 juin 2004 à 13:28
Concernant le lissage sur 2 points, j'ai écrit finalement le programme comme suit :

Option Explicit
Option Base 1
Public Function Lissage2p(col As Range)
' Déclaration des variables
' cells (ligne,colonne)
Dim i As Double, j As Double, rt, nRow As Double
On Error GoTo errFound
i = 1
While (col.Cells(i, 1) <> "") And (i <= col.Count - 1)
i = i + 1
Wend
nRow = i - 1
nRow = col.Count
ReDim rt(1 To nRow, 1)
For i = 1 To nRow - 1
rt(i, 1) = (col(i, 1) + col(i + 1, 1)) / 2
Next
rt(nRow, 1) = col(nRow, 1)
Lissage2p = rt
Exit Function
errFound:
Lissage2p = Err.Description
End Function

Je l'ai bien testé et il fonctionne correctement quelle que soit la lourdeur des calculs qui sont à réaliser.

Par contre, maintenant, j'aimerai faire la même chose mais pour un lissage sur 3 points puis sur 5 points.

Voici ce que j'ai écrit pour le lissage 3 points :

Option Explicit
Option Base 1
Public Function Lissage3p(col As Range)
' Déclaration des variables
' cells (ligne,colonne)
Dim i As Double, j As Double, rt, nRow As Double
On Error GoTo errFound
i = 1
While (col.Cells(i, 1) <> "") And (i <= col.Count - 1)
i = i + 1
Wend
nRow = i - 1
nRow = col.Count
ReDim rt(1 To nRow, 1)
For i = 1 To nRow - 1
rt(i, 1) = (col(i, 1) + col(i + 1, 1) + col(i + 2, 1)) / 3
Next
rt(nRow, 1) = col(nRow, 1)
Lissage3p = rt
Exit Function
errFound:
Lissage3p = Err.Description
End Function

Mais lorsque j'appelle cette fonction, il s'inscrit dans les cases le message suivant : Type mismatch.

Si qulqu'un a une idée ????? Je suis prenneur.

Merci d'avance
:)
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
29 juin 2004 à 14:42
J'ai une petite question : le but de l'algo, c'est de retourner un tableau qui contient les valeurs ou bien de remplir des cases excel avec ces valeurs ?

Pour ton problème je ne vois pas immediatement, j'essaierais ca ce soir chez moi (avec excel et pas OOo) : essaye d'executer en pas à pas et avec des espions là ou ca ne marche pas... j'ai pas plus de précision pour le moment

Sinon j'ai relevé des petites fautes :
l 6 : je ne sais plus à quoi correspond le type double en VB (je me calque sur le C), mais si il s'agit d'un type decimal, alors il vaut mieux déclarer i et j en integer ou en long. Si c'est pas ca alors autant pour moi. En passant, j n'est pas utilisée...

l 9 : While (col.Cells(i, 1) <> "") And (i <= col.Count - 1)
-> pourquoi s'arrêter à Count-1 ? si ta sélection comprend toutes tes valeurs + une case vide, dans ce cas là c'est la première condition qui te fait sortir (<>""), et si la selection ne contient pas de case vide, il faut aller jusqu'au bout, soit col.Count. Si tu ne vas que jusqu'a col.count-1, tu rates une valeur. Bon en l'occurrence ca n'a pas trop d'importance puisque tu affecte à nRow la valeur col.Count (mais ca pose un autre problème, cf en dessous)
De plus, avec ta solution tu ne sais pas si tu finis ta boucle parce que tu as detecté une case vide ou parce que tu as atteint la fin de ton objet range -> ca pose un problème pour donner la valeur de nRow (a ce sujet voir l'erreur suivante l12-13): si tu arrive en fin de range, yapa de problème puisque nRow va prendre la valeur col.Count. Mais si tu as une selection qui comprend plusieurs cases vides à la fin, alors la première boucle n'aura servi à rien, puisque tu vas initialiser nRow à col.Count, donc avec les cases vides... Donc j'en reviens à ma remarque du msg précédent : il vaut mieux travailler avec la colonne (par exemple avec un paramètre integer) qu'avec un objet range, puisqu'avec la colonne, tu es sur d'arriver à un moment ou à un autre sur une case vide

l 12-13 :
nRow = i - 1
nRow = col.Count
ca sert à rien d'affecter deux fois nRow, faut choisir à un moment. Pour choisir, avec ta solution faudrait ajouter un test pour savoir la raison qui t'a fait sortir de la première boucle...

l 14 : pas vraiment une erreur, mais tu peux ecrire simplement ReDim rt(1 To nRow). Si tu n'as besoin que d'un tableau à 1 dimension (un tableau à deux dimension serait une matrice en gros), le deuxième paramètre (ainsi que les suivants) sont mis par défauts à 1, ca fait moins à écrire. Même remarque pour l'accès à rt, ligne 18 : rt(nRow) suffit.

l 15 : pour un lissage à 3 points et avec ta méthode, il faudra t'arrêter trois cases avant la dernière case (cad laisser deux cases vides) : For i = 1 To nRow - 2
même remarque pour n points

Ensuite pour le lissage à n points : deux solution me viennent à l'esprit : soit comme tu le fais maintenant (une fonction pour chaque lissage) soit ajouter un deuxième paramètre qui indique le nombre de valeurs à prendre en compte. Ensuite dans la deuxième boucle tu fais une nouvelle boucle qui fait la somme des valeurs à prendre en compte (en utilisant le deuxième paramètre pour l'arrêter), puis tu la divise par le deuxième paramètre. Comme ca une seule fonction suffit pour faire des lissage à nimporte quel nombre de points.
0
Adoc5 Messages postés 53 Date d'inscription lundi 3 mai 2004 Statut Membre Dernière intervention 1 octobre 2007 1
29 juin 2004 à 14:55
Merci pour tes remarques, elles vont me permettre de progresser en programmation VBA.

Le but du programme est bien de remplir des cases excel avec les valeurs du lissage dans le but ensuite de tracer la courbe de mesure pui d'appliquer sur le graphe un gabarit. Relever les valeurs qui sortent du gabarit (j'espère qu'il n'y en aura pas) !!! Puis, envoyer les graphes dans Word dans le but de générer un rapport complet de mesures + conclusions pour voir si des pièces RF ont été correctement créées en prod.

Je prends en considération des remarques et vais essayer de le mettre en application.

j'ai posté sur le forum un nouveau message qui est un petit casse-tête que j'ai besoin de résoudre pour générer mon rapport de mesures.
Je t'expose le problème :

J'ai 2 colonnes excel : dans la première il y a les ordonnées puis dans l'autre les abscisses. Mon problème est le suivant : j'aimerai créer un fonction qui me trie la colonne des abscisses pour avoir les chiffres dans l'ordre croissant mais je ne veux pas perdre ma correspondance avec les valeurs des ordonnées. Pour le moment, je ne vois pas comment coder cela... Si jamais tu as une idée, elle sera la bienvenue.

en te remerciant par avance.

Adoc5
0
Mooiz Messages postés 128 Date d'inscription mercredi 25 juin 2003 Statut Membre Dernière intervention 8 juillet 2005
29 juin 2004 à 16:27
Alors la tu as de la chance c'est super simple: excel te fait tout. Il suffit d'appeler la fonction sort sur un objet range : par exemple pour trier 15 coordonnées qui sont disposées sur les colonnes A et B, avec A1 et B1 reservés pour les noms des coordonnées, c'est :

Range("A2:B16").Select
Selection.Sort Key1:=Range("A1"), Order1:=xlDescending, Header:=xlGuess, OrderCustom:=1, Orientation:=xlTopToBottom

explication : on applique la méthode sort sur les cases A2 à B16 (pour ne pas inclure A1 et B1 dans le tri)
Le premier paramètre sert à donner la colonne selon laquelle tu vas faire le tri
le 2e pour indiquer le sens dans lequel trier
le 3e pour dire s'il y a une "légende" (par exemple dans notre cas en A1 et B1, on met le titre des colonnes). Pour ce cas, comme on n'a pas selectionné les cases A1 et B1, on pourrait mettre xlNo. Si on les avait selectionnés, il aurait fallu mettre xlYes, ou bien xlGuess (qui devine si il y a une légende)
le 4e, ordercustom, j'ai pas bien compris à quoi ca servait, mais je pense que c'est pas très utile ;-)
le 5e, Orientation, c'est pour dire si on veut trier par ligne ou par colonne. Ici la valeur est xlTopToBottom, mais on peut également mettre xlSortRows qui est équivalent

voila. Pour plus de précision, faudrait consulter l'aide mais je pense que tu as déjà pas mal d'éléments. Si tu veux faire un tri selon les abscisses puis selon les ordonnées (ou le contraire), va voir dans l'aide, la méthode est décrite

PS : je pense que je vais continuer en messages privés, ca sera plus simple. Je vais essayer d'améliorer un peu ton algo...
0
Rejoignez-nous