Résolu Utiliser la Fonction Find pour afficher un résultat filtré en VBA - Excel

JulieM30

Habitué
Salut à tous ! :)

Je continue à faire mes petits pas dans le langage VBA et malheureusement me retrouve encore une fois coincée par mon code... :sarcastic:

J'ai un tableau (fixe) et on me demande de créer une maccro afin de filtrer certaines données et afficher les résultats par lignes. Je sais, faire un filtre tout simple serait la solution, mais justement on aimerait que tout le monde puisse utiliser ce fichier excel de manière intuitive, même pour ceux qui n'y connaissent rien... Donc, j'essaye de créer un petit code qui, par l'intermédiaire de boîtes de dialogues, fasse le filtre.
J'ai 2 critères : Le type et la date. (le type de fruit et la date de maturité de la récolte). Mon idée serait de filtrer d'abord sur le type, puis l'utilisateur cherchera à affiner sa recherche en tapant une date précise (j'aurais donc 2 petits programmes). Déjà faut il que j'arrive à faire marcher le premier que j'ai écrit ci-dessous :

Code:
Option Explicit

Sub Trouver()

Dim TheType As String
Dim F As Worksheet
Dim R As Range
Dim i As Long

Set F = Worksheets("Fiches")

TheType = InputBox("Entrez le type de pêche souhaité :", "Type")

With F
For i = 5 To 330
    Set R = .Range(i, 3).Find("TheType", LookIn:=xlValues, LookAt:=xlPart)
        If Not R Is Nothing Then
            F.Cells(i - 5).EntireRow.Hidden = True
            F.Cells(i + 5).EntireRow.Hidden = True
        Else
            MsgBox ("Ce type n'est pas répertorié")
        End If
Next
End With

En réalité je n'ai jamais utilisé la fonction Find auparavant, peut-être que je l'utilise mal ? Les arguments ne sont pas complets ? En erreur Excel m'affiche : "Erreur d'application '1004'. Erreur définie par l'application ou par l'objet"
Ce qui ne m'avance pas beaucoup...

Des lumières ??

Merci beaucoup à tous ceux qui se pencheront sur ce problème :) !! (Zeb, tu es de retour de vacances ? :p)
 

drul

Obscur pro du hardware
Staff
Salut, tu dois faire un find sur toute ta plage, et pas sur une cellule uniquement, c'est la cause de ton erreur.
Ensuite, il faut utiliser findnext pour trouver les autres occurences.

Exemple:
Code:
Option Explicit
 
Sub Trouver()
 
Dim TheType As String
Dim F As Worksheet
Dim R As Range
Dim i As Long
Dim FirstFound As String

 
Set F = Worksheets("Fiches")
 
TheType = InputBox("Entrez le type de pêche souhaité :", "Type")
 
With F.Range(Cells(5, 3), Cells(330, 3))

    Set R = .Find(TheType, LookIn:=xlValues)
    If Not (R Is Nothing) Then
        FirstFound = R.Address
        Do
            R.Offset(0, 1).Value = "trouver"
            Set R = .FindNext(R)
        Loop While R.Address <> FirstFound
    
    Else
        MsgBox ("Ce type n'est pas répertorié")
    End If
End With
 

JulieM30

Habitué
Salut Drul ! Merci pour ta réponse, déjà elle m'a permise de cerner un peu plus l'utilisation de Find, que je ne maitrisais pas du tout ! :bounce:
Donc je comprend, ainsi il regarde dans toute la plage... Néanmoins je ne comprend pas bien ta ligne :

Code:
With F.Range(Cells(5,3), Cells(330, 3))

A quoi sert ce "Cells(5,3)" ? Ce n'est pas suffisant d'écrire juste le Cells(330,3) ? (Pour qu'il ne cherche la valeur que dans les 330 lignes à la 3ème colonne) ?

Et autre lacune :
Pourquoi utilise t'on le ".Address" ? A quoi cela sert-il ?

Code:
FirstFound = R.Address

Sinon pour le reste j'ai bien compris la logique du code, je ne réfléchissais pas dans ce sens du tout !

J'attend tes éclairements sur mes petites questions, parce-que là j'ai essayé avec ce code, sa me marque encore le message d'erreur, comme au début ... :/

Il faut donc que j'adapte ! :)

Merci à vous !
 

drul

Obscur pro du hardware
Staff
Salut, le fait de passer deux cellules au Range, définit la plage. "Cells(5,3)" est le coin suppérieur gauche et Cells(330,3) est le coin inférieur droit. Si tu ne met qu'une cellule ta range n'est composé que d'une cellule et la fonction find ne marche pas.

Le . Address permet d'éviter que ton find ne tourne en boucle. (sinon findnext retrouverait les cellules déjà trouvées).
 

JulieM30

Habitué
Ok je vois, merci ! J'ai modifié pour le coup, sa s'éxécute bien jusqu'à l'InputBox, où il demande le type de pêche. Mais de suite après : "Erreur d'exécution 1004. Erreur définie par l'application ou par l'objet". J'ai lu l'aide, ce serait un objet que j'aurais mal défini à première vue, mais où ? J'ai bien déclaré toutes mes variables pourtant il me semble ! :??:
 

drul

Obscur pro du hardware
Staff
ça plante toujours sur le find ? reposte ton code que je regarde.

 

JulieM30

Habitué
Et voici :

Code:
 Option Explicit

Sub Trouver()

Dim TheType As String
Dim F As Worksheet
Dim R As Range
Dim FirstFound As String

Set F = Worksheets("Fiches")

TheType = InputBox("Entrez le type de pêche souhaité :", "Type")

With F.Range(Cells(5, 3), Cells(330, 3))

    Set R = .Find(TheType, LookIn:=xlValues, LookAt:=xlPart)
        If Not R Is Nothing Then
            FirstFound = R.Address
            Do
                R.Offset(0, 1).Value = "trouver"
                Set R = .FindNext(R)
            Loop While R.Adress <> FirstFound
        
        Else
            MsgBox ("Ce type n'est pas répertorié")
            
        End If
End With


End Sub
 

zeb

Modérateur
(

Salut, petite parenthèse pour signaler un mini bug.

Code:
F.Range(Cells(5, 3), Cells(330, 3))
Le Range s'applique sur la feuille F, les Cells sur la feuille courante.
Si la feuille courante n'est pas la feuille F, erreur 400 !

Range est pénible pour ça, au contraire de Intersect ou d'Union.

Autre bug qui n'en est pas un : merci de mettre le verbe trouver au participe passé à la ligne 20 !
(C'n'est pas Range qu'est pénible en fait :whistle: )

Autre bug qui n'en est toujours pas un : le nom de la fonction est très prétentieux. (Re)chercher plutôt ?
(C'est confirmé :D )


:lol:
)
 

drul

Obscur pro du hardware
Staff
Merci Zeb,

Décidement tu es mon idole (sisi :love:)
ça m'énerve de m'être fait avoir comme un bleu. :fou:
Pour le bug 2 qui n'en est pas un, j'avoue je suis nul en aurtograf.
Pour le Bug 3, je laisse Julie te répondre

Pour Julie, ligne 22, et si tu écrivais "address" juste ?
 

JulieM30

Habitué
Eh bien eh bien ! Zeb tu es un as ! :D
En effet, après ces quelques correctifs et notamment le coup de la page active (je ne savais pas du tout !!) Le programme tourne et me place à côté de ma colonne Type le mot "Trouvé" quand celui-ci correspond au critère.
Drul : Erreur de frappe avec le "address", un coup je l'avais écrit avec 2 "d" et l'autre avec un "d" (erreur vraiment d'inatention là... -_-' ) Mais pour le coup après ce petit rajout sa marche ! ;)

Code:
Option Explicit

Sub Rechercher()

Dim TheType As String
Dim F As Worksheet
Dim R As Range
Dim FirstFound As String

Set F = Worksheets("Fiches")

TheType = InputBox("Entrez le type de pêche souhaité :", "Type")

With F.Range(Cells(5, 3), Cells(330, 3))

    Set R = .Find(TheType, LookIn:=xlValues, LookAt:=xlPart)
        If Not (R Is Nothing) Then
            FirstFound = R.Address
            Do
                R.Offset(0, 1).Value = "Trouvé !"
                Set R = .FindNext(R)
            Loop While R.Address <> FirstFound
        
        Else
            MsgBox ("Ce type n'est pas répertorié")
            
        End If
End With


End Sub

Me voilà déjà bien avancée, merci beaucoup !

La suite, c'est qu'il faudrait que excel ne m'affiche que les lignes où le mot "Trouvé !" est... Trouvé. Donc j'ai pensé à écrire une suite dans l'esprit que si il trouve des cellules vides dans ma colonne 5 (là où le mot "Trouvé !" ce place) alors il efface les lignes de toutes ces cellules vides. Ce qui me donnerait mon fameux résultat filtré. Or 2 soucis :

1) Visiblement j'ai un dépassement de capacité quand j'éxécute ce code, ligne 7, "Erreur "6" : Dépassement de capacité". Mince, c'est trop gros de lui demander de regarder toutes les lignes et effacer ?


2) Dans cette logique je ne suis plus sur le simple filtre, puisqu'il efface tout ce qui ne correspond pas au critère... Donc l'utilisateur quand il va vouloir faire une autre recherche il ne trouvera plus de lignes ! :(

Avez vous une autre idée ?

Je poste tout de même ce que j'ai écrit, sans grand espoir pour son avenir... :

Code:
Set Plg = Range("D5:D330")
If Application.CountA(Plg) = Plg.Rows.Count Then Exit Sub   '  s'il n'y a pas de cellules vides
                                                            '  on sort
    Set Plg2 = Plg.SpecialCells(xlCellTypeBlanks) 'définit la plage, uniquement les cellules vides

        Plg2.Rows.Select 'sélectionne les lignes de toutes les cellules vides trouvées
        X = Plg2.Count 'nombre de cellules vides dans la plage
        Plg2.Areas(1).Select 'sélectionne la première cellule vide
        Plg2.Areas(X).Select 'sélectionne la dernière cellule vide
        Selection.ClearContents

En tout cas je suis ravie d'avoir appris à utiliser la fonction Find : très très pratique ! :)

 

zeb

Modérateur
Ecris
Code:
With F.Range(F.Cells(5, 3), F.Cells(330, 3))
pour éviter le bug repéré.
:fou:

Je vous laisse vous éclater avec Find et SpecialCells, et après je vous montre comment faire autrement.
Pourquoi pas tout de suite ?
Eh ! parce que Julie est en train d'apprendre des tas de choses intéressantes en cherchant elle-même et avec notre aide.
;)
 

drul

Obscur pro du hardware
Staff
Une idée est de changer la hauteur des lignes vides à 0 pixel, de cette manière elle disparaisse.

Mais en fait, pourquoi n'utilise tu pas les filtres auto de Excel, il me semblerait bien adapter à ce que tu veux faire ...

Donnée, filtre, filtreauto.
 

JulieM30

Habitué
Zeb, ta merveilleuse pédagogie te perdra :D mais tu n'as franchement pas tord ;)

Drul : C'est ce que je disais au début ! Sa parait ridicule ma requête quand on sait que le plus novice en excel saurait appliquer un simple filtre... -_-'' Mais on m'a demandé de le faire pour que n'importe qui et surtout ceux qui n'y connaissent rien du tout en excel puissent effectuer une recherche sans
même toucher aux onglets en haut de la fenêtre... Donc je m'y colle ! Et en même temps j'apprend :)

Ton idée sur la hauteur des lignes est super bien trouvée ! Je vais essayer de l'appliquer de ce pas :) merci !
 

drul

Obscur pro du hardware
Staff
Euh les filtres auto, une fois qui sont mis y a plus besoin d'aller dans leys menus, il y a juste une petite flèches sur la case d'entête et tu séléctionne juste le type de fruit désiré dans un menu déroulant. N'importe qui peut le faire. (en fait c'est même beaucoup plus simple que ton popup, puisque cela te propose directement toutes les possibilitées).

Jette un coup d'oeil ici:

 

JulieM30

Habitué
Oui je connais ;) Ton lien est quand même très intéressant à regarder et très complet, merci :)

Mais on me demande quand même un code, c'est l'occasion pour moi aussi de me faire un peu les dents, pas grave ! :) Je pense que c'est l'effet "intéraction" avec les InputBox qui leur plait surtout.. :sarcastic:

Bref : après exploration de l'idée sur la hauteur des cellules, je suis tombée sur peut-être autre chose, qui est à 2 doigts de marcher, que voici :

Code:
Dim Plg2 As Range
Dim C As Variant

Set Plg2 = F.Range(F.Cells(5, 4), F.Cells(330, 4))
Plg2.Select 'Je sélectionne ma plage = colonne de travail
For Each C In Selection 'Pour chaque cellule dans ma colonne
If F.Range(C) = "" Then 'Si ma cellule est vide
Rows(C.Row).Hidden = True 'Alors je cache la ligne contenant cette cellule vide
End If
Next

Je mettrais bien ça juste après mon End With du code précédent (qui marche à merveille lui !);
Ici le problème est visiblement à la ligne 7, où mon objet Range "échoue" :(
Décidément avec ce Range ! :kaola:
 

drul

Obscur pro du hardware
Staff
Quelques erreurs:

1) Dans la declaration: C est une range, pas une variant (ça marcherait quand même)

2) ligne 5 et 6 Plg2.Select et Selection.gnagna se remplace avantageusement par: plg2.gnagna

3) dans le for each, si tu veux chercher des cellules, dis le ! donc (cf ci-dessus) remplace selection par plg2.cells

4) C est est déjà une Range, donc inutile de l'entourer de F.Range(). Par dis au VBA ce que tu veux comparer (en l'occurence le ".Value") ce qui donne: if C.Value = "" then

5) Au lieu de Rows(C.Row), utilise c.EntireRow (ça marcherait quand même, mais moins propre)

Ensuite un conseille:

Au lieu de faire 330 hidden =true (ce qui est très lent), utilise Union pour te créer une grande plage et finalement fait le hidden directement sur cette plage:

Au finish ça donne:

Code:
Dim Plg2, plg3 As Range
Dim C As Range
Dim F As Worksheet
Set F = Worksheets("Fiches")
Set Plg2 = F.Range(F.Cells(5, 4), F.Cells(330, 4))
For Each C In Plg2.Cells 'Pour chaque cellule dans ma colonne
If C.Value = "" Then 'Si ma cellule est vide
    If plg3 Is Nothing Then
        Set plg3 = C
    Else
        Set plg3 = Union(plg3, C)
    End If
End If

Next
plg3.EntireRow.Hidden = true

P.S. Oublie pas de rendre visible toute les cellules à un moment donné ...
 

zeb

Modérateur
(Bon, ben je crois que je n'aurais bientôt plus rien à dire sur ce forum :/ Merci Drul :love: )
 

zeb

Modérateur
Ah si, je viens de voir un bug..... ahhhhh!
Ligne 1, Drul, tu déclares deux variables sur une même ligne. La première sera un variant. On est pas en PASCAL mais en VB

:bounce:

__________
/!\ irony inside

 

drul

Obscur pro du hardware
Staff
Tiens, on en apprend tout les jours.

Et en effet je programme principalement des trucs bizzares en Delphi (pascal), le VBA c'est juste un bac à sable pour moi ;)

Pour Julie, après on regardera comment modifier la routine pour se passer complétement du find plutot que de cascader l'appel de ces deux fonctions
(parce que bon la deuxième elle regarde déjà chaque cellule, alors pourquoi s'embêter a faire un find pour mettre un flag, pour ensuite rechercher chaque ligne sans flag et les cachers ...)
 

JulieM30

Habitué
Drul, c'est magnifique car ça marche parfaitement ! Je n'avais même pas vu l'erreur ligne 1 repérée par Zeb, car je déclare toujours mes variables ligne après ligne, donc je l'ai fait comme ça ici aussi et ma foi le programme tourne hyper bien ! :D Je suis d'accord pour le truc des 2 fonctions, sa le fait tourner 2 fois... Jvais essayer de voir comment simplifier ça. Pour redécouvrir les lignes, je pense créer un bouton de "réinitialisation", où l'utilisateur sera obligé de cliquer dessus avant de lancer tout type de recherche, il marche très bien :

Code:
Sub Réinitialiser()

Dim F As Worksheet
Dim Plg As Range

Set F = Worksheets("Fiches")
Set Plg = F.Range(F.Cells(2, 2), F.Cells(400, 6))

Plg.EntireRow.Hidden = False


With F.Range("C5:C330")
        .ClearContents
End With

With F.Range("E5:E330")
        .ClearContents
End With

End Sub

Au risque de paraître titilleuse ou pénible :ange: Si je souhaite qu'il affiche en réalité les 5 lignes au-dessus et les 5 lignes en-dessous de la valeur trouvée, comment puis-je m'y prendre ?

J'ai pensé utiliser notre "R" qui, après tout, est égal à la valeur trouvé non ? Genre lui dire R est à la ligne i de la colonne 3, afficher entre i+5 et i-5.
J'ai essayé de l'utiliser dans notre ligne :
Code:
Plg3.EntireRow.Hidden = True
mais sans grand succès... Peut-être qu'il existe un moyen plus simple ?
 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 128
Messages
6 717 852
Membres
1 586 375
Dernier membre
talmo
Partager cette page
Haut