UserForm, Tableau structuré VBA - Fil rouge

Bonjour,

J'ai entrevu quelque part une fonction à rallonge qui renvoie siun tableau structuré est vide, mais je n'ai pas noté.

Quelqu'un a-t-il ça dans ses notes ?

Merci

A+

Bonjour,

Peux-tu préciser la question ?

Cdlt.

Bonjour,

Je ne connais pas spécialement de fonction mais en VBA, il suffit de tester son nombre de lignes (ListRows.Count). Sil est égal à zéro, c'est que le tableau est vide.

Bonsoir,

thev : Ce n'est pas ce que je cherche. Voir ci-dessous.

Jean-Eric : En gros je cherche la manière la plus propre de détecter la ligne ou je dois écrire...

Dans un tableau structuré si le tableau n'est pas encore rempli avec des données .Rows.Count renvoie 1 et .end(xlUp) renvoie 2 que la première ligne de données soit remplie ou pas :

J'ai cru entrevoir une fonction dédiée (avec un nom à rallonge...) pour savoir si la première et unique ligne de données était vide ou pas.

Je suis assez capable de me recréer une fonction perso pour ça : Mais je cherche à savoir s'il existe une fonction ou une méthode particulière dédiée à ces tableaux structurés pour faire le boulot sans que je sois obligé de réinventer la roue...

A+

Re

Ci-dessous, ce que j'utilise pour déterminer la cellule (de destination) dans un tableau structuré.

Réponds je à ta question ?

Cdlt.

Option Explicit
'La propriété InsertRowRange retourne Nothing, lorsque la première ligne du tableau comporte des données.
'Si tel est le cas, on compte le nombre de lignes pour déterminer Cell. Sinon, Cell sera sur la première ligne (vide) du tableau.
Public Sub Galopin01()
Dim lo As ListObject, Cell As Range
    Set lo = ActiveSheet.ListObjects(1)
    With lo
        If .InsertRowRange Is Nothing Then
            Set Cell = .HeaderRowRange.Cells(1).Offset(.ListRows.Count + 1)
        Else
            Set Cell = .InsertRowRange.Cells(1)
        End If
    End With
End Sub

Dans un tableau structuré si le tableau n'est pas encore rempli avec des données .Rows.Count renvoie 1 et

A sa création, le tableau structuré n'est pas vide car il comporte une ligne., même si elle n'est pas remplie.

Personnellement, je rends toujours un tableau structuré vide soit en supprimant cette ligne soit manuellement, soit via VBA avec un DataBodyRange.Delete . Ce qui fait que le premier ListRows.Add ajoute bien la ligne 1 (beaucoup plus simple que de tester si la 1ére ligne est remplie ou non).

Sub remplissage()

    Dim tb_structuré As ListObject
    Dim ligne As ListRow
    Dim i As Long

    'assignation tableau et initialisation
    Set tb_structuré = ActiveSheet.ListObjects(1)
    If tb_structuré.ListRows.Count > 0 Then tb_structuré.DataBodyRange.Delete

    'remplissage tableau structuré
    With tb_structuré
        Set ligne = .ListRows.Add
        i = ligne.Index
        ............

    End With

End Sub

Jean-Eric : Oui ça doit être ce que l'avais entrevu et zappé.

thev : Il faudra que je me fasse la main sur TOUSSA pour en apprécier toutes les subtilités !

Merci à tous deux .

A+

Bonjour,

Utilisant majoritairement des tableaux structurés dans mes applications suite à leurs propriétés et à leur nécessité pour PowerQuery, j'apporte quelques précisions supplémentaires :

1- au niveau de sa création, on peut formater la ligne non remplie et y insérer des formules. Il faut savoir que le fait de rendre le tableau vide en supprimant cette ligne n'enlève ni le format ni les formules. Le premier Listrows.Add commencera à la ligne 1 et reprendra format et formules.

2- la restriction la plus importante sur les tableaux structurés est l'impossibilité de les utiliser dans un classeur partagé.

Très bien. Je te remercie.

Dans ces conditions la création d'un nom dans le Gestionnaire de Noms a-t-elle encore un sens (au point de vue de VBA) ?

A+

Dans ces conditions la création d'un nom dans le Gestionnaire de Noms a-t-elle encore un sens (au point de vue de VBA) ?

A priori non, car le tableau structuré crée un nom non modifiable relatif à l'ensemble des données (l'entête est exclu, = DataBodyRange en VBA). Ce nom est d'ailleurs tout simplement le nom du tableau.

Ce nom peut être utilisé dans le RowSource ou ListFillRange d'un contrôle ActiveX mais il ne le peut pas dans une liste de validation. Dans ce cas, je crée tout simplement un nom égal à celui créé automatiquement.

Ces 2 définitions sont équivalentes :

    Set plage = Range("Nom_tableau")
    Set plage = ActiveSheet.ListObjects("Nom_tableau").DataBodyRange

L'intérêt du nom créé est qu'il est de niveau classeur. Du coup, je l'utilise pour définir un tableau structuré par son nom sans référence à la feuille qui le supporte.

Set tableau = Range("Nom_tableau").Worksheet.ListObjects("Nom_tableau")

C'est ce que j'avais compris. Du coup je viens de découvrir qu'on pouvait appeler ListObjects par son nom et pas seulement par son index. (Ce qui est normal puisque Name comme index est une propriété de l'objet ListObject) et non pas de la collection ListObjects.

OK

Du coup cela m'amène à une autre question que je reposerai dans un moment :

Je renommerai ce fil Tableau structuré - Fil Rouge car je pense qu'il sera intéressant de regrouper de nombreuses routines applicables aux tableaux structurés dans le cadre de la confection d'un Userform.

Il faut d'abord que je prépare un classeur test.

A+

C'est effectivement une démarche intéressante car une fois bien maîtrisés les tableaux structurés offrent des fonctionnalités de recopie (format, formules) et de bornage des lignes / colonnes.

C'est la forme la plus proche de tables de base de données. C'est pourquoi ils sont indispensables dans PowerQuery et pour accès en lecture-mise à jour dans un classeur non ouvert.

Ils permettent aussi une bonne lisibilité et maintenance du code, en particulier via l'utilisation des entêtes de colonne.

Pfui...

Set tableau = Range("Nom_tableau").Worksheet.ListObjects("Nom_tableau")

C'est quoi cette suntaxe de malade !

Que viens faire le Worksheet dans cette ligne ?

EDIT : (inutile de répondre j'ai compris ! )

Bonjour à tous

Set tableau = Range("Nom_tableau").ListObject

Suffit il me semble

En fait .DataBodyRange.Delete ne supprime pas physiquement la première ligne : chez moi ça ne fait que la vider.

Bon ça c'est à peu près Ok, (sous réserve d'investigations plus poussés ultérieurement...) on va passer au plat de résistance :

Je n'arrive pas à initialiser ma ListBox :

Comment définir l'affichage des en-têtes

et le contenu .List

Voici le début du USerForm

Option Explicit

Dim rng As Range, TData As ListObject

Private Sub UserForm_Initialize()
'InitVar 'sans incidence sur la question
Set TData = Range("TData").Worksheet.ListObjects("TData")
Set rng = WsBD.ListObjects("TData").DataBodyRange 
InitListBox
End Sub

Private Sub InitListBox()
   With Me.lbData
     .ColumnHeads = True: .ColumnCount = 4: .ColumnWidths = "0;40;40;120"
'     .List = rng.Value ' plantage si rng est vide !
'     .ListIndex = 0
   End With
End Sub

En testant InsertRowRange j'arrive à afficher la Liste et à ne pas provoquer d'erreur quand elle est vide, mais je préfèrerai éviter de passer par un gestionnaire d'erreur pour une question aussi simple !

Quand au ;HeaderRowRange comment le faire digérer par ma ListBox (lbData)

A+

[EDIT:] Bonjour Chris : PAs eu le temps de vérifier.

Set tableau = Range("Nom_tableau").ListObject

C'est exact et beaucoup plus simple.

Merci Chris.

-- Annulé --

[@Galopin

En reprenant la remarque de Chris,

Option Explicit

Dim rng As Range, TData As ListObject

Private Sub UserForm_Initialize()
    'InitVar 'sans incidence sur la question
    Set TData = Range("TData").ListObject
    Set rng = TData.DataBodyRange
    InitListBox
End Sub

Private Sub InitListBox()
   With Me.lbData
     .ColumnHeads = False: .ColumnCount = 4: .ColumnWidths = "0;40;40;120"
    If TData.ListRows.Count > 0 Then .List = rng.Value
'     .ListIndex = 0
   End With
End Sub

Si tu charges ta ListBox à l'exécution, le ".ColumnHeads = True" ne fonctionne pas pour l'entête. Il ne fonctionne qu'avec la propriété RowSource. Comme ceci :

Private Sub InitListBox()
   With Me.lbData
     .ColumnHeads = True: .ColumnCount = 4: .ColumnWidths = "0;40;40;120"
     .RowSource = rng.Address
'     .ListIndex = 0
   End With
End Sub

Tu vas bien retrouver le titre de tes colonnes. Attention, si le contenu du RowSource change en cours d'exécution, Excel plantera !

Si tu veux retrouver les titres de colonne à l'exécution, tu peux utiliser une astuce qui consiste à créer une ListBox d'entête supplémentaire au-dessus de la première :

Private Sub InitListBox()

   With Me.lbData
     .ColumnHeads = False: .ColumnCount = 4: .ColumnWidths = "0;40;40;120"
     If TData.ListRows.Count > 0 Then .List = rng.Value
'     .ListIndex = 0
   End With
   With Me.lbHeader
     .ColumnHeads = False: .ColumnCount = Me.lbData.ColumnCount: .Width = Me.lbData.Width: .ColumnWidths = Me.lbData.ColumnWidths
     .List = TData.HeaderRowRange.Value
   End With

End Sub

Oui j'avais bien intégré la remarque de Chris mais comme je travaille sur 2 UserForm à la fois j'ai laissé passer la petite différence...

Ok pour le 2ème ListBox : ça me plait bien par contre le remplissage du lbData par Rowsource me chiffonne un peu : C'est quand m^me le but de la manoeuvre d'alimenter la base de donnée mais t'es en train de me dire que je peux pas faire un .ListRows.Add ? C'est un peu fort de café...

Donc j'adopte la solution N° 2.

Bon on va passer à la phase de test il faut que je nourrisse mes contrôles avec un ReadRecord et que je finalise mon WriteRecord.

Ça prend tournure.

Une bonne nuit en perspective ! C'est bon j'ai ma provision de Doliprane...

A+

par contre le remplissage du lbData par Rowsource me chiffonne un peu : C'est quand m^me le but de la manoeuvre d'alimenter la base de donnée mais t'es en train de me dire que je peux pas faire un .ListRows.Add ? C'est un peu fort de café...

Ben Oui. Un .ListRows.Add à partir d'un remplissage par RowSource va mettre Excel de très mauvaise humeur. Il va faire un gros, gros caprice.

Rechercher des sujets similaires à "userform tableau structure vba fil rouge"