web-dev-qa-db-fra.com

Comment boucler un tableau Excel 2010 en utilisant son nom et sa référence de colonne?

Depuis Excel 2010, j'utilise beaucoup de tableaux dans Excel. Par exemple, j'ai une table "tabWorkers" avec 3 colonnes: "ID", "Prénom", "Nom".

J'ai déjà découvert que je peux me référer à une table dans VBA en utilisant []. Par exemple:

Dim row As Range
For Each row In [tabWorkers].Rows
    MsgBox (row.Columns(2).Value)
Next

Cela me donnera le prénom de chaque ligne qui fonctionne très bien .. mais je veux le rendre plus dynamique en utilisant le nom de sa colonne comme ceci:

Dim row As Range
For Each row In [tabWorkers].Rows
    MsgBox (row.Columns("Firstname").Value)
Next

Bien sûr, je pourrais faire une sorte de recherche qui lie l'index de colonne '2' à un var comme FirstnameIndex, mais je veux la syntaxe correcte. Je suis sûr que c'est possible mais juste pas vraiment documenté (comme avec [tabWorkers] .Rows)

16
Tiele Declercq

Je ne connais pas très bien la méthode abrégée de référence aux tableaux. Si vous n'obtenez pas de réponse, vous pourriez trouver cette méthode longue, qui utilise le modèle ListOject, utile:

Sub ListTableColumnMembers()
Dim lo As Excel.ListObject
Dim ws As Excel.Worksheet
Dim lr As Excel.ListRow

Set ws = ThisWorkbook.Worksheets(2)
Set lo = ws.ListObjects("tabWorkers")

For Each lr In lo.ListRows
Debug.Print Intersect(lr.Range, lo.ListColumns("FirstName").Range).Value
Next lr
End Sub
18
Doug Glancy

essaye ça:

Dim row as Range
For Each row in [tabWorkers[first name]].Rows
     MsgBox row.Value
Next
8
Spencer Hutton

Moi aussi, j'ai réfléchi à cette question et cherché et cherché sans trouver une très bonne réponse

Enfin, aujourd'hui, le sou a chuté et j'ai trouvé quelque chose que je voudrais partager pour aider ceux qui suivent avec la même question qui me dérangeait.

En bref, la question était: comment référencer les lignes d'une table dans vba en utilisant les noms standard des parties d'une table. Cela s'avère assez facile. Vous pouvez vous référer à des lignes particulières du tableau et appeler les colonnes par leur vrai nom sans avoir à redéfinir d'autres variables.

La construction est la suivante: Range ("TableName [ColumnName]") (RowNumber)

où TableName et ColumnName sont les noms de table et de colonne standard d'Excelside et RowNumber est l'index entier simple du numéro de ligne de 1 à Range ("Table1"). Rows.Count

Pour une table à deux colonnes appelée Table1 avec des colonnes appelées ID et données, vous pouvez parcourir les éléments de table en utilisant cette construction

For Rw = 1 To Range("Table1").Rows.Count
     MsgBox(Range("Table1[ID]")(Rw) & "has value" & Range("Table1[Data]")(Rw)    )
Next Rw

Cela conserve des constructions très similaires à celles utilisées dans Excel et ne nécessite aucune dénomination supplémentaire. Et c'est tellement très lisible! Vous pouvez également ajouter les modificateurs de plage appropriés tels que .Text, .Value, .Formula etc. après cette partie (Rw) si nécessaire.

Notez que si vous avez une table à une seule ligne (par exemple pour les paramètres), ou si vous souhaitez vous référer à la première ligne d'une table plus grande, vous pouvez ignorer le bit (Rw) et utiliser directement la plage. Donc, une table appelée Params avec des colonnes appelées Couleur, Taille et Hauteur peut être référencée en utilisant Range ("Params [Color]") ou Range ("Params [Height]") etc. Vous n'aimez pas ça? :-)

Cette découverte m'a vraiment accroché aux tables. Ils me fournissent maintenant un lien très soigné entre vba et les feuilles de manière lisible et compatible.

Merci Microsoft!

Bob JordanB

7
user2092957

Plus concis, testé dans Excel 2007:

Dim row As Range
For Each row In [tabWorkers].Rows
    MsgBox Intersect (row,[tabWorkers[FirstName]]).Value
Next
3
Antoni Gual Via

Je le fais généralement comme ça

Dim rng as Range
Set rng = Application.Range("Tablename[Columnname]")

Vous devez uniquement faire référence au classeur car les noms de table sont uniques dans l'ensemble du classeur. Mais si vous avez des tables nommées de manière identique dans différents classeurs ouverts, cela affectera le classeur actif, pas les deux ou celui en arrière-plan. Pour éviter cela, vous devez appeler l'objet de plage de la feuille réelle dans laquelle réside votre table.

J'espère que cela montrera que cela peut être fait de la manière que j'ai décrite ci-dessus:

Par exemple, j'ai une méthode dans une base de données Access qui applique une mise en forme conditionnelle à une table dans un document Excel que je viens de créer et de remplir à l'aide de CopyFromRecordSet.

Qui a une signature de

Private Function HighlightBlankOrZeroColumn(RangeToFormat As Range, HighlightColor As Long)

et j'appelle comme ça

HighlightBlankOrZeroColumn ApXL.Range("Table1[" & SoucreRst.Fields(intCount).Name & "]"), BlankOrZeroColor

ApXL est un New Excel.Application et SoucreRst est un jeu d'enregistrements ADO.

À ce stade, j'avais déjà créé mon Recordset -> Range une table en appelant ces deux méthodes:

xlWSh.ListObjects.Add(xlSrcRange, xlWSh.UsedRange, , xlYes).Name = "Table1"
xlWSh.ListObjects("Table1").TableStyle = "TableStyleLight16"
3
Brad

Merci Doug! Cela a beaucoup aidé. un exemple de travail:

Dim row As Range
For Each row In [tabWorkers].Rows
    MsgBox (row.Columns(row.ListObject.ListColumns("Firstname").Index).Value)
Next
0
Tiele Declercq

C'est aussi mon premier post. Cela fait longtemps que la question n'a pas été posée, mais j'espère que cela sera de toute façon utile.

L'idée principale est de garder le morceau de code aussi propre que possible.

Set selrange = Selection.EntireRow

For Each rrow In selrange.Rows
        selrange.Parent.Parent.Names.Add "rrow", rrow
        name = [table1[name] rrow].Text
        age = [table1[age] rrow].Text
        gender = [table1[gender] rrow].Text
Next
selrange.Parent.Parent.Names("rrow").Delete
0
Ciro Rocha