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:
Je vous propose ça, fait sur la nappe entre l'assiette à fromage et l'assiette à dessert...
Edit: puis modifié car pas si simple !
VB:
Sub a()
    MsgBox VisibleCells(ActiveSheet).Address(0, 0)
End Sub

'---------------------------------------------------------------------
'Remplace Cells.SpecialCells(xlCellTypeVisible) quand feuille protégée
'---------------------------------------------------------------------
Function VisibleCells(Worksheet As Worksheet) As Range
    Dim Range As Range
    Dim UsedRangeVisibleRows As Range, UsedRangeVisibleColumns As Range
    Dim WorksheetVisibleRows As Range, WorksheetVisibleColumns As Range
    Dim RowColHidden As Boolean
    Dim First As Long
    Dim i As Long
    
    'All Rows hidden
    With Worksheet.Rows(Rows.Count)
        If .Top + .Height = 0 Then Exit Function
    End With
    
    'All Columns hidden
    With Worksheet.Columns(Columns.Count)
        If .Left + .Width = 0 Then Exit Function
    End With
    
    'All hidden Rows & Columns are always inside the Worksheet.UsedRange (except for the 2 cases above)
    With Worksheet.UsedRange
        '----------
        'Check Rows
        '----------
        RowColHidden = False
        First = 1
      
        For i = 1 To .Rows.Count
            If .Rows(i).Hidden Then
                If Not RowColHidden Then
                    RowColHidden = True
                    If i > First Then Set UsedRangeVisibleRows = Réunion(UsedRangeVisibleRows, Worksheet.Rows(First).Resize(i - First))
                End If
            Else
                If RowColHidden Then
                    RowColHidden = False
                    First = i
                End If
            End If
        Next i
        If Not RowColHidden Then Set UsedRangeVisibleRows = Réunion(UsedRangeVisibleRows, Worksheet.Rows(First).Resize(i - First))
        If Not UsedRangeVisibleRows Is Nothing Then Set WorksheetVisibleRows = UsedRangeVisibleRows.Offset(.Row - 1)
      
        'Add non-UsedRange above Range
        If Not .Rows(1).Top = 0 Then
            If .Row > 1 Then
                Set WorksheetVisibleRows = Réunion(Worksheet.Rows(1).Resize(.Row - 1), WorksheetVisibleRows)
            End If
        End If
        
        'Add non-UsedRange below Range
        If Not Round(Worksheet.Rows(Rows.Count).Top + Worksheet.Rows(Rows.Count).Height, 4) = _
               Round(Worksheet.Rows(.Row + .Rows.Count - 1).Top + Worksheet.Rows(.Row + .Rows.Count - 1).Height, 4) Then
            If (.Row + .Rows.Count - 1) < Rows.Count Then
                Set WorksheetVisibleRows = Réunion(Worksheet.Rows(.Row + .Rows.Count).Resize(Rows.Count - (.Row + .Rows.Count - 1)), WorksheetVisibleRows)
            End If
        End If
    End With
      
    With ActiveSheet
        '-------------
        'Check Columns
        '-------------
        RowColHidden = False
        First = 1

        For i = 1 To Columns.Count
            If .Columns(i).Hidden Then
                If Not RowColHidden Then
                    RowColHidden = True
                    If i > First Then Set WorksheetVisibleColumns = Réunion(WorksheetVisibleColumns, Worksheet.Columns(First).Resize(, i - First))
                    'All the remaining columns are hidden ?
                    If .Columns(Columns.Count).Left + .Columns(Columns.Count).Width = .Columns(i).Left + .Columns(i).Width Then Exit For
                End If
            Else
                If RowColHidden Then
                    RowColHidden = False
                    First = i
                End If
            End If
        Next i
        If Not RowColHidden Then Set WorksheetVisibleColumns = Réunion(WorksheetVisibleColumns, Worksheet.Columns(First).Resize(, i - First))
    End With
  
    '------------
    'Return value
    '------------
    Set VisibleCells = Intersect(WorksheetVisibleRows, WorksheetVisibleColumns)
End Function

Private Function Réunion(Range1 As Range, Range2 As Range) As Range
    Select Case True
        Case Range1 Is Nothing And Range2 Is Nothing
            Set Réunion = Nothing
            
        Case Range1 Is Nothing
            Set Réunion = Range2
            
        Case Range2 Is Nothing
            Set Réunion = Range1
            
        Case Else
            Set Réunion = Union(Range1, Range2)
    End Select
End Function
 
Dernière édition:
VB:
Sub M_Dudu()
     Dim R     As Range, bEAA, bProtected

     bEAA = Application.EnableEvents
     If bEAA Then Application.EnableEvents = False     'éviter lancement des évenements
     With ActiveSheet
          bProtected = .ProtectContents
          If bProtected Then .Unprotect

          On Error Resume Next
          Set R = ActiveSheet.Cells.SpecialCells(xlCellTypeVisible)
          On Error GoTo 0

          If bProtected Then .Protect
     End With
     If bEAA Then Application.EnableEvents = True

     If R Is Nothing Then MsgBox "erreur" Else MsgBox R.Address

End Sub

PS specialcells ne fonctionne pas dans une fonction
 
Bonsoir @Dudu2😉, @bsalv😉, à tous les autres😀,

J'étais parti sur la même idée que @Dudu2 avec un code différent mais le même principe. Ce qui m'a ralenti c'est le fait qu'une feuille peut n'avoir aucune cellule visible (*). Je ne teste que les lignes et colonnes de la zone utilisée (plus rapide ? Je ne sais pas).

Dans le classeur , deux boutons pour deux tests :
  1. pour Feuil1 => des cellules sont visibles
  2. pour Feuil2 => aucune cellule visible
Le code de la fonction nommée RangeVisibleCells qui renvoie un range :
VB:
Function RangeVisibleCells(MyWorksheet As Worksheet) As Range
Dim dercol&, derlig&, i&, j&, Ri As Range, Rj As Range
   With MyWorksheet
         
      derlig = .UsedRange.Row + .UsedRange.Rows.Count - 1
      If derlig = 1 Then
         If .Rows(1).EntireRow.Hidden = True Then Exit Function Else Set Ri = .Rows(1)
      Else
         If derlig + 1 <= Rows.Count Then Set Ri = .Range(.Cells(derlig + 1, 1), .Cells(Rows.Count, 1)).EntireRow
         For i = 1 To derlig
            If Not .Rows(i).Hidden Then
               If Ri Is Nothing Then Set Ri = .Rows(i) Else Set Ri = Union(Ri, .Rows(i))
            End If
         Next i
      End If
      
      dercol = .UsedRange.Column + .UsedRange.Columns.Count - 1
      If dercol = 1 Then
         If .Columns(1).EntireColumn.Hidden = True Then Exit Function Else Set Ri = .Columns(1)
      Else
         If dercol + 1 <= Columns.Count Then Set Rj = .Range(.Cells(1, dercol + 1), .Cells(1, Columns.Count)).EntireColumn
         For j = 1 To dercol
            If Not .Columns(j).Hidden Then
               If Rj Is Nothing Then Set Rj = .Columns(j) Else Set Rj = Union(Rj, .Columns(j))
            End If
         Next j
      End If

     If Ri Is Nothing And Rj Is Nothing Then
         Exit Function
      ElseIf Ri Is Nothing Then
         Set RangeVisibleCells = Rj
      ElseIf Rj Is Nothing Then
         Set RangeVisibleCells = Ri
      Else
         Set RangeVisibleCells = Intersect(Ri, Rj)
      End If
   End With
End Function

Contrairement @Dudu2, je ne me suis pas encore sustenté, j'y vais de ce pas...
 

Pièces jointes

Dernière édition:
autre méthode peut-être plus fiable
Code:
Sub Test()
     MsgBox IIf(f_Visible(Sheets("Feuil1").Cells), "une/plusieurs ", "aucune ") & " cellule(s) visible(s)"
End Sub


Function f_Visible(Plage As Range)
     Dim c1 As Range, c2 As Range
     Set c1 = Plage.Find("*", lookat:=xlWhole)
     Set c2 = Plage.Cells.Find("", lookat:=xlWhole)
     f_Visible = Not c1 Is Nothing Or Not c2 Is Nothing
End Function
 
Bonjour @bsalv😉,
VB:
     i = Range("A1").End(xlDown).Row
     j = Range("A1").End(xlToRight).Column
     If i + j = 2 Then MsgBox "toutes les lignes et colonnes sont invisibles, (sauf A1 ???)"

Toutes les cellules peuvent être invisibles y compris A1.
En plus quelque chose d'insolite : Quand on sélectionne toutes les cellules pour les masquer :
  • si on clique droit sur les en-têtes de lignes pour les masquer, ce sont les toutes les lignes qui sont masquées et non pas les colonnes bien qu'on ne voit plus aucune cellule (Rows(1).hidden = True et Columns(1).hidden = False)
  • si on clique droit sur les en-têtes de colonnes, ce sont toutes les colonnes qui sont masquées et non pas les lignes bien qu'on ne voit plus aucune cellule (Rows(1).hidden = False et Columns(1).hidden = True)
Pour ton code j'ai testé :
Premier cas : j'ai masqué toutes les lignes
dans ce cas i = 1 et j = 16 384 donc i + j n'est pas égal à 2

Deuxième cas : j'ai masqué toutes les colonnes
dans ce cas i = 1 048 576 et j = 1 donc i + j n'est pas égal à 2
 
Dernière édition:
Re @bsalv😉,
C'est très intéressant🤓. Je l'ai donc testé. J'ai deux résultats différents suivant qu'on a masqué toutes les lignes ou bien qu'on a masqué toutes les colonnes.

Premier cas : On a masqué toutes les lignes
C1 vaut Nothing et C2 est Range("B1") donc f_Visible vaut True (résultat erroné)

Deuxième cas : On a masqué toutes les colonnes
C1 vaut Nothing et C2 vaut Nothing donc f_Visible vaut False (résultat juste)

Vba n'est pas toujours facile à cerner !!!
 
Bonjour @Dudu2😛,
Bonjour à vous,
@mapomme, comment fais-tu pour masquer toutes les cellules ?
Lorsque je clique sur le coin Regarde la pièce jointe 1225746 je n'ai pas d'option de masquage.
Je suis dans la même configuration que toi.

Je sélectionne toutes les cellules et ensuite deux manières de procéder de ma part :
  1. une fois toutes les cellules sélectionnées, cliquer-droit sur un en-tête de ligne et faire masquer (seuls les en-têtes de colonnes subsistent) mais plus aucune cellule n'est visible
  2. une fois toutes les cellules sélectionnées, cliquer-droit sur un en-tête de colonne et faire masquer (seuls les en-têtes de lignes subsistent) mais plus aucune cellule n'est visible
Visuellement c'est du kif-kif bourricot. Mais au sein de VBA c'est une autre histoire. Dans le premier cas, les lignes ont leur attribut Hidden à True et les colonnes ont leur attribut Hidden à False. Dans le second cas, c'est le contraire.
 
Dernière édition:
Re @Dudu2,

Et en plus quand toutes les lignes sont masquées, je n'arrive plus à les afficher, obligé de fermer le classeur sans enregistrer !

Une astuce pour tout réafficher sans enregistrer et perdre les modifications:
  • sélectionner la feuille concernée
  • passer sous éditeur VBA
  • afficher le fenêtre d'exécution (Ctrl+g)
  • Y coller l'instruction columns.hidden=false:rows.Hidden=false puis faire entrée. Fonctionne dans les deux cas (lignes masquées ou colonnes masquées). En fait si on voit les en-têtes de colonnes, Rows.Hidden = False suffit. Si on voit les en-têtes de lignes, Columns.Hidden = False suffit
 
Dernière édition:
- 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…