Ceci est une page optimisée pour les mobiles. Cliquez sur ce texte pour afficher la vraie page.

XL 2021 VBA Alternative à SpecialCells(xlCellTypeVisible)

  • Initiateur de la discussion Initiateur de la discussion Dudu2
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Dudu2

XLDnaute Barbatruc
Bonjour

SpecialCells ne fonctionne pas sur une feuille protégée (erreur 1004).
J'ai besoin de connaître le Range des cellules visibles d'une feuille non protégée.
Auriez-vous une fonction performante qui fait ça ?

VB:
Sub a()
    Dim R As Range
  
    On Error Resume Next
    Set R = ActiveSheet.Cells.SpecialCells(xlCellTypeVisible)
    MsgBox "Err.Number = " & Err.Number & IIf(Err.Number = 0, ", Range = " & R.Address(0, 0), "")
End Sub
 
Dernière édition:
Dans les cas "standards" les fonctions (@mapomme et @Dudu2) sont 10 fois plus rapides que le SpecialCells.
Dans les cas marginaux (ex toutes les lignes masquées sauf la dernière) c'est la cata pour les fonctions qui bouclent sur les 1.000.000+ de lignes du UsedRange. Je vais essayer de couvrir ces cas.

Concernant le test de toutes les lignes ou colonnes masquées...
VB:
    'All Rows hidden
    If Worksheet.Cells.Rows.Hidden Then Exit Function
 
    'All Columns hidden
    If Worksheet.Cells.Columns.Hidden Then Exit Function
 

Pièces jointes

Dernière édition:
je pense qu'on fait quelques erreurs :
  • If Worksheet.Cells.Rows.Hidden Then Exit Function ne vérifie que la première ligne, si la première ligne est cachée alors le résultat sera "Vrai", le reste est sans importance. Mieux serait de vérifier ceci : if worksheet.cells(rows.count,1).top=0 then exit function. La même chose pour les colonnes et left.

  • PS l'utilisation du variable "Worksheet" pour assigner une feuille est douteuse, mieux serait "ws" ou "sh"
  • si on cache des lignes dans la plage dehors "usedrange" cela n'est pas bien manipulé
on ne demande presque jamais la plage des cellules visible d'une feuille complète, ce sera plutôt sheets(....).usedrange.specialcells(xlvisible) donc une partie sérieuzement plus petite que la feuille complète, donc l'écart entre vos fonctions et ce "specialcells" sera moins grand.
A mon avis, aucune de vos fonctions est fiable assez pour remplacer "specialcells"
 
If Worksheet.Cells.Rows.Hidden Then Exit Function ne vérifie que la première ligne,
C'est vrai, et d'une manière générale on ne peut tester qu'une seule ligne ou colonne avec .Hidden.
Si on groupe plusieurs lignes ou colonnes dans le Range testé avec .Hidden, ça ne donne pas le résultat escompté. Pas très cool et pas du tout intuitif.

PS l'utilisation du variable "Worksheet" pour assigner une feuille est douteuse, mieux serait "ws" ou "sh"
Excel sait parfaitement faire la différence en un nom de variable et un type. Cela ne pose aucun problème d'utiliser Range ou Workbook ou Worksheet comme nom de variable. Dans les instructions déclaratives le nom de variables est avant le type. Dans les instructions autres, on manipule des noms de variables, pas de types sauf avec TypeOf où Excel sait où se trouve le nom et le type.

si on cache des lignes dans la plage dehors "usedrange" cela n'est pas bien manipulé
A part le cas ou toutes les lignes ou toutes les colonnes sont masquées, un masquage en dehors du UsedRange en cours étend le UsedRange aux limites de ce masquage. Donc on peut assurément, après exclusion du masquage de tout, utiliser le UsedRange pour détecter les lignes masquées. Dans les cas "standards" ça évite de parcourir un grand nombre de lignes et colonnes. Dans les cas marginaux, qui incluent des lignes et colonnes masquées bien au-delà des données, au contraire, ça oblige à les parcourir inutilement.
Hélas on ne peut le faire que ligne par ligne et colonne par colonne à cause de l'impossibilité de tester le .Hidden sur plus d'1.
 
Dernière édition:
Sinon, il y a peut-être une solution pour détecter par Ranges de multiples lignes (ou colonnes) issue du commentaire de @bsalv en testant les .top des lignes (ou .left des colonnes) sachant qu’apparemment Excel considère comme Hidden une ligne de hauteur 0 (ou une colonne de largeur 0).

Ça permettrait d'éviter un parcours ligne par ligne (ou colonne par colonne) pour détecter les masquages.
Pas simple à coder car il faut considérer des groupes progressivement réduits (genre dichotomie en réduction) pour les boucles de détection.

Edit: à propos j'ai remplacé les tests de tout masqué (sur l'idée de @bsalv) par:
VB:
    'All Rows hidden
    If Worksheet.Rows(Rows.Count).Top = 0 Then Exit Function
 
    'All Columns hidden
    If Worksheet.Columns(Columns.Count).Left = 0 Then Exit Function
 
Dernière édition:
Bonjour @Dudu2

j'ai essayer quelques choses : cela semble assez rapide

VB:
Option Explicit
Function ReperePlageVisible(Wks As Worksheet) As Collection
' Prend la feuille (active Wks) en paramètre
' Retourne la Collection contenant toutes les zones de cellules visibles :
'       - ligne par ligne
'
' Déclaration des variables
    Dim UniondRng As Range ' ................ Stocke le UsedRange de la feuille (zone réellement utilisée).
    Dim ColDept As Long ' ................... C'est la premiére colonne de la zone visible sur la ligne courante "UniondRng".
    Dim colFin As Long ' .................... C'est la derniere colonne de la zone visible sur la ligne courante "UniondRng".
    Dim PlageVisible As New Collection ' .... C'est cette Collection qui stock chaque UniondRng visible contigu par ligne.
    Dim Lig As Long ' ....................... C'est le Compteur des boucles des lignes
    Dim Col As Long ' ....................... C'est le Compteur des boucles des Colonnes
    Dim PremCol As Long ' ................... C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    Dim DerCol As Long ' .................... C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    On Error Resume Next ' .................. Au cas ou la feuille est vide ! (Sécurité d'une Gestion d'Erreur).
        Set UniondRng = Wks.UsedRange ' ..... Stocks (Toutes les plages de la feuille)
    On Error GoTo 0
'
    If UniondRng Is Nothing Then Exit Function ' ................. Fin de la VBA si aucune cellule remplis !
'
    PremCol = UniondRng.Columns(1).Column '......................  C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    DerCol = UniondRng.Columns(UniondRng.Columns.Count).Column ' . C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    ' Parcours toutes les lignes de "UniondRng" :
    ' Les lignes sans cellules non vides ne génèrent aucune plage.
    ' Exemple : Plage 1 (B6:B31) ' Lignes 6 à 31
    '         ' la ligne 5 Est totalement vide donc (pas prise en compte)
    '           Plage 2 (E2:E4) ' Ligne 2 à 4
    ' Parcours des lignes "UniondRng" soit : 2 à 4 (Plage 1) | La ligne 5 exclus | Puis de 6 à 31 (Plage 2)
    For Lig = UniondRng.Row To UniondRng.Row + UniondRng.Rows.Count - 1
        ' Boucle sur toutes les lignes utilisées.
        If Not Wks.Rows(Lig).Hidden Then ' Ignore les lignes masquées
            ColDept = 0 ' Réinitialisation : Colonne à 0.
            ' Parcours colonne par colonne dans la ligne courante de "UniondRng" :.
            ' Exclus les Colonnes totalement vide.
            For Col = PremCol To DerCol
                If Not Wks.Columns(Col).Hidden Then ' Ignore les Colonnes masquées
                    ' Démarre ou étend une zone contiguë visible.
                    If ColDept = 0 Then
                        If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                            ColDept = Col ' Premiére Colonne de la plage "UniondRng"
                        End If
                    End If
                    If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        colFin = Col  ' Derniére Colonne de la plage "UniondRng"
                    End If
                Else ' Colonne masquée ? fin de zone visible.
                    ' Fin de zone contiguë visible
                    If ColDept > 0 Then
                        ' Enregistre la zone visible détectée dans la collection
                        PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
                        ColDept = 0
                    End If
                End If
            Next Col
            ' Cas où la ligne se termine sur une colonne visible
            ' Ajouter la zone en fin de ligne
            If ColDept > 0 Then
                ' Stock la plage dans la collection
                PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
            End If
        End If
    Next Lig
   
    ' Retour de la fonction
    Set ReperePlageVisible = PlageVisible ' Cette collection contient l'ensemble des plages visibles.
End Function

' Exemple d'utilisation
Sub PlageVisible()
    Dim Col As Collection
    Dim Rng As Range
    Dim Msg As String
'
    ' Fonction : Stocks toutes les cellules visibles dans la collection "Col"
    Set Col = ReperePlageVisible(ActiveSheet)
'
    If Col.Count = 0 Then
        MsgBox "Aucune cellule visible"
        Exit Sub
    End If
'
    Msg = "Cellule Visibles :" & vbCrLf
    For Each Rng In Col
        Msg = Msg & Rng.Address(0, 0) & vbCrLf
    Next Rng
    MsgBox Msg
'
End Sub
 
Bonjour @Dudu2
Bonsoir @laurent950,
Je ne suis pas chez moi ce WE et regarderai ça lundi.

C'est effectivement assez complexe a comprendre pour en définir une régle et trouver le bon algorithme.

j'ai fais 5 versions : V0 / V1 / V2 / V3 / (V4 = c'est une solution voir ma solution sur l'ensemble des codes proposés)

pour arrivé a comprendre c'est la V4 qui fonctionne je poste les 5 versions. pour en comprendre les évolutions et peux être que l'on pourrait encore Obptimisé (mais c'est la version V4 (Ultra Rapide qui fonctionne parfaitement) --- de La V0 à V3 pour en comprendre le fil et l'évolution vers la final V4.
 
Dernière édition:
Bonjour @Dudu2

Module_L950_V0


VB:
Option Explicit
Function ReperePlageVisible_V0(Wks As Worksheet) As Collection
' Prend la feuille (active Wks) en paramètre
' Retourne la Collection contenant toutes les zones de cellules visibles :
'       - ligne par ligne
'
' Déclaration des variables
    Dim UniondRng As Range ' ................ Stocke le UsedRange de la feuille (zone réellement utilisée).
    Dim ColDept As Long ' ................... C'est la premiére colonne de la zone visible sur la ligne courante "UniondRng".
    Dim colFin As Long ' .................... C'est la derniere colonne de la zone visible sur la ligne courante "UniondRng".
    Dim PlageVisible As New Collection ' .... C'est cette Collection qui stock chaque UniondRng visible contigu par ligne.
    Dim Lig As Long ' ....................... C'est le Compteur des boucles des lignes
    Dim Col As Long ' ....................... C'est le Compteur des boucles des Colonnes
    Dim PremCol As Long ' ................... C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    Dim DerCol As Long ' .................... C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    On Error Resume Next ' .................. Au cas ou la feuille est vide ! (Sécurité d'une Gestion d'Erreur).
        Set UniondRng = Wks.UsedRange ' ..... Stocks (Toutes les plages de la feuille)
    On Error GoTo 0
'
    If UniondRng Is Nothing Then Exit Function ' ................. Fin de la VBA si aucune cellule remplis !
'
    PremCol = UniondRng.Columns(1).Column '......................  C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    DerCol = UniondRng.Columns(UniondRng.Columns.Count).Column ' . C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    ' Parcours toutes les lignes de "UniondRng" :
    ' Les lignes sans cellules non vides ne génèrent aucune plage.
    ' Exemple : Plage 1 (B6:B31) ' Lignes 6 à 31
    '         ' la ligne 5 Est totalement vide donc (pas prise en compte)
    '           Plage 2 (E2:E4) ' Ligne 2 à 4
    ' Parcours des lignes "UniondRng" soit : 2 à 4 (Plage 1) | La ligne 5 exclus | Puis de 6 à 31 (Plage 2)
    For Lig = UniondRng.Row To UniondRng.Row + UniondRng.Rows.Count - 1
        ' Boucle sur toutes les lignes utilisées.
        If Not Wks.Rows(Lig).Hidden Then ' Ignore les lignes masquées
            ColDept = 0 ' Réinitialisation : Colonne à 0.
            ' Parcours colonne par colonne dans la ligne courante de "UniondRng" :.
            ' Exclus les Colonnes totalement vide.
            For Col = PremCol To DerCol
                If Not Wks.Columns(Col).Hidden Then ' Ignore les Colonnes masquées
                    ' Démarre ou étend une zone contiguë visible.
                    If ColDept = 0 Then
                        If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                            ColDept = Col ' Premiére Colonne de la plage "UniondRng"
                        End If
                    End If
                    If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        colFin = Col  ' Derniére Colonne de la plage "UniondRng"
                    End If
                Else ' Colonne masquée ? fin de zone visible.
                    ' Fin de zone contiguë visible
                    If ColDept > 0 Then
                        ' Enregistre la zone visible détectée dans la collection
                        PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
                        ColDept = 0
                    End If
                End If
            Next Col
            ' Cas où la ligne se termine sur une colonne visible
            ' Ajouter la zone en fin de ligne
            If ColDept > 0 Then
                ' Stock la plage dans la collection
                PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
            End If
        End If
    Next Lig
    
    ' Retour de la fonction
    Set ReperePlageVisible_V0 = PlageVisible ' Cette collection contient l'ensemble des plages visibles.
End Function

' Exemple d'utilisation
Sub PlageVisible_V0()
    Dim Col As Collection
    Dim Rng As Range
    Dim Msg As String
'
    ' Fonction : Stocks toutes les cellules visibles dans la collection "Col"
    Set Col = ReperePlageVisible_V0(ActiveSheet)
'
    If Col.Count = 0 Then
        MsgBox "Aucune cellule visible"
        Exit Sub
    End If
'
    Msg = "Cellule Visibles :" & vbCrLf
    For Each Rng In Col
        Msg = Msg & Rng.Address(0, 0) & vbCrLf
    Next Rng
'    MsgBox Msg
'
End Sub
 
Bonjour @Dudu2

Module_L950_V1_VarianteCells

Code:
Option Explicit
Function ReperePlageVisible_L950_V1_VarianteCells(Wks As Worksheet) As Collection
' Prend la feuille (active Wks) en paramètre
' Retourne la Collection contenant toutes les zones de cellules visibles :
'       - ligne par ligne
'
' Déclaration des variables
    Dim UniondRng As Range ' ................ Stocke le UsedRange de la feuille (zone réellement utilisée).
    Dim ColDept As Long ' ................... C'est la premiére colonne de la zone visible sur la ligne courante "UniondRng".
    Dim colFin As Long ' .................... C'est la derniere colonne de la zone visible sur la ligne courante "UniondRng".
    Dim PlageVisible As New Collection ' .... C'est cette Collection qui stock chaque UniondRng visible contigu par ligne.
    Dim Lig As Long ' ....................... C'est le Compteur des boucles des lignes
    Dim Col As Long ' ....................... C'est le Compteur des boucles des Colonnes
    Dim PremCol As Long ' ................... C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    Dim DerCol As Long ' .................... C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    On Error Resume Next ' .................. Au cas ou la feuille est vide ! (Sécurité d'une Gestion d'Erreur).
        Set UniondRng = Wks.UsedRange ' ..... Stocks (Toutes les plages de la feuille)
    On Error GoTo 0
'
    If UniondRng Is Nothing Then Exit Function ' ................. Fin de la VBA si aucune cellule remplis !
'
    PremCol = UniondRng.Columns(1).Column '......................  C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    DerCol = UniondRng.Columns(UniondRng.Columns.Count).Column ' . C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    ' Parcours toutes les lignes de "UniondRng" :
    ' Les lignes sans cellules non vides ne génèrent aucune plage.
    ' Exemple : Plage 1 (B6:B31) ' Lignes 6 à 31
    '         ' la ligne 5 Est totalement vide donc (pas prise en compte)
    '           Plage 2 (E2:E4) ' Ligne 2 à 4
    ' Parcours des lignes "UniondRng" soit : 2 à 4 (Plage 1) | La ligne 5 exclus | Puis de 6 à 31 (Plage 2)
    For Lig = UniondRng.Row To UniondRng.Row + UniondRng.Rows.Count - 1
        ' Boucle sur toutes les lignes utilisées.
        If Not Wks.Rows(Lig).Hidden Then ' Ignore les lignes masquées
            ColDept = 0 ' Réinitialisation : Colonne à 0.
            ' Parcours colonne par colonne dans la ligne courante de "UniondRng" :.
            ' Exclus les Colonnes totalement vide.
            Dim CelNotEmpty As Variant
            For Col = PremCol To DerCol
            ' Optimisation 1 (VarianteCells = Accées via les cellules excel)
            ' Lire une seule fois la valeur de la cellule
            ' Gains : ÷2 accès cellule
                CelNotEmpty = Wks.Cells(Lig, Col).Value
                If Not Wks.Columns(Col).Hidden Then ' Ignore les Colonnes masquées
                    ' Démarre ou étend une zone contiguë visible.
                    If ColDept = 0 Then
                       'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                            ColDept = Col ' Premiére Colonne de la plage "UniondRng"
                        End If
                    End If
                        'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                            colFin = Col  ' Derniére Colonne de la plage "UniondRng"
                        End If
                Else ' Colonne masquée ? fin de zone visible.
                    ' Fin de zone contiguë visible
                    If ColDept > 0 Then
                        ' Enregistre la zone visible détectée dans la collection
                        PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
                        ColDept = 0
                    End If
                End If
            Next Col
            ' Cas où la ligne se termine sur une colonne visible
            ' Ajouter la zone en fin de ligne
            If ColDept > 0 Then
                ' Stock la plage dans la collection
                PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
            End If
        End If
    Next Lig
    
    ' Retour de la fonction
    Set ReperePlageVisible_L950_V1_VarianteCells = PlageVisible ' Cette collection contient l'ensemble des plages visibles.
End Function

' Exemple d'utilisation
Sub PlageVisible_V1()
    Dim Col As Collection
    Dim Rng As Range
    Dim Msg As String
'
    ' Fonction : Stocks toutes les cellules visibles dans la collection "Col"
    Set Col = ReperePlageVisible_L950_V1_VarianteCells(ActiveSheet)
'
    If Col.Count = 0 Then
        MsgBox "Aucune cellule visible"
        Exit Sub
    End If
'
    Msg = "Cellule Visibles :" & vbCrLf
    For Each Rng In Col
        Msg = Msg & Rng.Address(0, 0) & vbCrLf
    Next Rng
'    MsgBox Msg
'
End Sub
 
Bonjour @Dudu2

Module_L950_V2_VarianteCellsTab


Code:
Option Explicit
Function ReperePlageVisible_L950_V2_VarianteCellsTab(Wks As Worksheet) As Collection
' Prend la feuille (active Wks) en paramètre
' Retourne la Collection contenant toutes les zones de cellules visibles :
'       - ligne par ligne
'
' Déclaration des variables
    Dim UniondRng As Range ' ................ Stocke le UsedRange de la feuille (zone réellement utilisée).
    Dim ColDept As Long ' ................... C'est la premiére colonne de la zone visible sur la ligne courante "UniondRng".
    Dim colFin As Long ' .................... C'est la derniere colonne de la zone visible sur la ligne courante "UniondRng".
    Dim PlageVisible As New Collection ' .... C'est cette Collection qui stock chaque UniondRng visible contigu par ligne.
    Dim Lig As Long ' ....................... C'est le Compteur des boucles des lignes
    Dim Col As Long ' ....................... C'est le Compteur des boucles des Colonnes
    Dim PremCol As Long ' ................... C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    Dim DerCol As Long ' .................... C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    On Error Resume Next ' .................. Au cas ou la feuille est vide ! (Sécurité d'une Gestion d'Erreur).
        Set UniondRng = Wks.UsedRange ' ..... Stocks (Toutes les plages de la feuille)
    On Error GoTo 0
'
    If UniondRng Is Nothing Then Exit Function ' ................. Fin de la VBA si aucune cellule remplis !
'
    PremCol = UniondRng.Columns(1).Column '......................  C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    DerCol = UniondRng.Columns(UniondRng.Columns.Count).Column ' . C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    ' Parcours toutes les lignes de "UniondRng" :
    ' Les lignes sans cellules non vides ne génèrent aucune plage.
    ' Exemple : Plage 1 (B6:B31) ' Lignes 6 à 31
    '         ' la ligne 5 Est totalement vide donc (pas prise en compte)
    '           Plage 2 (E2:E4) ' Ligne 2 à 4
    ' Parcours des lignes "UniondRng" soit : 2 à 4 (Plage 1) | La ligne 5 exclus | Puis de 6 à 31 (Plage 2)
    For Lig = UniondRng.Row To UniondRng.Row + UniondRng.Rows.Count - 1
        ' Boucle sur toutes les lignes utilisées.
        If Not Wks.Rows(Lig).Hidden Then ' Ignore les lignes masquées
            ColDept = 0 ' Réinitialisation : Colonne à 0.
            ' Optimisation 2 (VarianteCellsTab = Accées via une variable tableau 2D)
            ' Cette fois ci Précharger la ligne dans une variable tableau 2D (vraiment plus très rapide)
            ' Maintenant Excel n’est plus appelé cellule par cellule plus de Lecture pour une seule fois la valeur de la cellule "CelNotEmpty"
            ' Gains : Travailler en mémoire (VBA pur) décorrelé de la feuille excel.
            Dim TabLig As Variant
                TabLig = Wks.Range(Wks.Cells(Lig, PremCol), Wks.Cells(Lig, DerCol)).Value
            ' Parcours colonne par colonne dans la ligne courante de "UniondRng" :.
            ' Exclus les Colonnes totalement vide.
            'For Col = PremCol To DerCol
            For Col = 1 To UBound(TabLig, 2)
                'Dim CelNotEmpty As Variant
                'CelNotEmpty = Wks.Cells(Lig, Col).Value
                'If Not Wks.Columns(Col).Hidden Then ' Ignore les Colonnes masquées
                If Not Wks.Columns(PremCol + Col - 1).Hidden Then
                    ' Démarre ou étend une zone contiguë visible.
                    If ColDept = 0 Then
                       'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        'If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                        If TabLig(1, Col) <> Empty Then
                            'ColDept = Col ' Premiére Colonne de la plage "UniondRng"
                            ColDept = PremCol + Col - 1
                        End If
                    End If
                        'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        'If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                        If TabLig(1, Col) <> Empty Then
                            'colFin = Col  ' Derniére Colonne de la plage "UniondRng"
                            colFin = PremCol + Col - 1
                        End If
                Else ' Colonne masquée ? fin de zone visible.
                    ' Fin de zone contiguë visible
                    If ColDept > 0 Then
                        ' Enregistre la zone visible détectée dans la collection
                        PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
                        ColDept = 0
                    End If
                End If
            Next Col
            ' Cas où la ligne se termine sur une colonne visible
            ' Ajouter la zone en fin de ligne
            If ColDept > 0 Then
                ' Stock la plage dans la collection
                PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
            End If
        End If
    Next Lig
    
    ' Retour de la fonction
    Set ReperePlageVisible_L950_V2_VarianteCellsTab = PlageVisible ' Cette collection contient l'ensemble des plages visibles.
End Function

' Exemple d'utilisation
Sub PlageVisible_V2()
    Dim Col As Collection
    Dim Rng As Range
    Dim Msg As String
'
    ' Fonction : Stocks toutes les cellules visibles dans la collection "Col"
    Set Col = ReperePlageVisible_L950_V2_VarianteCellsTab(ActiveSheet)
'
    If Col.Count = 0 Then
        MsgBox "Aucune cellule visible"
        Exit Sub
    End If
'
    Msg = "Cellule Visibles :" & vbCrLf
    For Each Rng In Col
        Msg = Msg & Rng.Address(0, 0) & vbCrLf
    Next Rng
'    MsgBox Msg
'
End Sub
 
Bonjour @Dudu2

Module_L950_V3_VarianteCellsTab

Code:
Option Explicit
Function ReperePlageVisible_L950_V3_VarianteCellsTab(Wks As Worksheet) As Collection
' Prend la feuille (active Wks) en paramètre
' Retourne la Collection contenant toutes les zones de cellules visibles :
'       - ligne par ligne
'
' Déclaration des variables
    Dim UniondRng As Range ' ................ Stocke le UsedRange de la feuille (zone réellement utilisée).
    Dim ColDept As Long ' ................... C'est la premiére colonne de la zone visible sur la ligne courante "UniondRng".
    Dim colFin As Long ' .................... C'est la derniere colonne de la zone visible sur la ligne courante "UniondRng".
    Dim PlageVisible As New Collection ' .... C'est cette Collection qui stock chaque UniondRng visible contigu par ligne.
    Dim Lig As Long ' ....................... C'est le Compteur des boucles des lignes
    Dim Col As Long ' ....................... C'est le Compteur des boucles des Colonnes
    Dim PremCol As Long ' ................... C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    Dim DerCol As Long ' .................... C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    On Error Resume Next ' .................. Au cas ou la feuille est vide ! (Sécurité d'une Gestion d'Erreur).
        Set UniondRng = Wks.UsedRange ' ..... Stocks (Toutes les plages de la feuille)
    On Error GoTo 0
'
    If UniondRng Is Nothing Then Exit Function ' ................. Fin de la VBA si aucune cellule remplis !
'
    PremCol = UniondRng.Columns(1).Column '......................  C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    DerCol = UniondRng.Columns(UniondRng.Columns.Count).Column ' . C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    ' Parcours toutes les lignes de "UniondRng" :
    ' Les lignes sans cellules non vides ne génèrent aucune plage.
    ' Exemple : Plage 1 (B6:B31) ' Lignes 6 à 31
    '         ' la ligne 5 Est totalement vide donc (pas prise en compte)
    '           Plage 2 (E2:E4) ' Ligne 2 à 4
    ' Parcours des lignes "UniondRng" soit : 2 à 4 (Plage 1) | La ligne 5 exclus | Puis de 6 à 31 (Plage 2)
    
    ' Stock les colonnes masquées (1 fois) dans la variable tableau
        Dim ColHidden() As Boolean
        Dim c As Long
            ReDim ColHidden(PremCol To DerCol)
                For c = PremCol To DerCol
                    ColHidden(c) = Wks.Columns(c).Hidden
                Next c
    
    Dim TabLig As Variant
    For Lig = UniondRng.Row To UniondRng.Row + UniondRng.Rows.Count - 1
        ' Boucle sur toutes les lignes utilisées.
        If Not Wks.Rows(Lig).Hidden Then ' Ignore les lignes masquées
            ColDept = 0 ' Réinitialisation : Colonne à 0.
            ' Optimisation 2 (VarianteCellsTab = Accées via une variable tableau 2D)
            ' Cette fois ci Précharger la ligne dans une variable tableau 2D (vraiment plus très rapide)
            ' Maintenant Excel n’est plus appelé cellule par cellule plus de Lecture pour une seule fois la valeur de la cellule "CelNotEmpty"
            ' Gains : Travailler en mémoire (VBA pur) décorrelé de la feuille excel.
                TabLig = Wks.Range(Wks.Cells(Lig, PremCol), Wks.Cells(Lig, DerCol)).Value
            ' Parcours colonne par colonne dans la ligne courante de "UniondRng" :.
            ' Exclus les Colonnes totalement vide.
            'For Col = PremCol To DerCol
            For Col = 1 To UBound(TabLig, 2)
                'Dim CelNotEmpty As Variant
                'CelNotEmpty = Wks.Cells(Lig, Col).Value
                'If Not Wks.Columns(Col).Hidden Then ' Ignore les Colonnes masquées
                'If Not Wks.Columns(PremCol + Col - 1).Hidden Then
                If Not ColHidden(PremCol + Col - 1) Then
                    ' Démarre ou étend une zone contiguë visible.
                    If ColDept = 0 Then
                       'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        'If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                        If TabLig(1, Col) <> Empty Then
                            'ColDept = Col ' Premiére Colonne de la plage "UniondRng"
                            ColDept = PremCol + Col - 1
                        End If
                    End If
                        'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        'If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                        If TabLig(1, Col) <> Empty Then
                            'colFin = Col  ' Derniére Colonne de la plage "UniondRng"
                            colFin = PremCol + Col - 1
                        End If
                Else ' Colonne masquée ? fin de zone visible.
                    ' Fin de zone contiguë visible
                    If ColDept > 0 Then
                        ' Enregistre la zone visible détectée dans la collection
                        PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
                        ColDept = 0
                    End If
                End If
            Next Col
            ' Cas où la ligne se termine sur une colonne visible
            ' Ajouter la zone en fin de ligne
            If ColDept > 0 Then
                ' Stock la plage dans la collection
                PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
            End If
        End If
    Next Lig
    
    ' Retour de la fonction
    Set ReperePlageVisible_L950_V3_VarianteCellsTab = PlageVisible ' Cette collection contient l'ensemble des plages visibles.
End Function

' Exemple d'utilisation
Sub PlageVisible_V3()
    Dim Col As Collection
    Dim Rng As Range
    Dim Msg As String
'
    ' Fonction : Stocks toutes les cellules visibles dans la collection "Col"
    Set Col = ReperePlageVisible_L950_V3_VarianteCellsTab(ActiveSheet)
'
    If Col.Count = 0 Then
        MsgBox "Aucune cellule visible"
        Exit Sub
    End If
'
    Msg = "Cellule Visibles :" & vbCrLf
    For Each Rng In Col
        Msg = Msg & Rng.Address(0, 0) & vbCrLf
    Next Rng
'    MsgBox Msg
'
End Sub
 
Bonjour @Dudu2

Module_L950_V4_VarianteCellsTab

Ps : c'est la version qui est la plus rapide.
Fonctionne sur 1 048 576 lignes et 16 384 colonnes (sans bloquée)
La version V4 est l'amélioration des versions V0 / V1 / V2 / V3 (Pour en comprendre la logique et l'évolution vers la V4)
Cela fait un bon exercice.

Code:
Option Explicit
Function ReperePlageVisible_L950_V4_VarianteCellsTab(Wks As Worksheet) As Collection
' Prend la feuille (active Wks) en paramètre
' Retourne la Collection contenant toutes les zones de cellules visibles :
'       - ligne par ligne
'
' Déclaration des variables
    Dim UniondRng As Range ' ................ Stocke le UsedRange de la feuille (zone réellement utilisée).
    Dim ColDept As Long ' ................... C'est la premiére colonne de la zone visible sur la ligne courante "UniondRng".
    Dim colFin As Long ' .................... C'est la derniere colonne de la zone visible sur la ligne courante "UniondRng".
    Dim PlageVisible As New Collection ' .... C'est cette Collection qui stock chaque UniondRng visible contigu par ligne.
    Dim Lig As Long ' ....................... C'est le Compteur des boucles des lignes
    Dim Col As Long ' ....................... C'est le Compteur des boucles des Colonnes
    Dim PremCol As Long ' ................... C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    Dim DerCol As Long ' .................... C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    On Error Resume Next ' .................. Au cas ou la feuille est vide ! (Sécurité d'une Gestion d'Erreur).
        Set UniondRng = Wks.UsedRange ' ..... Stocks (Toutes les plages de la feuille)
    On Error GoTo 0
'
    If UniondRng Is Nothing Then Exit Function ' ................. Fin de la VBA si aucune cellule remplis !
'
    PremCol = UniondRng.Columns(1).Column '......................  C'est le Bornage des colonnes (Preméire Colonne) utilisées dans cette feuille
    DerCol = UniondRng.Columns(UniondRng.Columns.Count).Column ' . C'est le Bornage des colonnes (Derniére Colonne) utilisées dans cette feuille
'
    ' Parcours toutes les lignes de "UniondRng" :
    ' Les lignes sans cellules non vides ne génèrent aucune plage.
    ' Exemple : Plage 1 (B6:B31) ' Lignes 6 à 31
    '         ' la ligne 5 Est totalement vide donc (pas prise en compte)
    '           Plage 2 (E2:E4) ' Ligne 2 à 4
    ' Parcours des lignes "UniondRng" soit : 2 à 4 (Plage 1) | La ligne 5 exclus | Puis de 6 à 31 (Plage 2)
    
    ' Stock les colonnes masquées (1 fois) dans la variable tableau
        Dim ColHidden() As Boolean
        Dim c As Long
            ReDim ColHidden(PremCol To DerCol)
                For c = PremCol To DerCol
                    ColHidden(c) = Wks.Columns(c).Hidden
                Next c
    Dim TabLig As Variant
    Dim RngLig As Range
    For Lig = UniondRng.Row To UniondRng.Row + UniondRng.Rows.Count - 1
        ' Boucle sur toutes les lignes utilisées.
        If Wks.Rows(Lig).Hidden Then GoTo LigneSuivante ' Ignore les lignes masquées
            ' Optimisation 4
            ' sert a tester si la ligne est totalement vide avec Application.CountA(LaVariable)
                Set RngLig = Wks.Range(Wks.Cells(Lig, PremCol), Wks.Cells(Lig, DerCol))
                If Application.CountA(RngLig) = 0 Then GoTo LigneSuivante
            ' Charge la ligne en mémoire (si contient au moins une valeur
                TabLig = RngLig.Value
                ColDept = 0 ' Réinitialisation : Colonne à 0.
            ' Parcours colonne par colonne dans la ligne courante de "UniondRng" :.
            ' Exclus les Colonnes totalement vide.
            'For Col = PremCol To DerCol
            For Col = 1 To UBound(TabLig, 2)
                'Dim CelNotEmpty As Variant
                'CelNotEmpty = Wks.Cells(Lig, Col).Value
                'If Not Wks.Columns(Col).Hidden Then ' Ignore les Colonnes masquées
                'If Not Wks.Columns(PremCol + Col - 1).Hidden Then
                If Not ColHidden(PremCol + Col - 1) Then
                    ' Démarre ou étend une zone contiguë visible.
                    If ColDept = 0 Then
                       'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        'If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                        'If TabLig(1, Col) <> Empty Then
                        If LenB(TabLig(1, Col)) <> 0 Then
                            'ColDept = Col ' Premiére Colonne de la plage "UniondRng"
                            ColDept = PremCol + Col - 1
                        End If
                    End If
                        'If Wks.Cells(Lig, Col) <> Empty Then ' Tester si cellule non vide.
                        'If CelNotEmpty <> Empty Then ' Tester si cellule non vide.
                        'If TabLig(1, Col) <> Empty Then
                        If LenB(TabLig(1, Col)) <> 0 Then
                            'colFin = Col  ' Derniére Colonne de la plage "UniondRng"
                            colFin = PremCol + Col - 1
                        End If
                Else ' Colonne masquée ? fin de zone visible.
                    ' Fin de zone contiguë visible
                    If ColDept > 0 Then
                        ' Enregistre la zone visible détectée dans la collection
                        PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
                        ColDept = 0
                    End If
                End If
            Next Col
            ' Cas où la ligne se termine sur une colonne visible
            ' Ajouter la zone en fin de ligne
            If ColDept > 0 Then
                ' Stock la plage dans la collection
                PlageVisible.Add Wks.Range(Wks.Cells(Lig, ColDept), Wks.Cells(Lig, colFin))
            End If
LigneSuivante:
    Next Lig
    
    ' Retour de la fonction
    Set ReperePlageVisible_L950_V4_VarianteCellsTab = PlageVisible ' Cette collection contient l'ensemble des plages visibles.
End Function

' Exemple d'utilisation
Sub PlageVisible_V4()
    Dim Col As Collection
    Dim Rng As Range
    Dim Msg As String
'
    ' Fonction : Stocks toutes les cellules visibles dans la collection "Col"
    Set Col = ReperePlageVisible_L950_V4_VarianteCellsTab(ActiveSheet)
'
    If Col.Count = 0 Then
        MsgBox "Aucune cellule visible"
        Exit Sub
    End If
'
    Msg = "Cellule Visibles :" & vbCrLf
    For Each Rng In Col
        Msg = Msg & Rng.Address(0, 0) & vbCrLf
    Next Rng
'    MsgBox Msg
'
End Sub
 
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

Réponses
5
Affichages
755
Réponses
2
Affichages
695
Réponses
5
Affichages
504
Réponses
4
Affichages
618
  • Question Question
Microsoft 365 Problème de date
Réponses
5
Affichages
293
Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…