[VBA] Calcul surface selon valeurs cellules

Bonsoir,

J'ai une grosse modification à apporter à mon document, pour laquelle je ne sais pas comment m'y prendre.

Fonctionnement de mon document :

Première feuille : Base de données

Feuille 2 ['B'] : Récupération des infos de la feuille 1 pour générer un tableau.

Feuille 3 [C] : Indication manuelle du nombre d'impacts qui va engendrer la création d'autant de lignes qu'il n'y a d'impact, pour chacune des lignes originelles, puis fusion des cellules des colonnes [A : E] et [J : M]. De cette manière, il n'y a un saut de ligne que pour les colonnes [F : I].

Lorsque j'ai 1 impact, j'ai su faire en sorte que dans la colonne F, un "1" s'affiche, suivi par la surface concernée impactée.

Mais, il faut que ce fonctionnement s'applique également pour 2, 3 , 4 etc. impacts (jusqu'à 10 (et si on peut ne pas mettre de limite c'est mieux).

Il faudrait alors que pour chaque ligne créée dans la colonne F, les cellules se remplissent automatiquement avec le n° de l'impact (1, 2, 3, 4, etc.) et avec la surface impactée.

Cette surface impactée est calculée comme suit :

  • Feuille 1, dans la colonne [AS] est indiquée une valeur.
  • Cette valeur c'est la surface occupée par chaque entité (colonne [AH])
  • Pour chacune de ces entités est indiqué un numéro d'impact (colonne [AT]) : Impact 1, Impact 2, Impact 3, etc.

Avec 1 impact, j'ai trouvé la démarche à suivre (tant bien que mal... mon code est disponible et vous allez pas aimer) ; en revanche, pour plus d'1 impact, je ne sais pas comment m'y prendre...

Vous auriez une idée ?

J'espère que c'est je suis assez explicite car c'est pas évident ! Autrement, je m'y reprendrai pour mieux décrire ce que je cherche à faire.

Merci de votre attention,

Bonne fin de journée !

A plus tard.

19partie-impacts.xlsm (118.24 Ko)

Bonsoir,

Pour simplifier les tâches, mon document créé désormais un nombre de ligne équivalent au nombre d'impacts précisés.

(Pour le moment ça marche sur le calcul du nombre de valeurs uniques présentes dans la feuille [A] colonne [AT].

Pour résumer ; voici les opérations réalisées par mon document :

Définition des variables, remplissages des premières colonnes de la feuille 2 ['B'] plus quelques traitements.

Dim ws As Worksheet, ws2 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Dim rng As Range, Cell As Range, rng2 As Range, Cell2 As Range, rng3 As Range, Cell3 As Range
Dim n As Long, n2 As Long, g As Long, m As Long, o As Long
Dim n3 As Long, n4 As Long, n4b As Long, n5 As Long, n6 As Long, lrs As Long
Dim nn3, nn4, nn4b As Long

    Application.ScreenUpdating = False
        'initialisation des variables
    Set ws = Worksheets("A")
    Set ws2 = Worksheets("B")
    Set ws3 = Worksheets("C")
    'Set ws4 = Worksheets("D")

'Nettoyer le tableau avant calculs
lrs = ws.Cells(Rows.Count, 34).End(xlUp).Row
Range(Cells(3, 1), Cells(lrs, 26)).EntireRow.Delete

'Nettoyer le second tableau
ws3.Activate
suppression
ws2.Activate

    With ws
        'dernière ligne non vide de la colonne AH (34)
        n = .Cells(.Rows.Count, 34).End(xlUp).Row   'AH
        'plage à copier sans l'en-tête de colonne
        Set rng = .Cells(2, 34).Resize(n - 1)
    End With

    With ws2
        'dernière ligne non vide de la colonne B (2)
        n2 = .Cells(.Rows.Count, 2).End(xlUp).Row + 1
        'cellule de destination de la copie de rng
        Set Cell = .Cells(n2, 2)
    End With

    rng.Copy Destination:=Cell

    With ws2
        'dernière ligne non vide de la colonne B (2)
        n2 = .Cells(.Rows.Count, 2).End(xlUp).Row   'B
        'plage de cellules avec en-tête pour supprimer les doublons
        Set rng = .Cells(2, 2).Resize(n2 - 1)
    End With

'suppression des doublons
    rng.RemoveDuplicates Columns:=1, Header:=xlYes

'Identifier la dernière ligne utilisée
    g = ws2.Cells(Rows.Count, 2).End(xlUp).Row

Puis, j'additionne les surfaces :

    ws2.Range(Cells(3, 4), Cells(g, 4)).numberformat = "#,##0.00"" ha"""
    ws2.Range(Cells(3, 4), Cells(g, 4)).FormulaR1C1 = _
        "=IF(SUMIF(A!R2C34:R2500C34,'B'!RC[-2],A!R2C45:R2500C45)=0,"" - "",SUMIF(A!R2C34:R2500C34,'B'!RC[-2],A!R2C45:R2500C45))"

Là, les pro du VBA voient probablement un souci ; l'utilisation d'une formule dans un code VBA (j'ai opté pour ce choix, ne sachant pas encore faire autrement).

La formule : SI(SOMME.SI(A!$AH$2:$AH$2500;B!B32;A!$AS$2:$AS$2500)=0;" - ";SOMME.SI(A!$AH$2:$AH$2500;B!B32;A!$AS$2:$AS$2500))

La première partie du code sert à dire : Si le résultat = "0" alors remplacer par "-".

Puis,

Je demande à faire la somme des surfaces (Feuille A ; colonne AS2 : AS2500), pour chaque valeur de la plage [Feuille A ; colonne AH] identique à la valeur indiquée dans la plage [Feuille B ; colonne A2 : A2500].

Si vous avez un code pour améliorer son fonctionnement et ne plus utiliser de formule je suis preneur.

'Recherche les données correspondantes
    ws2.Range(Cells(3, 5), Cells(g, 5)).FormulaR1C1 = _
        "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-3],A!R2C34:R2500C34,0),30)=0,"" - "",INDEX(A!R2C1:R2500C47,MATCH(RC[-3],A!R2C34:R2500C34,0),30))"

    ws2.Range(Cells(3, 6), Cells(g, 6)).FormulaR1C1 = _     "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-4],A!R2C34:R2500C34,0),29)=0,""-"",INDEX(A!R2C1:R2500C47,MATCH(RC[-4],A!R2C34:R2500C34,0),29))"

    ws2.Range(Cells(3, 7), Cells(g, 7)).FormulaR1C1 = _      "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-5],A!R2C34:R2500C34,0),31)=0,""-"",INDEX(A!R2C1:R2500C47,MATCH(RC[-5],A!R2C34:R2500C34,0),31))"

    ws2.Range(Cells(3, 8), Cells(g, 8)).FormulaR1C1 = _       "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-6],A!R2C34:R2500C34,0),36)=0,""-"",INDEX(A!R2C1:R2500C47,MATCH(RC[-6],A!R2C34:R2500C34,0),36))"

   ws2.Range(Cells(3, 9), Cells(g, 9)).FormulaR1C1 = _       "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-7],A!R2C34:R2500C34,0),35)=0,""-"",INDEX(A!R2C1:R2500C47,MATCH(RC[-7],A!R2C34:R2500C34,0),35))"

    ws2.Range(Cells(3, 10), Cells(g, 10)).FormulaR1C1 = _        "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-8],A!R2C34:R2500C34,0),37)=0,""-"",INDEX(A!R2C1:R2500C47,MATCH(RC[-8],A!R2C34:R2500C34,0),37))"
 

Toutes ces formules permettent de remplir la plupart des colonnes de la Feuille B à parti des informations de la feuille A.

Voici ce que donne la première formule :

=SI(INDEX(A!$A$2:$AU$2500;EQUIV(B3;A!$AH$2:$AH$2500;0);30)=0;" - ";INDEX(A!$A$2:$AU$2500;EQUIV(B3;A!$AH$2:$AH$2500;0);30))

La première partie du code sert à dire : Si le résultat = "0" alors remplacer par "-".

Puis,

J'indexe la plage de données [Feuille A ; colonne A2:AU2500] et demande à rechercher l'équivalent de la valeur [Feuille B ; Cellule B3] dans la plage de données [Feuille A : colonne AH2:AH2500] pour m'affiche en cellule E3 la valeur correspondante de la colonne n°30 (cad : [Feuille A colonne 30].

Là aussi je suis preneur si vous avez des solutions pour améliorer...

Suite...

La suite du code permet de gérer un peu toute la mise en forme pour m'assurer qu'elle ne bouge jamais.

 'Précise la police, la taille de police, l'alignement dans chaque cellule
    With Range(Cells(3, 3), Cells(g, 10)).Font
        .Name = "Calibri"
        .Size = 9
        .Bold = False
        .Italic = False
    End With

    With Range(Cells(2, 1), Cells(2, 10)).Font
    With Range(Cells(2, 2), Cells(g, 2)).Font
        .Name = "Calibri"
        .Size = 9
        .Bold = True
        .Italic = False
    End With
    End With

    With Range(Cells(2, 1), Cells(g, 10)).Cells
       .HorizontalAlignment = xlHAlignCenter 'soit :  xlHAlignCenter soit :  xlHAlignLeft soit : xlHAlignRight
       .VerticalAlignment = xlVAlignCenter 'soit  xlVAlignTop soit : xlVAlignCenter soit : xlVAlignBottom
    End With

 'Dimensionne le tableau pour qu'il s'intègre toujours au rapport
    Columns("A").ColumnWidth = 20.9
    Columns("B").ColumnWidth = 17.8
    Columns("C").ColumnWidth = 22.7
    Columns("D").ColumnWidth = 6.3
    Columns("E").ColumnWidth = 10.9

    Columns("F").ColumnWidth = 11.1
    Columns("G").ColumnWidth = 6.9
    Columns("H").ColumnWidth = 5.2
    Columns("I").ColumnWidth = 17
    Columns("J").ColumnWidth = 10.4

    Rows(2).RowHeight = 26.7

    For o = 3 To g
        p = Cells(o, 1).Row
        Range("A" & p).Rows.AutoFit
    Next

 'Renvoyer à la ligne automatiquement
    With Range(Cells(2, 2), Cells(g, 10)).Cells
        .VerticalAlignment = xlCenter
        .WrapText = True
        .Orientation = 0
        .AddIndent = False
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
    End With

'Applique des bordures noires autours des cellules
Dim bordures As Range
    For Each bordures In Range(Cells(2, 1), Cells(g, 10))
    If bordures <> "" Then bordures.Borders.Weight = xlThin
    If bordures = "" Then bordures.Borders.Weight = xlThin
    Next

 'Colore automatiquement les cellules
    Dim a As Integer

        For a = 3 To g
            If Cells(a, 10) = "Très fort" Then
                Range(Cells(a, 10), Cells(a, 10)).Interior.Color = RGB(192, 0, 0)
                Range(Cells(a, 10), Cells(a, 10)).Font.Color = RGB(255, 255, 255)
            Else
                If Cells(a, 10) = "Fort" Then
                Range(Cells(a, 10), Cells(a, 10)).Interior.Color = RGB(255, 0, 0)
                Range(Cells(a, 10), Cells(a, 10)).Font.Color = RGB(0, 0, 0)
                Else
                    If Cells(a, 10) = "Modéré" Then
                         Range(Cells(a, 10), Cells(a, 10)).Interior.Color = RGB(255, 192, 0)
                         Range(Cells(a, 10), Cells(a, 10)).Font.Color = RGB(0, 0, 0)
                    Else
                        If Cells(a, 10) = "Faible" Then
                            Range(Cells(a, 10), Cells(a, 10)).Interior.Color = RGB(255, 255, 153)
                            Range(Cells(a, 10), Cells(a, 10)).Font.Color = RGB(0, 0, 0)
                        Else
                            If Cells(a, 10) <> "Très fort" Then  'Or "Fort" Or "Modéré" Or "Faible"
                                Range(Cells(a, 10), Cells(a, 10)).Interior.Color = RGB(255, 255, 255)
                                Range(Cells(a, 10), Cells(a, 10)).Font.Color = RGB(0, 0, 0)
                            End If
                        End If
                    End If
                End If
            End If
        Next

'Ne conserver que les valeurs
'    Range(Cells(3, 4), Cells(g, 10)).Value = Range(Cells(3, 4), Cells(g, 10)).Value

'Classement des données dans l'ordre des enjeux + ordre des surfaces du + vers le -
    Application.AddCustomList ListArray:=Array("Très fort", "Fort", "Modéré", "Faible", "Très faible", "Nul", " - ")
    CustomOrder1 = Application.CustomListCount
    Range(Cells(2, 1), Cells(g, 10)).Sort _
    Key1:=Range(Cells(3, 10), Cells(g, 10)), OrderCustom:=CustomOrder1, _
    Key2:=Range(Cells(3, 4), Cells(g, 4)), Order2:=xlDescending, _
    Header:=xlYes, Orientation:=xlTopToBottom

Ensuite, je commence à remplir la Feuille C

'Remplissage feuille impacts
  With ws
        'dernière ligne non vide de la colonne AH (34)
        n3 = .Cells(.Rows.Count, 34).End(xlUp).Row   'AH
        'plage à copier sans l'en-tête de colonne
        Set rng2 = .Cells(2, 34).Resize(n3 - 1)
    End With

    With ws3
        'dernière ligne non vide de la colonne A (1)
        n4 = .Cells(.Rows.Count, 1).End(xlUp).Row + 2
        'cellule de destination de la copie de rng
        Set Cell2 = .Cells(n4, 1)
    End With

    rng2.Copy Destination:=Cell2

    With ws3
        'dernière ligne non vide de la colonne A (1)
        n4b = .Cells(.Rows.Count, 1).End(xlUp).Row   'B
        'plage de cellules avec en-tête pour supprimer les doublons
        Set rng2 = .Cells(1, 1).Resize(n4b - 1)
    End With

    n5 = ws3.Cells(Rows.Count, 1).End(xlUp).Row

    For h = 4 To n5
        ws3.Cells(h, 16).FormulaR1C1 = _
        "=IF(INDEX(A!R[-2]C1:R2500C47,MATCH(RC[-15],A!R[-2]C34:R2500C34,0),46)=0,""-"",INDEX(A!R[-2]C1:R2500C47,MATCH(RC[-15],A!R[-2]C34:R2500C34,0),46))"
    Next

La première partie du code est une autre méthode qui m'a été proposée sur ce forum et que je pourrai éventuellement reproduire pour remplacer une partie des formules ?

Ici, la formule fonctionne de la même façon que les précédentes.

Il y a également différents modules

modifvaleurs2
remdupli
sumdel
clecont
classauto
majhabs
modifvaleurs3
suppression2
style

Qui permettent de réaliser des opérations d'une feuille à l'autre.

Je vais parler de ceux qui me posent problème.

Tout d'abord j'utilise ce code :

Rappel : n5 = ws3.Cells(Rows.Count, 1).End(xlUp).Row

    For hb = 4 To n5
        ws3.Cells(hb, 5).FormulaR1C1 = _
            "=IF(SUMIF(A!R2C34:R2500C34,'C'!RC[-4],A!R2C45:R2500C45)=0,"" - "",SUMIF(A!R2C34:R2500C34,'C'!RC[-4],A!R2C45:R2500C45))"
        ws3.Cells(hb, 6).FormulaR1C1 = _
            "=IF(RC[10]=""Impact"",INDEX(A!R[-2]C1:R2500C47,MATCH(RC[-5],A!R[-2]C34:R2500C34,0),45),"" 0 "")"
        ws3.Cells(hb, 2).FormulaR1C1 = _ "=IF(INDEX(A!R2C1:R2500C47,MATCH(RC[-1],A!R2C34:R2500C34,0),37)=0,""-"",INDEX(A!R2C1:R2500C47,MATCH(RC[-1],A!R2C34:R2500C34,0),37))"
    Next

Pour les colonnes 5 [E] et 6 [F], de la Feuille C, j'applique des formules qui me permettent :

Colonne E : Calculer les somme des surfaces (Feuille A col AS) de chaque valeur inscrite en colonne A (feuille C)

> Ex. formule : =SI(SOMME.SI(A!$AH$2:$AH$2500;'C'!A4;A!$AS$2:$AS$2500)=0;" - ";SOMME.SI(A!$AH$2:$AH$2500;'C'!A4;A!$AS$2:$AS$2500))

Colonne F : Caculculer la somme des surfaces pour chaque valeur inscrite en colonne A impactée (l'impact est indiqué en feuille A, colonne AT) => Utiliser uniquement les surfaces pour lesquelles il est précisé "impact" en [Feuille A colonne AT]

> Ex. formule : =SI(P4="Impact";INDEX(A!$A2:$AU$2500;EQUIV(A4;A!$AH2:$AH$2500;0);45);" 0 ")

Là j'ai mon premier problème : Désormais, les impacts sont numéroté car il peut y en avoir plusieurs

impact 1 ; impact 2 ; impact 3 ; etc.

Cette formule ne permet donc plus de calculer les surfaces [Feuil A ; col 'AS'] touchées par chaque impact [Feuil A ; col 'AT'].

Auriez-vous une solution pour que : pour chacune des valeurs indiquées en Feuille A colonne 34 [AH], Excel calcule les surfaces [Feuil A ; col 'AS'] touchées par chaque impact [Feuil A ; col 'AT'] ?

suite...

En feuille C, pour chaque valeur en colonne A, un nombre de ligne est créé, équivalent au nombre d'impact présent en [Feuille A ; col AT].

Dans l'exemple, il y a 4 impacts, donc 4 lignes créées.

Pour ces 4 nouvelles lignes, j'aimerais que dans la [Feuille C colonne F] apparaissent les numéros des impacts (à savoir 1 (ligne 1), 2 (ligne 2), 3 (ligne 3) et 4 (ligne 4). Suivi (dans la même cellule), entre parenthèses, de la surface impactée (calculée précédemment*) et de la mention "ha".

1 (xx ha)

2 (xx ha)

3 (xx ha)

4 (xx ha)

*le calcul se faisant ainsi : Pour chaque valeur en [Feuille C ; colonne A] calculer les surfaces impactées [Feuille A ; col AS] pour impact 1, impact 2, impact 3, impact 4 [Feuille A ; col AT].

Un point compliqué est que ce nombre d'impact peut varier (min. 1, max. 9 ou +)

J'ai mis à jour mon document Excel, que je joins à ce post.

J'ai empêché l'exécution de certains modules, qu'on peut réactiver dans le code pour voir ce qu'ils font (beaucoup n'entrent pas en compte dans la résolution du problème).

nb_doublons
impacts

Permettent de compter le nombre de doublons et de créer, ainsi, le nombre de lignes adéquat.

Dès que je peux, je vais essayer d'épurer, encore davantage, le code, pour ne conserver que ce qui est utile dans la résolution du problème.

Je vous remercie de votre attention !

J'ai peut-être un peu trop détaillé... J'essaye de décrire le plus précisément possible mon problème et espère qu'une solution existe.

Bonne soirée !

Sujet résolu, arrêt de l'utilisation de formules dans du code VBA.

Résolu en utilisant des macros.

Rechercher des sujets similaires à "vba calcul surface valeurs"