Filtre critère
Si je peux encore un peu abusé , je pense avoir compris le souci mais ne vois pas trop comment le régler
maintenant l'appel de la fonction est devenu très très lente , je pense que c'est du a
=NB.SI.ENS(RecupResult!A:A;C2;RecupResult!B:B;I2)j'ai une autre feuille sur laquelle je référence la feuille que je génère j'imagine donc que ca fait ramer le bouzin y'aurait 'il moyen d'appliquer les formule une fois seulement les infos générer
Il te suffit de suspendre le calcul en le mettant sur manuel et de le rétablir en fin de procédure, pour ça, voir Application.Calculation
Au top merci , j'étudie ça .
Le truc avec le VBA c'est qu'il y'a toujours une fonction qui fait ce qu'on veux lol , maintenant le secret c'est comment trouver cette fonction ? y'a t'il un moyen spécifique ou c'est a force on les connais
Je me permet , mais aurais tu des livres/sites à conseiller.
J'était partie sur mettre mon nb.si dans un SI avec une condition variable que je mettais à jour à la fin du script lol
Bonjour,
Le dernier livre concernant Excel que j'ai ouvert je ne m'en souviens plus (ça fait déjà quelques années)
Internet, les forums et en particulier celui-ci sont des mines d'informations mais comme dit le proverbe, c'est en forgeant qu'on devient forgeron !
Merci encore pour ton aide, dans le but d'apprendre j'essaye d'optimiser au mieux le code
J'etait partis dans l'idée de ne plus utiliser qu'une seule et meme feuille pour le recup des resultats et le traitement .... me suis perdu lol
en fait j'ai bcq de mal a comprendre ca par rapport a un range.cureentregion qui ne marche pas d'ailleur en remplacement
Set Plage = .Range(.Cells(1, 1), _
.Cells(.Cells.Find("*", .[A1], -4123, , _
1, 2).Row, .Cells.Find("*", .[A1], -4123, , _
2, 2).Column))[/code]
Comme tu peux le voir si dessous j'ai fait des essais plutot concluant arrivant à faire ce que je veux , mais là je bloque , je voulais egalement compter le nombre de ligne filtré et si pas de résultat sortire de la fonction pas réussi lol
du coup j'ai fait autrement mais tous à la fin du traitement par contre
With Worksheets("RecupResult")
.Activate
On Error Resume Next
Set Plage = .Range(.Cells(1, 1), _
.Cells(.Cells.Find("*", .[A1], -4123, , _
1, 2).Row, .Cells.Find("*", .[A1], -4123, , _
2, 2).Column))
T = Plage
.Cells.Clear
For I = 1 To UBound(T, 2)
.Cells(I, 1).Value = T(1, I)
.Cells(I, 2).Value = T(2, I)
'.Cells(I, 3).FormulaLocal = "=NB.SI.ENS(FReponses!I:I;B" & I & ";FReponses!C:C;A" & I & ")"
Next I
If Range("B5").Value = "" Then
MsgBox "Participant non trouvé dans la Feuille de résultats " & vbLf & "ou erreur sur l'email " & vbLf & "Pas de résultat QCM", vbCritical, "Importation NOK"
ElseIf Range("B5").Value = Nparti Then
MsgBox "L'importantion des résultats QCM pour" & vbLf & "" & Nparti & "" & vbLf & "c'est déroulé avec succès", vbInformation, "Importation OK"
End If
End With
Application.DisplayAlerts = False
Sheets("Traitement").Delete
Application.DisplayAlerts = True
'With Worksheets("FReponses")
' .Activate
' Lastline = .Range("A" & .Rows.Count).End(xlUp).Row + 1
' .Cells(1, 10).Value = "Reponse OK"
' For I = 2 To Lastline
' .Cells(I, 10).FormulaLocal = "=NB.SI.ENS(RecupResult!$A:$A;$C" & I & ";RecupResult!$B:$B;$I" & I & ")"
' Next I
'.Columns(11).Copy
' .Columns(10).PasteSpecial Paste:=xlPasteValues
'.Columns(11).Clear
'End With
Worksheets("Eval Final").Activate
Application.Calculation = xlAutomatic
Application.ScreenUpdating = True
End SubEn vous remerciant par avance pour l'aide , j'essaye de comprendre mais je pense qu'il me manque encore 2 ou 3 petit conceptes que je ne comprends pas
Bonjour,
Le problème avec CurrentRegion c'est que tu ne peux pas être sûr de prendre en compte toute la zone utilisée (quand je dis "utilisée", je veux dire toute la zone qui contient des valeurs) sur la feuille et pour t'en convaincre, dans une feuille vierge, entres une valeur en A1 puis en B3 et exécutes cette Sub :
Sub Test()
MsgBox Range("A1").CurrentRegion.Address(0, 0)
End Subla valeur retournée sera A1 et non A1:B3 car B3 n'est pas contiguë à A1 maintenant, tu entres une valeur en B2 donc, contiguë à A1 et la valeur retournée sera alors A1:B3 car B2 fait le lien entre les deux cellules. Avec CurrentRegion, toutes les cellules doivent se toucher !
Il en est de même pour UsedRange qui à mon sens est même pire car si tu entres une valeur en A1 puis tu descends sur par exemple P30 et que tu n'entres aucune valeur mais simplement une mise en forme comme une mise en gras, la plage retournée sera A1:P30 alors que la seule valeur dans la feuille se trouve en A1 !
La fonction que j'utilise prend en compte la plage de A1 "Cells(1, 1)" à la valeur sur la ligne la plus basse et sur la colonne la plus à droite en utilisant la fonction "Find()" ce qui fait que si tu as une valeur à B3 et une autre en G10, la plage retournée sera A1:G10 et dans le cas où tu as une valeur en B3, une valeur en G10 et une valeur en B30, la plage retournée sera A1:G30 donc, la colonne la plus à droite (G) et la ligne la plus basse (30).
je voulais egalement compter le nombre de ligne filtré et si pas de résultat sortire de la fonction pas réussi lol
en utilisant la propriété "SpecialCells()" avec l'argumen,t "xlCellTypeVisible". La fonction va retourner le nombre de cellules visible issues du filtrage, il suffit alors de diviser par le nombre de colonnes que contient le filtrage ou encore la plage moins 1 pour ne pas prendre en compte la ligne d'entêtes :
NBLignes = .AutoFilter.Range.SpecialCells(xlCellTypeVisible).Count / .AutoFilter.Range.Columns.Count - 1
'ou :
NBLignes = .AutoFilter.Range.SpecialCells(xlCellTypeVisible).Count / Plage.Columns.Count - 1et ceci après :
Plage.AutoFilter 5, NpartiMerci beaucoup pour tes explications
J'ai encore un peu de mal a bien tous comprendre les mécanismes de VBA .
c'est le LookIn de -4123 qui me perturbe , pourquoi ce chiffre ?
le souci du VBA est qu'on peux faire les choses de 1000 façons différentes.
de ce fait ci dessous , j'ai du mal à comprendre dans quelle cas faire l'un ou l'autre ? (pour l'exemple j'utilise currentregion pour simplifier sinon j'utilise bien ta méthode
Set Plage = Range("A1").CurrentRegion
OU
Plage = Range("A1").CurrentRegion.ValueDans le but d'apprendre , j'ai repris le code que tu m'avais proposé pour me l'approprier et faire autrement.
Je n'utilise plus de feuille traitement et travail directement sur recup result avec une logique différente , je sélectionne tous ce que je ne veux pas puis le supprime avant de traiter la plage je pense gagné en utilisation mémoire en procédant de la sorte .
Je ne sais pas du tous si je respecte les bonnes pratiques
Option Explicit
Sub ImportCSV_et_traite()
Dim Fe As Worksheet
Dim Plage As Range
Dim T
Dim mypath
Dim Mparti As String
Dim I As Integer
Dim Lastline As Integer
Dim Verifexist As Integer
Dim Msgboxtxt As String
Dim NbrlResult As Integer
'on alimente les variables de validation de lancement de l'importantion
Verifexist = Range("QCMOK").Value2
Mparti = Range("MailParticipant").Value2
'On vérifie avant de lancer la procédure
If Mparti = "" Then
Msgboxtxt = MsgBox("Adresse email manquante" & vbLf & "Arret de la procédure d'importation du QCM" & vbLf & "Veuillez rentrer l'email du candidat", vbCritical, "! Email Obligatoire !")
Exit Sub
ElseIf Verifexist > 0 Then Msgboxtxt = MsgBox("QCM déjà integré !" & vbLf & "Voulez vous ré-importer un nouveau QCM ?" & vbLf & "Attention reset du QCM présent", vbYesNo + vbQuestion, "! QCM déjà présent !")
If Msgboxtxt = vbNo Then Exit Sub
End If
mypath = Application.GetOpenFilename(", *.csv", , "Recherche du CSV", "Envoyer le CSV")
If mypath = False Then Exit Sub
Application.ScreenUpdating = False
Application.Calculation = xlManual
'si la feuille n'existe pas, elle est créée sinon, vidée
On Error Resume Next
Set Fe = Worksheets("RecupResult")
If Err.Number <> 0 Then
Set Fe = Sheets.Add(, Worksheets(Worksheets.Count))
Fe.Name = "RecupResult"
Else
Fe.Cells.Clear
End If
On Error GoTo 0 'suppression du gestionnaire d'erreur
'applique une requête sur le fichier
With Fe.QueryTables.Add("TEXT;" & mypath, Fe.Range("A1"))
.TextFileSemicolonDelimiter = True
.TextFilePlatform = 65001
.Refresh 'exécute la requête
.Delete 'supprime la connexion au fichier texte
End With
'défini la plage et applique le filtre avec copie du résultat
'sur la feuille "RecupResult"
With Fe
Set Plage = .Range(.Cells(1, 1), _
.Cells(.Cells.Find("*", .[A1], -4123, , _
1, 2).Row, .Cells.Find("*", .[A1], -4123, , _
2, 2).Column))
'Set Plage = Range("A1").CurrentRegion
'Plage = Range("A1").CurrentRegion.Value
Plage.AutoFilter 'permet de mettre à 0 les filtres si présent
Plage.AutoFilter 5, "<>" & Mparti 'on affiche les lignes non conrrespondantes au critère
Plage.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.EntireRow.Delete 'Puis on supprime en gardant l'entete
'Plage.SpecialCells(xlCellTypeVisible).EntireRow.Copy Worksheets("RecupResult").Range("A1")
'.AutoFilter.Range.EntireRow.Copy Worksheets("RecupResult").Range("A1")
Plage.AutoFilter ' on supprime les filtres pour voir la ligne que l'on veux
NbrlResult = Plage.Rows.Count ' et on compte
If NbrlResult <> 2 Then
.Cells.Clear
MsgBox "Participant non trouvé dans la Feuille de résultats " & vbLf & "ou erreur sur l'email " & vbLf & "Pas de résultat QCM", vbCritical, "Importation NOK"
Exit Sub
End If
T = Plage
.Cells.Clear
For I = 1 To UBound(T, 2)
.Cells(I, 1).Value = T(1, I)
.Cells(I, 2).Value = T(2, I)
'.Cells(I, 3).FormulaLocal = "=NB.SI.ENS(FReponses!I:I;B" & I & ";FReponses!C:C;A" & I & ")"
Next I
MsgBox "L'importation des résultats QCM pour" & vbLf & "" & Range("B4").Value & " " & Range("B3").Value & " " & Mparti & "" & vbLf & "c'est déroulé avec succès", vbInformation, "Importation OK"
End With
Application.Calculation = xlAutomatic
Application.ScreenUpdating = True
Worksheets("Eval Finale").Activate
End SubSurtout surtout ne pas hésiter à critiquer, je suis demandeur , mon but étant de prendre les bonnes habitudes tous de suites .
Ps : j'utilise Value2 pour les variable que je trouve plus pratique du fait de son non formatage je ne vois pas beuacoup de gens l'utilisant ici y'a t'il une raison ??
Encore merci tu m'a mis le pieds à l'étrier , ...... maintenant ca m'éclate le VBA merci merci merci
Ahh encore juste une petit question , pourquoi ouvrire et fermer les With tant q'on travail avec le même objet ?
Bonjour,
J'ai encore un peu de mal a bien tous comprendre les mécanismes de VBA .
c'est le LookIn de -4123 qui me perturbe , pourquoi ce chiffre ?
Ce nombre représente la valeur de la constante "xlFormulas"
Ci-dessous, j'ai éclaté le code en utilisant les constantes adéquates plutôt que leur valeur !
J'ai essayé d'expliquer au mieux le principe de fonctionnement :
Sub DefinirLaPlage()
Dim plage As Range
Dim Col As Long
Dim Lig As Long
Dim Cel_1 As Range
Dim Cel_2 As Range
With ActiveSheet
'si on veut commencer la plage depuis A1 (cellule qui sera la plus à gauche et en haut)
Set Cel_1 = .Cells(1, 1)
'"*" ---> cherche n'importe quelle valeur
'.[A1] ---> plage de référence(qui peut être une seule cellule, ce qui est le cas ici), on pourrait écrire .Range("A1"), les crochets représente la fonction "Evaluate()" donc, le compilateur sait comment interpréter cela
'xlFormulas ---> recherche aussi dans les formules
'xlByRows ---> recherche par ligne
'xlByColumns ---> recherche par colonne
'xlPrevious ---> recherche en arrière à patir de A1
'donc, comme si on partait de la cellule "XFD1048576" (>= 2007) en remontant depuis tout en bas et tout à droite
'pour trouver la ligne de la cellule la plus basse ayant une valeur...
Lig = .Cells.Find("*", .[A1], xlFormulas, , xlByRows, xlPrevious).Row
'...et la colonne la plus à droite ayant elle aussi une valeur
Col = .Cells.Find("*", .[A1], xlFormulas, , xlByColumns, xlPrevious).Column
'ce qui donne une cellule à l'intersection de la ligne et de la colonne
Set Cel_2 = .Cells(Lig, Col)
'et voilà la plage
Set plage = .Range(Cel_1, Cel_2)
End With
End Suble souci du VBA est qu'on peux faire les choses de 1000 façons différentes.
de ce fait ci dessous , j'ai du mal à comprendre dans quelle cas faire l'un ou l'autre ? (pour l'exemple j'utilise currentregion pour simplifier sinon j'utilise bien ta méthode
)
En VBA, pour définir un objet quel qu'il soit, il faut utiliser l'instruction "Set" donc, quand tu déclares :
Dim Plage As Rangetu déclares un objet Range et l'instruction :
Plage = Range("A1").CurrentRegion.Valuegénère une erreur puisque pas d'instruction Set mais de cette manière non plus :
Set Plage = Range("A1").CurrentRegion.Valuecar "Value" ne renvoi pas un objet mais une valeur de l'objet "CurrentRegion" qui lui, est une propriété de l'objet Range et qui renvoi un objet Range. Pas toujours facile à comprendre quand on commence mais rassure toi, nous sommes tous passés par là !
Si tu veux récupérer ce que renvoi "Range("A1").CurrentRegion.Value", il te faut utiliser un "Array" (un tableau) qui va contenir la ou les valeurs du Range, exemple :
Sub Test()
Dim Plage As Variant
Dim I As Integer
Dim J As Integer
Plage = Range("A1").CurrentRegion.Value
'on boucle sur les lignes
For I = 1 To UBound(Plage, 1)
'et sur chaque colonne de la ligne en cours
For J = 1 To UBound(Plage, 2)
Debug.Print Plage(I, J) 'dans la fenêtre d'exécution (Ctrl+G)
Next J, I
End SubPetite précision, un Array(), si Option Base n'est pas précisé en tête de module, a pour base 0 mais quand on affecte des valeurs de plage à un Array(), c'est toujours en base 1 donc, toujours :
For I = 1 To UBound(Plage, 1)
et non :
For I = 0 To UBound(Plage, 1) - 1
c'est d'ailleurs ce que j'ai fais ici dans le code que je t'ai donné :
T = Plage
For I = 1 To UBound(T, 2)T = Plage ou T = Plage.Value revient au même !
Bon, je te laisse digérer
Je viens a peine de finir de digérer
J'ai finaliser le projet en l'état avant digestion , je vais le reprendre sous peu pour améliorer et optimiser tous ça.
Mon souci et que je n'arrive pas à lâcher mes codes
Merci encore Theze
Bon gros souci , j'arrive pas à comprendre d'ou cela peut venir , je ne récupère que les 193 premières réponses au question
Dim Fe As Worksheet
Dim Plage As Range
Dim T
Dim Tresp As Integer
Dim mypath
Dim Nparti
Dim I As Integer
Dim Lastline As Integer
Nparti = Range("MailParticipant").Value
If Nparti = "" Then
MsgBox "Adresse email manquante" & vbLf & "Arret de la procédure d'importation du QCM" & vbLf & "Veuillez rentrer l'email du candidat", vbCritical, "Email Obligatoire"
Exit Sub
End If
mypath = Application.GetOpenFilename(", *.csv", , "Recherche du CSV", "Envoyer le CSV")
If mypath = False Then Exit Sub
Application.ScreenUpdating = False
Application.Calculation = xlManual
'si la feuille n'existe pas, elle est créée sinon, vidée
On Error Resume Next
Set Fe = Worksheets("Traitement")
If Err.Number <> 0 Then
Set Fe = Sheets.Add(, Worksheets(Worksheets.Count))
Fe.Name = "Traitement"
Else
Fe.Cells.Clear
End If
On Error GoTo 0 'suppression du gestionnaire d'erreur
'applique une requête sur le fichier
With Fe.QueryTables.Add("TEXT;" & mypath, Fe.Range("A1"))
.TextFileSemicolonDelimiter = True
.TextFilePlatform = 65001
.Refresh 'exécute la requête
.Delete 'supprime la connexion au fichier texte
End With
'défini la plage et applique le filtre avec copie du résultat
'sur la feuille "RecupResult" atterntion, elle doit exister !
With Fe
Set Plage = .Range(.Cells(1, 1), _
.Cells(.Cells.Find("*", .[A1], -4123, , _
1, 2).Row, .Cells.Find("*", .[A1], -4123, , _
2, 2).Column))
Plage.AutoFilter 5, Nparti
.AutoFilter.Range.EntireRow.Copy Worksheets("RecupResult").Range("A1")
End With
'les valeurs sont passées à un tableau, la feuille est vidée et les valeurs sont
'placées en colonne A pour les entêtes et B pour les valeurs
With Worksheets("RecupResult")
.Activate
On Error Resume Next
Set Plage = .Range(.Cells(1, 1), _
.Cells(.Cells.Find("*", .[A1], -4123, , _
1, 2).Row, .Cells.Find("*", .[A1], -4123, , _
2, 2).Column))
T = Plage
.Cells.Clear
For I = 1 To UBound(T, 2)
.Cells(I, 1).Value = T(1, I)
.Cells(I, 2).Value = T(2, I)
Next IJe viens de comprendre, en fait ce sont les saut de ligne dans la cellule qui me fait sauter les réponse qui suivent.
Comment faire pour gérer ca ?