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 et surtout de la comprendre.

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 Sub

En 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 Sub

la 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 - 1

et ceci après :

Plage.AutoFilter 5, Nparti

Merci 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.Value

Dans 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 Sub

Surtout 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 Sub

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 )

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 Range

tu déclares un objet Range et l'instruction :

Plage = Range("A1").CurrentRegion.Value

génère une erreur puisque pas d'instruction Set mais de cette manière non plus :

Set Plage = Range("A1").CurrentRegion.Value

car "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 Sub

Petite 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 je suis toujours à la recherche d'amélioration/optimisation ca me prend un temps fous en essai test ect ... bref.

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 j'ai bien les 324 libélé , mais il ne prend que les 193 première réponse, le reste est vide

    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 I

Je 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 ?

Rechercher des sujets similaires à "filtre critere"