Condition et boucle VBA Excel
Bonjour à tous,
Ayant très peu de connaissances en VBA, mais ayant quelques notions en language web (C, JS, PHP...), je me permet de vous demander de l'aide pour un projet à faire en VBA.
Voici mes besoins par rapport au fichiers en pj :
- Si le chiffre en i1 est négatif, alors parcours la colonne G et cherche la valeur la plus haute avec comme exception le code 57-55-6 appartenant à la colonne C
- Remplacer la valeur se trouvant dans la colonne E par la valeur de la même ligne de la colonne F, jusqu'à ce que la case i1 devienne positive
-Si G est different de 0 alors tu me remplace le code matière équivalent se trouvant sur un fichier .xls de mon serveur.
Je me doute qu'il faut utiliser des If et des foreach mais je bloque sur les syntaxes et les indentations.
Voici une idée de l'algo pour le début (mais pas en vba)
// Je pars du principe que colonneG est un tableau d'int
int i;
int nbPlusGrand;
i = 0;
if (caseI1 < 0)
{
c = countNbCase(colonneG);
nbPlusGrand = colonneG[i];
while (i < c - 1)
{
if (colonneG[i] >colonneG[i +1])
{
nbPlusGrand = colonneG[i];
}
i = i + 1;
}
}Merci beaucoup pour votre aide.
Bonjour,
Voici une traduction de ton code en VBA :
sub valmax()
if (range("I1")< 0) then
der_lig = range("g" & rows.count).end(xlup).row
maxi = range("g2")
for i = 3 to der_lig
if (range("g" & i) > maxi) then
maxi= range("g" & i)
end if
next i
end if
end subMerci beaucoup pour ton aide et ta réactivité.
Aurais tu une piste pour la suite de ma problématique?
P.S : je n'ai jamais vu quelqu'un porter aussi bien son pseudo ^^
Rebonjour,
De rien
J'ai bien ceci qui pourrait y répondre :
En revanche pour l'implémentation du code sur le serveur je ne saurais pas trop dire...
Malheureusement excel me met bcp de msg d'erreur à l'ouverture de ton fichier. Surement du à la différence de version de nos pack office.
j'ai ce msg qui m'indique que cela a été supprimé :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><logFileName>Réparer le résultat vers Copie de exemple_developpez1.xml</logFileName><summary>Des erreurs ont été détectées dans le fichier « /Users/anthony/Downloads/Copie de exemple_developpez.xlsm »</summary><removedParts summary="Liste des parties supprimées ci-dessous :"><removedPart>Partie supprimée: /xl/vbaProject.bin partie. (Visual Basic pour Applications (VBA))</removedPart></removedParts></recoveryLog>et du coup je n'ai pas accès à tes modifs, ni au code VBA
Encore un gros merci pour le tps que tu prend pour mon problème.
Rebonjour,
Ah mince, je te donne le code du coup:
Sub valmax()
If (Range("I1") < 0) Then
der_lig = Range("g" & Rows.Count).End(xlUp).Row
maxi = Range("g2")
lig_maxi = 2
For i = 3 To der_lig
If (Range("g" & i) > maxi) And Range("c" & i) <> "57-55-6" Then
maxi = Range("g" & i)
lig_maxi = i
End If
Next i
Range("g" & lig_maxi) = Range("f" & lig_maxi)
If Range("g" & lig_maxi) <> 0 Then
MsgBox ("remplacer par code matière.")
End If
End If
End SubJ'ai testé et ça semble marcher
Au top, merci bcp.
tu es un monstre!!
Effectivement cela fonctionne mais je viens de voir que j'ai oublié de préciser (les joies de l'écrit par rapport à l'oral) qu'il fallait qu'il me modifie les valeurs les plus hautes jusqu'a que la cellule i1 soit positive, je vient de modifier le post de départ afin d'être le plus explicit possible.
je viens de modifier le code pour avoir les modifcations pour que la valeur de F soit identique à E (au lieu que la valeur de G soit identique à F) du à ma mauvaise explications. Je suis en train de faire différent test afin de voir si la boucle continu tant que i1 n'est pas positive.
et je vais regarder pour modifier le code matière si G est différent de 0, car mon fichier excel (se trouvant sur mon serveur ) on retrouve le code matière (se trouvant dans la colonne A dans le fichier serveur et colonne C dans l'exemple donné) et si différent de 0 il doit le remplacer par celui du fichier serveur se trouvant colonne D.
Encore un sacré chantier
Mais encore un énorme merci
En effet je n'avais pas tout compris
Si le but c'est de continuer jusqu'à ce que I soit supérieur ou égal à 0, alors il faut écrire le code comme ceci:
Sub valmax()
cpt_err = 0
While (Range("I1") < 0)
cpt_err = cpt_err + 1
der_lig = Range("g" & Rows.Count).End(xlUp).Row
maxi = Range("g2")
lig_maxi = 2
For i = 3 To der_lig
If (Range("g" & i) > maxi) And Range("c" & i) <> "57-55-6" Then
maxi = Range("g" & i)
lig_maxi = i
End If
Next i
Range("f" & lig_maxi) = Range("e" & lig_maxi)
If Range("g" & lig_maxi) <> 0 Then
MsgBox ("remplacer par code matière.")
End If
If cpt_err = 1000 and Range("I1") < 0 Then
If MsgBox("La boucle a dépassé les 1000 itérations, nous craignions que vous ne soyez dans une boucle infinie; voulez-vous en faire 1000 de plus?", vbYesNo) = vbNo Then
MsgBox ("Le programme a été interrompu.")
Exit Sub
Else
cpt_err = 0
End If
End If
Wend
End SubComme j'avais peur que tu ne puisses tomber dans une boucle infinie, je déclare une variable cpt_err que j'initialise à 0, je l'incrémente à chaque fois qu'on reboucle, si au bout de 1000 changements tu n'as toujours pas une valeur supérieure à 0, alors je demande si tu veux continuer le programme, si tu mets oui, ça fait 1000 boucles en plus et s'arrête de nouveau pour te demander si besoin, si tu mets non, ça quitte le programme en t'affichant un message
j'avance un peu pour récupérer les informations d'un fichier excel externe, j'ai rajouté ce bout de code dans la conditions à la place du msg box :
Sub valmax()
cpt_err = 0
While (Range("I1") < 0)
cpt_err = cpt_err + 1
der_lig = Range("g" & Rows.Count).End(xlUp).Row
maxi = Range("g2")
lig_maxi = 2
For i = 3 To der_lig
If (Range("g" & i) > maxi) And Range("c" & i) <> "57-55-6" Then
maxi = Range("g" & i)
lig_maxi = i
End If
Next i
Range("f" & lig_maxi) = Range("e" & lig_maxi)
If Range("g" & lig_maxi) <> 0 Then
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim titre As String
Dim wbk1 As Workbook
Dim wbk2 As Workbook
titre = " /Users/anthony/Desktop/test.xlsx"
Set wbk1 = ThisWorkbook
Set wbk2 = Workbooks.Open(titre) ' jouvre le classeur (titre)
wk1.Sheets(1).Range("D").Value = wbk2.Sheets(2).Range("C").Value
wbk2.Close
MsgBox ("remplacer par code matière.")
End If
If cpt_err = 1000 And Range("I1") < 0 Then
If MsgBox("La boucle a dépassé les 1000 itérations, nous craignions que vous ne soyez dans une boucle infinie; voulez-vous en faire 1000 de plus?", vbYesNo) = vbNo Then
MsgBox ("Le programme a été interrompu.")
Exit Sub
Else
cpt_err = 0
End If
End If
Wend
End SubMais celui ne fonctionne pas, ce qui est normal je pense car je lui indique une colonne entière, et je ne comprend pas comment faire pour lui indiquer via le code matiere celui à changer.
merci pour votre aide
En effet tu lui donnes une colonne entière... il faudrait que tu trouves ton code via un range.find peut-être... comme ça tu sais dans quelle ligne aller chercher le code, et donc après tu peux le ramener par formule, tu as déjà la lig_max pour savoir sur quelle ligne écrire, reste à voie celle d'où tu importes
J'ai trouvé ce code :
Sub FindAddress()
'Defining the variables.
Dim GCell As Range
Dim Page$, Txt$, MyPath$, MyWB$, MySheet$
'The text for which to search.
Txt = "121-5_30KJ"
'The path to the workbook in which to search.
MyPath = "/Users/anthony/Desktop/"
'The name of the workbook in which to search.
MyWB = "test.xlsx"
'fichier excel de mon serveur'
'Use the current sheet as the place to store the data for which to search.
MySheet = ActiveSheet.Name
'If an error occurs, use the error handling routine at the end of this file.
On Error GoTo ErrorHandler
'Turn off screen updating, and then open the target workbook.
Application.ScreenUpdating = False
Workbooks.Open test:=MyPath &; MyWB
'Search for the specified text
Set GCell = ActiveSheet.Cells.Find(Txt)
'Close the data workbook, without saving any changes, and turn screen updating back on.
ActiveWorkbook.Close savechanges:=False
Application.ScreenUpdating = True
Exit Sub
'Error Handling section.
ErrorHandler:
Select Case Err.Number
'Common error #1: file path or workbook name is wrong.
Case 1004
Range("D10:E11").ClearContents
Application.ScreenUpdating = True
MsgBox "The workbook " &; MyWB &; " could not be found in the path" &; vbCrLf &; MyPath &; "."
Exit Sub
'Common error #2: the specified text wasn't in the target workbook.
Case 9, 91
ThisWorkbook.Sheets(MySheet).Range("D10:E11").ClearContents
Workbooks(MyWB).Close False
Application.ScreenUpdating = True
MsgBox "The value " &; Txt &; " was not found."
Exit Sub
'General case: turn screenupdating back on, and exit.
Case Else
Application.ScreenUpdating = True
Exit Sub
End Select
End SubProvenant de la doc range.find de microsoft mais je ne le comprend vraiment pas(j'ai attaqué le VBA par nécessité hier), pour moi il devrait aller me chercher "121-5_30KJ" et me le mettre sur D10, si j'ai juste mais j'ai une erreur de compilation.
Bonsoir,
Je ne pense pas que tu ais besoin de tout ça, en fait pour t'expliquer la fonction find...
Tu lui donnes une plage de cellules dans laquelle chercher l'information Range(plagedecellules) et à ça tu rajoutes ton .find et tu mets dedans au minimum l'information que tu cherches. Ensuite si il la trouve, il te renvoie la cellule où il l'a trouvé, tu récupères un range, dont tu peux prendre la colonne, la ligne, la valeur, le fond... Tu peux accéder à toutes ses propriétés (désolé si j'utilise un vocabulaire peut-être encore étrange pour toi).
Si je reprends ton code...
Sub valmax()
cpt_err = 0
While (Range("I1") < 0)
cpt_err = cpt_err + 1
der_lig = Range("g" & Rows.Count).End(xlUp).Row
maxi = Range("g2")
lig_maxi = 2
For i = 3 To der_lig
If (Range("g" & i) > maxi) And Range("c" & i) <> "57-55-6" Then
maxi = Range("g" & i)
lig_maxi = i
End If
Next i
Range("f" & lig_maxi) = Range("e" & lig_maxi)
If Range("g" & lig_maxi) <> 0 Then
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim titre As String
Dim wbk1 As Workbook
Dim wbk2 As Workbook
titre = " /Users/anthony/Desktop/test.xlsx"
Set wbk1 = ThisWorkbook
Set wbk2 = Workbooks.Open(titre) ' jouvre le classeur (titre)
wk1.Sheets(1).Range("D").Value = wbk2.Sheets(2).Range("C").Value
wbk2.Close
MsgBox ("remplacer par code matière.")
End If
If cpt_err = 1000 And Range("I1") < 0 Then
If MsgBox("La boucle a dépassé les 1000 itérations, nous craignions que vous ne soyez dans une boucle infinie; voulez-vous en faire 1000 de plus?", vbYesNo) = vbNo Then
MsgBox ("Le programme a été interrompu.")
Exit Sub
Else
cpt_err = 0
End If
End If
Wend
End SubLa seule partie qui bloque de ce que je comprends, c'est ça :
wk1.Sheets(1).Range("D").Value = wbk2.Sheets(2).Range("C").ValueEn clair tu vas faire :
wk1.Sheets(1).Range("D" & lig_maxi) = wbk2.Sheets(2).Range("C" & wbk2.Sheets(2).Range().find().row)En revanche je ne sais pas dans quelle colonne tu dois chercher le code qui fait le lien entre tes deux fichiers, mais tu dois chercher par exemple sur la colonne D la valeur "exemple", ça donnerait :
wk1.Sheets(1).Range("D" & lig_maxi) = wbk2.Sheets(2).Range("C" & wbk2.Sheets(2).Range("d:d").find("exemple").row)si ça te fait trop de code sur la même ligne, tu peux faire ça en 2 lignes :
lig_import = wbk2.Sheets(2).Range("d:d").find("exemple").row
wk1.Sheets(1).Range("D" & lig_maxi) = wbk2.Sheets(2).Range("C" & lig_import)Merci beaucoup pour tes explications, je commence à y voir un peu plus clair.
Donc voici le bout de code que j'ai rajouté dans ma condition
If Range("g" & lig_maxi) <> 0 ThenDim titre As String
Dim wbk1 As Workbook
Dim wbk2 As Workbook
titre = " Users/anthony/Desktop/test.xlsx"
Set wbk1 = ThisWorkbook
Set wbk2 = Workbooks.Open(titre)
wk1.Sheets(1).Range("D" & lig_maxi) = wbk2.Sheets(2).Range("C" & wbk2.Sheets(2).Range("d:d").Find("121-33-5_30PG").Row)
wbk2.CloseOn dirait qu'il ne rentre pas dans la condition car le msgbox ne s'ouvre pas ou qu'il ne trouve pas mon fichier test.xlsx.
Bonjour,
Pour vérifier si il ouvre ton fichier, si il va dans la boucle... tu dois utiliser le mode pas à pas de la barre d'outils déboguage, tu fais clic droit dans la barre d'outils de Visual Basic puis tu cliques sur déboguage, il faut ensuite utiliser la commande pas à pas détaillé, un point d'arrêt... Je te laisse regarder sur internet comment utiliser le déboguage
Je pense que le problème vient en effet de l'ouverture de ton fichier car tu as un soucis dans le chemin...
titre = " Users/anthony/Desktop/test.xlsx"
Tu lui dis de partir de Users mais tu ne précises pas de lecteur, ça pourrait être la source du problème, comme j'ai dû mettre un On error resume next, ça doit contourner le soucis, le mieux serait de mettre ceci avant ton code qui semble poser soucis :
On error goto 0
Ce qui est assez bizarre c'est que quand je met ce code :
Range("g" & lig_maxi) = Range("f" & lig_maxi)
If Range("g" & lig_maxi) <> 0 Then
MsgBox ("remplacer par code matière.")
End Ifje rentre dans ma condition, et si je remplace les colonne g et f :
Range("f" & lig_maxi) = Range("e" & lig_maxi)
If Range("g" & lig_maxi) <> 0 Then
MsgBox ("remplacer par code matière.")
End Ifje ne rentre plus dedans
C'est normal,
Comme g est égal à 0, tu ne rentres pas dans la condition, comme avant tu mettais la valeur de f dans g, g n'était pas égal à zéro, essaye de mettre 1 dans la colonne g de la ligne que tu veux tester et tu verras
oui mais je veux lui dire comme condition :
If Range("g" & lig_maxi).Value > 0 Then
MsgBox ("remplacer par code matière.")
End IfDonc la si la valeur dans les cellules de la colonne G sont supérieur (on aurait pu mettre <> de 0) tu m'affiche la box, ca devrait marcher?
J'ai besoin d'identifier les lignes différentes afin de changer le code matière, alors soit via la colonne G soit avec la différence entre la colonne E et la colonne F.
J'ai inclus la condition dans la boucle mais boucle infini:
Sub valmax()
cpt_err = 0
While (Range("I1") < 0)
cpt_err = cpt_err + 1
der_lig = Range("g" & Rows.Count).End(xlUp).Row
maxi = Range("g2")
lig_maxi = 2
For i = 3 To der_lig
If (Range("g" & i) > maxi) And Range("c" & i) <> "57-55-6" Then
maxi = Range("g" & i)
lig_maxi = i
End If
If Range("g" & lig_maxi).Value > 0 Then
Dim titre As String
Dim wbk1 As Workbook
Dim wbk2 As Workbook
titre = "/Users/anthony/Desktop/test.xlsx"
Set wbk1 = ThisWorkbook
Set wbk2 = Workbooks.Open(titre)
wk1.Sheets(1).Range("c" & lig_maxi) = wbk2.Sheets(2).Range("a" & wbk2.Sheets(2).Range("d:d").Find("121-33-5_30PG").Row)
wbk2.Close
MsgBox ("remplacer par code matière.")
End If
Next i
Range("f" & lig_maxi) = Range("e" & lig_maxi)
If cpt_err = 1000 And Range("I1") < 0 Then
If MsgBox("La boucle a dépassé les 1000 itérations, nous craignions que vous ne soyez dans une boucle infinie; voulez-vous en faire 1000 de plus?", vbYesNo) = vbNo Then
MsgBox ("Le programme a été interrompu.")
Exit Sub
Else
cpt_err = 0
End If
End If
Wend
End SubPar contre msg d'erreur : Erreur d'execution <<9>> l'indice est en dehors des dimensions du tableau.
Donc si je récapitule, pour être sur de bien comprendre :
- wbk1 correspond à mon fichier exemple
- wbk2 correspond à mon fichier test
cette ligne de code(d'ou vient mon problème visiblement)
wk1.Sheets(1).Range("c" & lig_maxi) = wbk2.Sheets(2).Range("a" & wbk2.Sheets(2).Range("d:d").Find("121-33-5_30PG").Row)veut dire que dans mon fichier exemple les lignes de la colonne C qui rentre dans ma condition sont égales à celles de la colonne A du fichier test. Alors dans la colonne d (du fichier test) tu cherche la ligne ou tu trouvera "121-33-5_30PG" et tu remplace la valeur de la case correspondante dans la colonne c du fichier exemple.
Merci pour votre aide
Désolé j'ai un peu du mal avec le code, comme en général je fonctionne en déboguage...
Je reprends ton code avec ce que je trouve bizarre :
Sub valmax()
'on va initialiser toutes les variables ici plutôt qu'en milieu de programme pour commencer
cpt_err = 0
Dim titre As String
Dim sh1 As worksheet 'j'ai remplacé workbook 1 par sheet 1 du workbook actuel
Dim wbk2 As Workbook
titre = "/Users/anthony/Desktop/test.xlsx"
Set sh1 = thisworkbook.Sheets(1)
Set wbk2 = Workbooks.Open(titre)
'J'ai préféré préciser à chaque fois le classeur dans lequel on va chercher les données
While (sh1.Range("I1") < 0)
cpt_err = cpt_err + 1
der_lig = sh1.Range("g" & Rows.Count).End(xlUp).Row
maxi = sh1.Range("g2")
lig_maxi = 2
For i = 3 To der_lig
If (sh1.Range("g" & i) > maxi) And sh1.Range("c" & i) <> "57-55-6" Then
maxi = sh1.Range("g" & i)
lig_maxi = i
End If
Next i
sh1.Range("f" & lig_maxi) = sh1.Range("e" & lig_maxi)
'J'ai enlevé la condition de la boucle, on a besoin de traiter la cellule maximale qu'une fois qu'on a parcouru toutes les cellules pour être sûr que c'est bien la cellule maxi
If sh1.Range("g" & lig_maxi).Value > 0 Then
sh1.Range("c" & lig_maxi) = wbk2.Sheets(2).Range("a" & wbk2.Sheets(2).Range("d:d").Find("121-33-5_30PG").Row)
MsgBox ("remplacer par code matière.")
End If
If cpt_err = 1000 And sh1.Range("I1") < 0 Then
If MsgBox("La boucle a dépassé les 1000 itérations, nous craignions que vous ne soyez dans une boucle infinie; voulez-vous en faire 1000 de plus?", vbYesNo) = vbNo Then
MsgBox ("Le programme a été interrompu.")
wbk2.Close
Exit Sub
Else
cpt_err = 0
End If
End If
Wend
wbk2.Close
End SubLa ligne où pour toi il y avait le problème me semble bien, et oui wk1 c'était le fichier exemple et wk2 ton autre fichier
Merci de me dire si tu as encore des soucis ou non avec ton fichier, je n'ai pas testé mon code... Désolé d'avance si ça plante ..