• Aucun résultat trouvé

Si la manipulation de ces propriétés en partant de la feuille est assez triviale, elle peut être un peu plus piégeuse lorsqu'on travaille sur des objets Range.

Pour les plages continues, ces propriétés renvoient un objet Range contenant toutes les cellules appartenant à la colonne ou à la ligne de l'objet Range d'où elles sont appelées. Un petit exemple est plus simple à comprendre.

Sub TestColRow()

Dim MaPlage As Range

Set MaPlage = ThisWorkbook.Worksheets("tableau").Range("C3:G30")

Debug.Print MaPlage.Columns(2).Address(False, False, xlA1)

'D3:D30

Debug.Print MaPlage.Rows(2).Address(False, False, xlA1)

'C4:G4

End Sub

Autrement dit, c'est un objet Range représentant l'intersection entre la ligne ou la colonne et l'objet Range. Attention, si la colonne ou la ligne n'appartiennent pas à l'objet Range, c'est une plage décalée qui va être renvoyée. Celle-ci sera alors l'intersection entre par exemple la ligne spécifiée et les colonnes de l'objet Range appelant. Par exemple :

Debug.Print MaPlage.Rows(31).Address(False, False, xlA1)

'C33:G33

Lorsqu'on souhaite obtenir une plage de colonnes ou de lignes continues, on passe un argument sous forme de texte précisant les colonnes (en lettres) ou les lignes (en chiffres). Attention, il s'agit d'une référence relative, c'est-à-dire que pour un objet Range "C3:G30", l'appel de la propriété Columns("B") renvoie "D3:D30".

Comme ces propriétés renvoient un objet Range, il est possible de les enchaîner :

Debug.Print MaPlage.Columns("A:C").Rows("2:8").Address(False, False, xlA1)

Dependents, DirectDependents, Precedents & DirectPrecedents

Ces propriétés sont assez complexes à manipuler. Elles sont issues de la notion de plages liées, c'est-à-dire de cellules étant des arguments de formule d'autres cellules. Par définition, une cellule dépendante est une cellule contenant une formule utilisant une autre cellule, une cellule précédente est une cellule dont la valeur est utilisée par la formule d'une autre cellule.

Les cellules sont directement précédentes ou dépendantes si leur relation est directe.

Pour bien comprendre ces principes, nous allons prendre comme exemple une feuille de dépouillement d'un étalonnage de voie d'acquisition.

On peut représenter cette feuille avec ses formules.

Les flèches représentent les dépendances telles qu'elles sont affichées par la barre d'audit. Nous allons visualiser ces dépendances par le code en modifiant le fond des cellules avec un code VBA, en prenant la cellule L32C3 (C32) comme cellule de référence.

N lons donc mettre en jaune les cellules précédentes, en rouge les cellules directement précédentes et en bleu clair les cellules dépendantes.

Sub AntecedentDependent()

ous al

Dim MaPlage As Range

On Error Resume Next

Set MaPlage = ThisWorkbook.Worksheets("Depend").Cells(32, 4)

MaPlage.Precedents.Interior.Color = vbYellow MaPlage.DirectPrecedents.Interior.Color = vbRed MaPlage.Dependents.Interior.Color = vbCyan On Error Goto 0

End Sub

Notez que je suis en mode "No Kill", c'est-à-dire que je me suis mis en mode de traitement d'erreurs immédiat sans pour autant traiter les erreurs. En effet, VBA va lever une erreur 1004 s'il n'y a pas de cellules antécédentes ou précédentes. En l'occurrence, il n'y a pas d'incidence à ne pas traiter l'erreur puisque nous cherchons juste à colorier des cellules le cas échéant.

Ce code nous donnera un résultat tel que :

Vous remarquerez qu'il faut évidemment colorier les cellules précédentes avant les cellules directement précédentes si vous voulez faire la différence entre les deux puisque par définition, l'objet renvoyé par la collection des cellules précédentes contient les cellules directement précédentes. Il en serait de même pour les cellules dépendantes.

Les cellules précédentes et dépendantes ne sont pas souvent manipulées. De fait, seul certains scénarii particuliers requièrent ce genre de programmation, le cas le plus connu étant la gestion contrôlée des calculs dans les feuilles denses.

Par exemple, le code suivant recalcule uniquement les cellules dépendantes d'une cellule modifiée.

Private Sub Worksheet_Change(ByVal Target As Range)

Static EnCours As Boolean

If EnCours Then Exit Sub

EnCours = True

On Error Resume Next

Target.DirectDependents.Calculate Do While Err.Number = 0

Set Target = Target.DirectDependents

Target.DirectDependents.Calculate

Loop

End

La propriété End renvoie la cellule de fin de zone d'une plage donnée. La notion de zone est assez simple à comprendre et assez complexe à employer. Une zone pour Excel, c'est une plage linéaire de cellules contenant des valeurs ou n'en contenant pas. Prenons la feuille exemple suivante :

Commençons par des cas simples

Sub TestEnd()

Dim MaPlage As Range

Set MaPlage = ThisWorkbook.Worksheets("End").Range("A1")

Debug.Print MaPlage.End(xlToRight).Address(False, False, xlA1)

'G1

Debug.Print MaPlage.End(xlDown).Address(False, False, xlA1)

'A29

Set MaPlage = ThisWorkbook.Worksheets("End").Range("C2")

Debug.Print MaPlage.End(xlToRight).Address(False, False, xlA1)

'F2

Debug.Print MaPlage.End(xlDown).Address(False, False, xlA1)

'C23

Set MaPlage = ThisWorkbook.Worksheets("End").Range("E1")

Debug.Print MaPlage.End(xlToRight).Address(False, False, xlA1)

'G1

Debug.Print MaPlage.End(xlDown).Address(False, False, xlA1)

'E2

Set MaPlage = ThisWorkbook.Worksheets("End").Range("G1")

Debug.Print MaPlage.End(xlToRight).Address(False, False, xlA1)

'IV1

Debug.Print MaPlage.End(xlDown).Address(False, False, xlA1)

'G65536

Ces exemples renvoient la cellule de fin de zone. Dans ce cas je fais la recherche en bas ou à droite, mais c'est équivalent en haut ou à gauche. Regardons les deux derniers exemples, lorsque G1 est la cellule de base. Dans les deux cas, c'est la dernière cellule de la feuille dans la direction de recherche qui est renvoyée. En effet, End ne renvoie jamais la cellule appelante comme cellule de fin de zone, dans ce cas, End cherche la fin de la zone suivante, la fin de la feuille en l'occurrence puisqu'il n'y a plus que des cellules vides. Pour bien comprendre ce fonctionnement, imaginons le code suivant :

Sub TestEnd1()

Dim MaPlage As Range, Message As String

Set MaPlage = ThisWorkbook.Worksheets("End").Range("E1")

Do

Set MaPlage = MaPlage.End(xlDown)

Message = Message & vbCrLf & MaPlage.Address(False, False, xlA1)

Loop Until MaPlage.Row = 65536 MsgBox Message

End Sub

Ce qui nous donnera :

Comme vous le voyez, les cellules renvoyées contiennent toujours une valeur à l'exception de la dernière, la recherche de fin de zone est donc bien basée sur les cellules ayant une valeur. Cette méthode End est souvent utilisée pour renvoyer des plages de valeurs continues sans avoir à connaître au préalable le nombre de cellule de la plage. Par exemple le code suivant renvoie la première colonne de valeur de la feuille :

With ThisWorkbook.Worksheets("End")

Set MaPlage = .Range(.Cells(1, 1), .Cells(1, 1).End(xlDown))

'on trouve parfois la notation

'Set MaPlage = .Range("A1", .Range("A1").End(xlDown))

End With

La recherche de la dernière cellule pour les développeurs VBA c'est un peu comme le Saint Graal pour les chevaliers de la table ronde. Je vous exposerai le problème et les solutions dans l'étude des techniques classiques.

EntireRow & EntireColumn

Renvoie la ou les colonnes (lignes) entières de la plage appelante.

Sub TestEntire()

Dim MaPlage As Range

Set MaPlage = ThisWorkbook.Worksheets("Tableau").Range("J1:N28")

Debug.Print MaPlage.EntireColumn.Address(False, False, xlA1)

'J:N

MergeArea

S'applique généralement sur une cellule. Renvoie la plage fusionnée si la cellule appartient à une plage fusionnée ou la cellule si tel n'est pas le cas. Ne confondez pas cette propriété qui renvoie une plage avec la propriété MergedCells qui renvoie vraie si la cellule fait partie d'une plage fusionnée.

Offset

Renvoie une plage décalée par rapport à la plage appelante. De la forme : Property Offset([RowOffset As Long], [ColumnOffset As Integer]) As Range

Où RowOffset est un entier long définissant le décalage de ligne et ColumnOffset est un entier définissant le décalage de colonne. Ces arguments suivent les règles :

¾ Si la valeur de l'argument est négative, le décalage aura lieu vers le haut pour les lignes et vers la gauche pour les colonnes.

¾ Si l'argument est positif, le décalage aura lieu vers le bas pour les lignes et vers la droite pour les colonnes.

¾ Si l'argument est nul ou omis il n'y aura pas de décalage

¾ Si le décalage demandé renvoie une ligne ou une colonne en dehors de l'intervalle de la feuille (1 à 65536 pour les lignes ; 1 à 256 pour les colonnes), une erreur sera levée. La plage renvoyée a le même nombre de lignes / colonnes que la plage appelante.

Le code suivant efface les cellules contenant la valeur 0 dans la plage "A2:G2000" de la feuille tableau.

Sub TestOffset()

Dim MaPlage As Range, cmptCol As Long, cmptLig As Long

Set MaPlage = ThisWorkbook.Worksheets("Tableau").Cells(2, 1)

For cmptLig = 0 To MaPlage.End(xlDown).Row - MaPlage.Row

For cmptCol = 0 To MaPlage.End(xlToRight).Column - MaPlage.Column

If MaPlage.Offset(cmptLig, cmptCol).Value = 0 Then

MaPlage.ClearContents

Next cmptCol

Next cmptLig

End Sub

Resize

Redimensionne un objet Range du nombre de colonnes / lignes passé en argument. De la forme: Property Resize([RowSize As Long], [ColumnSize As Integer]) As Range

Où RowSize est un entier long définissant le nombre de lignes et ColumnSize est un entier définissant le nombre de colonnes. Ces arguments sont forcément des valeurs positives ou sont omis, dans ce cas la plage n'est pas redimensionnée. Si la plage renvoyée n'est pas dans les limites admissibles de la feuille, une erreur sera levée.

En combinant cette propriété et la propriété Offset vue précédemment, il est possible de redéfinir n'importe quelle plage sur la feuille en partant d'une autre plage. Cette façon de travailler peut alors remplacer l'utilisation de plage fixe comme nous le verrons dans la discussion technique plus loin.

L'exemple suivant rempli la colonne moyenne de la feuille tableau.

Sub TestResize()

Dim MaPlage As Range, cmptLig As Long

Set MaPlage = ThisWorkbook.Worksheets("Tableau").Cells(2, 1)

MaPlage.Offset(, 6).Value = "Moyenne T1-T4"

'parcours la plage en ligne

For cmptLig = 1 To MaPlage.End(xlDown).Row - MaPlage.Row

MaPlage.Offset(cmptLig, 6).FormulaLocal = "=Moyenne(" &

MaPlage.Offset(cmptLig, 2).Resize(, 4).AddressLocal(True, True, xlR1C1) &

")"

Next cmptLig