1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
| Option Explicit ' Indexation de données de tableaux à en-têtes différentes
Public Const strTitleApp = "Table header indexer" ' by MattChess, August 10, 2011
' Type d'organisation selon la structure de chaque entête du tableau
Public Const header1Row_1Col As Byte = 1 ' Une Rangée d'en-tête * une Colonne d'en-tête
Public Const header1Row_2Col As Byte = header1Row_1Col + 1 ' Une Rangée * (Colonne principale + Colonnes secondaires)
Public Const header2Row_1Col As Byte = header1Row_2Col + 1 ' Deux Rangées d'en-tête * une Colonne d'en-tête
Public Const header2Row_2Col As Byte = header2Row_1Col + 1 ' Deux Rangées d'en-tête * deux Colonnes d'en-tête
' ... Décrire les autres organisations de structure de tableaux
Type TabType ' Type tableau = nom, organisation de l'en-tête, plage de cellules
Name As String ' Nom du tableau
TypeTab As Byte ' Type du tableau parmi header1Row_1Col, header1Row_2Col, ...
RngTab As Range ' Plage de cellules du tableau y compris les en-têtes
RngHeaderRow As Range ' Plage des en-têtes de rangées automatiquement calculée
RngHeaderCol As Range ' Plage des en-têtes de colonnes automatiquement calculée
RngHeaderCorner As Range ' Plage du coin supérieur gauche à l'intersection des en-têtes
End Type
' Clé d'indexation basée sur le nombre maximum de rangées et de colonnes d'un tableau
Const nbrMaxRow As Long = 10, nbrMaxCol As Long = 10 ' doivent être une puissance de la base 10
Public tabPeopleAgePlace As TabType, tabSimple As TabType ' Exemple de tableaux à structure différente
Sub TableHeaderIndexer() ' Point d'entrée de la maquette
' Colonne primaire "Nombre de personnes" au-dessus des colonnes secondaires "-20 ans", "20-60", "+60"
TabInit "Nbr Personnes dans Commune par Age", header1Row_2Col, Range("A1:D4"), tabPeopleAgePlace
' Autre tableau ayant une seule entête de colonne et de rangée
TabInit "Autre statistique", header1Row_1Col, Range("B6:E8"), tabSimple
End Sub
Sub TabInit(ByVal strName As String, ByVal typeOfTab As Byte, ByVal rngOfTab As Range, _
ByRef tableau As TabType) ' Initialise la structure d'un tableau, c-a-d sa description
With tableau
.Name = strName
.TypeTab = typeOfTab
Set .RngTab = rngOfTab
Set .RngHeaderRow = RangeHeaderRow(tableau)
Set .RngHeaderCol = RangeHeaderCol(tableau)
Set .RngHeaderCorner = RangeHeaderCorner(tableau)
End With
Debug.Print "La structure du tableau """ + tableau.Name + """ a été décrite."
End Sub
' Indexation de la cellule de la rangée indRow et de la colonne indCol dans le tableau
Function IdFromRowCol(ByVal indRow As Long, ByVal indCol As Long, tableau As TabType) As Long
Dim rngCell As Range
Set rngCell = Cells(indRow, indCol)
IdFromRowCol = IdFromCell(rngCell, tableau)
End Function
Function IdFromCell(ByVal rngCell As Range, tableau As TabType) As Long ' Indexation de cellule
Dim rngDataNoHeader As Range
IdFromCell = 0 ' Not found
If Intersect(tableau.RngTab, rngCell) Is Nothing Then Exit Function
Set rngDataNoHeader = RangeDataNoHeader(tableau)
If Intersect(rngDataNoHeader, rngCell) Is Nothing Then
IdFromCell = IdHeaderFromCell(rngCell, tableau) ' N° id dans en-tête
Else
IdFromCell = IdDataFromCell(rngCell, tableau) ' N° id dans donnée statistique
End If
End Function
Function IdHeaderFromCell(ByVal rngCell As Range, tableau As TabType) As Long ' Indexation d'en-tête
IdHeaderFromCell = 0 ' Cellule hors zone
With tableau
Select Case .TypeTab
Case header1Row_1Col
If Not Intersect(rngCell, .RngHeaderCorner) Is Nothing Then Exit Function ' Dans le coin supérieur gauche
If Intersect(rngCell, .RngHeaderCol) Is Nothing Then
IdHeaderFromCell = rngCell.Row - .RngHeaderRow.Row + 1 ' Unique rangée d'en-tête
Else
IdHeaderFromCell = rngCell.Column - .RngHeaderRow.Column ' Unique colonne d'en-tête
End If
Case header1Row_2Col
If Not Intersect(rngCell, .RngHeaderCorner) Is Nothing Then Exit Function ' Dans le coin supérieur gauche
If Intersect(rngCell, .RngHeaderCol) Is Nothing Then
IdHeaderFromCell = rngCell.Row - .RngHeaderRow.Row + 1 ' Unique rangée d'en-tête
ElseIf Intersect(rngCell, .RngTab.Rows(1)) Is Nothing Then
IdHeaderFromCell = rngCell.Column - .RngHeaderRow.Column ' Colonne secondaire d'en-tête
Else
IdHeaderFromCell = 1 ' Colonne primaire d'en-tête
End If
Case header2Row_1Col
IdHeaderFromCell = 0 ' Extraire le n° id selon la rangée et la colonne dans cet autre type d'organisation
Case header2Row_2Col
IdHeaderFromCell = 0 ' Idem
Case Else
Warning "1000: Type de tableau inconnu dans IdHeaderFromCell": Stop
End Select
End With
End Function
Function IdDataFromCell(ByVal rngCell As Range, tableau As TabType) As Long ' Indexation de donnée
Dim rngColSecondary As Range
IdDataFromCell = 0
With tableau
Select Case .TypeTab
Case header1Row_1Col ' indRow, indCol -> n° id rangée n° id colonne
IdDataFromCell = _
IdHeaderFromCell(.RngHeaderRow.Rows(rngCell.Row - .RngHeaderRow.Row + 1), tableau) * nbrMaxRow + _
IdHeaderFromCell(.RngHeaderCol.Columns(rngCell.Column - .RngHeaderCol.Column + 1), tableau)
Case header1Row_2Col ' indRow, indCol -> n° id colonne primaire n° id rangée n° id colonne secondaire
Set rngColSecondary = Intersect(.RngHeaderCol.Columns(rngCell.Column - .RngHeaderCol.Column + 1), _
.RngTab.Rows(2))
If rngColSecondary Is Nothing Then Exit Function
IdDataFromCell = _
IdHeaderFromCell(.RngHeaderCol.Columns(1), tableau) * nbrMaxRow * nbrMaxCol + _
IdHeaderFromCell(.RngHeaderRow.Rows(rngCell.Row - .RngHeaderRow.Row + 1), tableau) * nbrMaxRow + _
IdHeaderFromCell(rngColSecondary, tableau)
Case header2Row_1Col
IdDataFromCell = 0 ' Extraire le n° id selon la rangée et la colonne dans cet autre type d'organisation
Case header2Row_2Col
IdDataFromCell = 0 ' Ditto
Case Else
Warning "1100: Type de tableau inconnu dans IdDataFromCell": Stop
End Select
End With
End Function
Sub RowColFromId(ByVal idCell As Long, tableau As TabType, _
ByRef indRow As Long, ByRef indCol As Long)
Dim rngCell As Range
Set rngCell = RangeFromId(idCell, tableau)
If rngCell Is Nothing Then
indRow = 0: indCol = 0 ' idCell incorrect
Else
indRow = rngCell.Row
indCol = rngCell.Column
End If
End Sub
Function RangeFromId(ByVal idCell As Long, tableau As TabType) As Range
Const prodRowColMax As Long = nbrMaxRow * nbrMaxCol
Dim indRow As Integer, indCol As Integer, indColPrimary As Integer, indColSecondary As Integer
Set RangeFromId = Nothing
Select Case tableau.TypeTab
Case header1Row_1Col ' n° id rangée n° id colonne -> indRow, indCol
indRow = idCell \ nbrMaxRow + 1
If indRow <= 1 Then Exit Function
indCol = idCell Mod nbrMaxRow + 1
If indCol < 1 Then Exit Function
Set RangeFromId = tableau.RngTab.Cells(indRow, indCol)
Case header1Row_2Col ' n° id colonne primaire n° id rangée n° id colonne secondaire -> indRow, indCol
indColPrimary = idCell \ prodRowColMax
If indColPrimary <> 1 Then Exit Function
indRow = (idCell Mod prodRowColMax) \ nbrMaxRow + 2
If indRow <= 2 Then Exit Function
indColSecondary = idCell Mod nbrMaxRow + 1
If indColSecondary < 1 Then Exit Function
Set RangeFromId = tableau.RngTab.Cells(indRow, indColSecondary)
Case header2Row_1Col
Set RangeFromId = Nothing ' Extraire le n° de rangée de l'idCell dans cet autre type d'organisation
Case header2Row_2Col
Set RangeFromId = Nothing ' Idem
Case Else
Warning "1200: Type de tableau inconnu dans RangeFromId": Stop
End Select
End Function
Function RowFromId(ByVal idCell As Long, tableau As TabType) As Long
Dim rngCell As Range
Set rngCell = RangeFromId(idCell, tableau)
If rngCell Is Nothing Then
RowFromId = 0 ' idCell incorrect
Else
RowFromId = rngCell.Row
End If
End Function
Function ColFromId(ByVal idCell As Long, tableau As TabType) As Long
Dim rngCell As Range
Set rngCell = RangeFromId(idCell, tableau)
If rngCell Is Nothing Then
RowFromId = 0 ' idCell incorrect
Else
RowFromId = rngCell.Column
End If
End Function
Function RangeDataNoHeader(tableau As TabType) As Range ' Range utile des données hors en-tête
With tableau
Select Case tableau.TypeTab
Case header1Row_1Col
Set RangeDataNoHeader = Intersect(.RngTab, .RngTab.Offset(1, 1))
Case header1Row_2Col
Set RangeDataNoHeader = Intersect(.RngTab, .RngTab.Offset(2, 1))
Case header2Row_1Col
Set RangeDataNoHeader = Nothing
Case header2Row_2Col
Set RangeDataNoHeader = Nothing
Case Else
Warning "1300: Type de tableau inconnu dans RangeDataNoHeader": Stop
End Select
End With
End Function
Function RangeHeaderRow(tableau As TabType) As Range ' Zone d'en-tête de rangées
With tableau
Select Case .TypeTab
Case header1Row_1Col
Set RangeHeaderRow = Intersect(.RngTab.Columns(1), .RngTab.Offset(1, 0))
Case header1Row_2Col
Set RangeHeaderRow = Intersect(.RngTab.Columns(1), .RngTab.Offset(2, 0))
Case header2Row_1Col
Set RangeHeaderRow = Nothing
Case header2Row_2Col
Set RangeHeaderRow = Nothing
Case Else
Warning "1400: Type de tableau inconnu dans RangeHeaderRow": Stop
End Select
End With
End Function
Function RangeHeaderCol(tableau As TabType) As Range ' Zone d'en-tête de colonnes
With tableau
Select Case .TypeTab
Case header1Row_1Col
Set RangeHeaderCol = Intersect(.RngTab.Rows(1), .RngTab.Offset(0, 1))
Case header1Row_2Col
Set RangeHeaderCol = .RngTab.Range(Cells(1, 2), Cells(2, .RngTab.Columns.Count))
Case header2Row_1Col
Set RangeHeaderCol = Nothing
Case header2Row_2Col
Set RangeHeaderCol = Nothing
Case Else
Warning "1500: Type de tableau inconnu dans RangeHeaderCol": Stop
End Select
End With
End Function
Function RangeHeaderCorner(tableau As TabType) As Range ' Zone du coin supérieur gauche
With tableau
Select Case .TypeTab
Case header1Row_1Col
Set RangeHeaderCorner = .RngTab.Cells(1, 1)
Case header1Row_2Col
Set RangeHeaderCorner = .RngTab.Range(Cells(1, 1), Cells(2, 1))
Case header2Row_1Col
Set RangeHeaderCorner = Nothing
Case header2Row_2Col
Set RangeHeaderCorner = Nothing
Case Else
Warning "1600: Type de tableau inconnu dans RangeHeaderCorner": Stop
End Select
End With
End Function
Sub Warning(ByVal strMsg As String) ' Common error management
Const lenErr = 4 ' Number of digits of the error code beginning the message
If Err.Number <> 0 Then
strMsg = strMsg + vbCrLf + "Error " + Str(Err.Number) + ": " + Err.Description
End If
MsgBox Mid(strMsg, lenErr + 3), vbExclamation, strTitleApp + " warning " + Left(strMsg, lenErr)
End Sub |
Partager