Ajouter les boutons avec code VBA sur chaque ligne

Résolu
Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   -  
Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   -
Bonjour,

Voici ma macro :

Public i As Long
Public V As Long


Sub Macro1()

Dim DL As Long, Obj As Object, Code As String

DL = Cells(Application.Rows.Count, 1).End(xlUp).Row

For i = 1 To DL

'crée le bouton

With Range("K" & i)
    Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
    Link:=False, DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.ColumnWidth, Height:=.RowHeight)
    Obj.Name = "BoutonTest"
End With

V = i

'texte du bouton
    ActiveSheet.OLEObjects(1).Object.Caption = "OK"

'Le texte de la macro
    Code = "Sub BoutonTest_Click_Ligne_" & i & "()" & vbCrLf
    Code = Code & "Rows(V).Interior.Color = RGB(146, 208, 80)" & vbCrLf
    Code = Code & "End Sub"
'Ajoute la macro en fin de module feuille
    With ActiveWorkbook.VBProject.VBComponents(ActiveSheet.Name).CodeModule
        .insertlines .CountOfLines + 1, Code
    End With
    
Next i
End Sub


Les boutons se mettent bien sur chaque ligne. Mais ce qui m'embête, c'est que le code qui est censé colorer la ligne si je clique dessus ne marche pas...

2ème chose, le bouton ne fait pas la taille exacte de la cellule, alors qu'il en censé se redimensionner...

Et enfin une dernière question importante, est ce que si je met cette macro dans un bouton du ruban, elle pourra s'exécuter sur n'importe quel fichier excel vierge? Sinon comment est-ce possible?

Edit : Trouvé pour la question d'utiliser mes macros dans n'importe quel fichier. Merci à ce tuto : https://www.commentcamarche.net/faq/28980-creation-classeur-de-macros-personnalisees-2007

Merci d'avance.

Cordialement.

4 réponses

  1. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773
     
    Bonjour,

    La propriété ColumnsWidth n'utilises pas la même unité que la propriété Width. D'ou le décalage de tailles attendues...
    utilise donc :
        Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
        Link:=False, DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.Width, Height:=.RowHeight)


    Ensuite, tu nommes tous tes boutons de manière identique :
    Obj.Name = "BoutonTest"

    ET tu utilises un événement qui ne fonctionnera pas : _Click_Lignexx

    Regarde ce code :
    For i = 1 To DL
    
    'crée le bouton
    
    With Range("K" & i)
        Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
        Link:=False, DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.Width, Height:=.RowHeight)
        Obj.Name = "BoutonTest" & i
    End With
    
    'texte du bouton
        ActiveSheet.OLEObjects(1).Object.Caption = "OK"
    
    'Le texte de la macro
        Code = "Sub BoutonTest" & i & "_Click()" & vbCrLf
        Code = Code & "Rows(" & i & ").Interior.Color = RGB(146, 208, 80)" & vbCrLf
        Code = Code & "End Sub"
    'Ajoute la macro en fin de module feuille
        With ActiveWorkbook.VBProject.VBComponents(ActiveSheet.Name).CodeModule
            .insertlines .CountOfLines + 1, Code
        End With
        
    Next i


    Avant, j'arrivais jamais à finir mes phrases... mais maintenant je
    1
    1. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Ca marche beaucoup mieux merci ! Petite chose encore, quand j'ai plusieurs ligne, le premier bouton s'appelle "OK" mais les autres s'appellent CommandButton1, je comprend pas...
      0
    2. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773 > Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention  
       
      A la place de :
      With Range("K" & i)
          Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
          Link:=False, DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.ColumnWidth, Height:=.RowHeight)
          Obj.Name = "BoutonTest" & i
      End With
      
      texte du bouton
          ActiveSheet.OLEObjects(1).Object.Caption = "OK"


      Essaye :
      With Range("K" & i)
          Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
          Link:=False, DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.ColumnWidth, Height:=.RowHeight)
          Obj.Name = "BoutonTest" & i
      End With
      
      texte du bouton
          Obj.Object.Caption = "OK"
      0
    3. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Bravo belle maîtrise.

      Merci beaucoup. C'est vraiment sympa.

      Bonne soirée.
      0
    4. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Mais du coup je me demande quand même comment j'ai pu être assez stupide pour ne pas mettre directement :

      Code = Code & "Rows(" & i & ").Interior.Color = RGB(146, 208, 80)" & vbCrLf


      Il n'y avait besoin de rien d'autre...
      0
    5. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773 > Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention  
       
      Tu étais partie avec l'idée de construire ta macro grâce à une variable publique.
      Du coup cette idée t'es apparue comme LA bonne, et tu n'as pas cherché autre chose.
      ça m'arrive tout le temps.
      C'est à ça qu'aide, parfois, un second regard, généralement le lendemain...ou par un autre sur le forum ;-)
      A++
      0
  2. cs_Le Pivert Messages postés 8437 Statut Contributeur 730
     
    Bonjour,

    un petit salut a pijaku

    Pour faire ce que tu veux faire, il faut d'abord faire ton code pour qu'il soit opérationnel comme ceci:

    Sub BoutonTest1_Click()
    If BoutonTest1.Caption = "PAS OK" Then
    Rows(1).Interior.Color = RGB(146, 208, 80)
    BoutonTest1.Caption = "OK"
    Else
    Rows(1).Interior.Color = xlNone
    BoutonTest1.Caption = "PAS OK"
    End If
    End Sub


    après il suffit de le retranscrire comme cela:

    Option Explicit
    Public i As Long
    Public V As Long
    Sub Bouton1_Clic()
    Macro1
    End Sub
    Sub Macro1()
    Dim DL As Long, Obj As Object, Code As String
    
    DL = Cells(Application.Rows.Count, 1).End(xlUp).Row
    
    For i = 1 To DL
    
    'crée le bouton
    
    With Range("K" & i)
        Set Obj = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", _
        Link:=False, DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.ColumnWidth, Height:=.RowHeight)
        Obj.Name = "BoutonTest" & i
    End With
    
    'texte du bouton
        Obj.Object.Caption = "OK"
    'texte du bouton
        ActiveSheet.OLEObjects(1).Object.Caption = "OK"
    
    'Le texte de la macro
        Code = "Sub BoutonTest" & i & "_Click()" & vbCrLf
         Code = Code & "If BoutonTest" & i & ".Caption = ""PAS OK"" Then" & vbCrLf
        Code = Code & "Rows(" & i & ").Interior.Color = RGB(146, 208, 80)" & vbCrLf
        Code = Code & "BoutonTest" & i & ".Caption = ""OK""" & vbCrLf
        Code = Code & "Else" & vbCrLf
        Code = Code & "Rows(" & i & ").Interior.Color = xlNone" & vbCrLf
        Code = Code & "BoutonTest" & i & ".Caption = ""PAS OK""" & vbCrLf
        Code = Code & "End If" & vbCrLf
        Code = Code & "End Sub"
    'Ajoute la macro en fin de module feuille
        With ActiveWorkbook.VBProject.VBComponents(ActiveSheet.Name).CodeModule
            .insertlines .CountOfLines + 1, Code
        End With
        
    Next i
    End Sub


    Le plus dure c'est les double cote, mais quand tu as pigé ça va tout seul
    0
    1. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773
       
      Bonjour Le Pivert,

      Merci du coup de main.

      Personnellement, ce qui me gène dans ce genre de choses, c'est la multiplication des contrôles sur la feuille. En grand nombre, le fichier n'est plus stable et risque fort de planter définitivement avec perte des données...

      Pourquoi faire des boutons lorsqu'une simple MFC suffit à résoudre la chose?

      Il suffit en effet de saisir OK ou PAS OK en colonne K pour parvenir au même résultat.

      Je déconseille donc vivement la solution VBA dans ce sujet.

      Mais bon, ta macro résoud le problème posé ici.

      A++
      0
    2. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Super !

      Merci beaucoup, c'est exactement ce que je voulais. En plus, ça m'a permis d'apprendre pas mal de trucs !

      Juste une chose, voilà je me pose la question, sachant qu'en fait, je créé une macro qui sera utilisée par n'importe quel fichier excel donc dans PERSONAL.xlsb étant donné qu'elle doit être utilisable juste après une extraction de mon logiciel de gestion. Ma macro qui créé les boutons est intégrée à une macro qui fait plein de mises en forme.

      Seulement voilà, macro terminée. Ok tout est beau et mis en forme. Mais, par exemple il faut que l'utilisateur puisse supprimer une ligne ou en rajouter une si ça le chante. Si je supprime une ligne, je clique sur le bouton OK de la ligne d'en face, évidemment, c'est la ligne du dessous qui se colore en vert puisque i n'a pas changé dans le bouton. Un moyen de contrer cela?

      Comment je peux faire si l'utilisateur rajoute une ligne pour qu'un bouton se mette en face et ait la même fonction, c'est à dire de colorer la ligne si je clique sur OK?

      Merci d'avance.
      0
    3. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Vous pensez que si je déclare DL sur "ThisWorkbook" de PERSONAL.xlsb en public ça peut marcher?
      0
    4. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Laissez tomber, j'ai trouvé une autre solution. Merci.
      0
  3. cs_Le Pivert Messages postés 8437 Statut Contributeur 730
     
    Je crois que pijaku t'as donné la solution. Ca que tu veux faire, va ressembler à une usine à gaz. Tout est possible en vba, jusqu'à une certaine limite. Excel possède des outils natifs, il faut t'en servir!
    0
    1. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      C'est exact, c'était une usine à gaz. Du coup j'ai fais une coloration et un "OK" automatique dans ma colonne avec un bouton dans le ruban. Beaucoup plus simple. Beaucoup plus stable.
      0
    2. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      J'ai une dernière question (pardon d'abuser de vos connaissances), dans ma macro, j'ai une InputBox qui demande une date. Cette date sert à mettre à titre sur la ligne 1. J'ai une deuxième macro qui enregistre le fichier, est-ce que je peux me resservir de la valeur de l'InputBox pour donner un nom au fichier?
      0
      1. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773 > Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention  
         
        Si la variable qui stocke la réponse de l'InputBox est déclarée Public en entête d'un module standard, la réponse est oui.
        Attention toutefois, les / des dates ne sont pas forcément bons pour les noms de fichier sous Windows. Dans ce cas, utiliser la fonction Replace :
        Replace(mavar, "/", "")
        0
  4. cs_Le Pivert Messages postés 8437 Statut Contributeur 730
     
    en complément de pijaku, voici un exemple:

    Dim madate As Date
    madate = Application.InputBox("Entrez votre date", "Date", FormatDateTime(Date, vbShortDate), Type:=1)
    Range("A1").Value = madate
    

    0
    1. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773
       
      Salut,

      Ou plutôt :

      Public madate As Date
      
      Sub Macro1()
      madate = Application.InputBox("Entrez votre date", "Date", FormatDateTime(Date, vbShortDate), Type:=1)
      Range("A1").Value = madate
      End Sub
      
      Sub Macro2()
      'syntaxe SaveAs à vérifier...
      ThisWorkbook.SaveAs ThisWorkbook.Name & madate
      End Sub
      0
    2. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Dans ma macro, j'ai :

      Recommence:

      DATE_ECHEANCE = InputBox("Entrer la date d'échéance des factures concernées au format jj/mm/aaaa.", "Date d'échéance")
      
      If DATE_ECHEANCE = "" Then
      MsgBox ("Vous devez entrer une date d'échéance pour poursuivre le traitement.")
      GoTo Recommence
      End If
      
      If Not IsDate(DATE_ECHEANCE) Then
      MsgBox ("Le format entré n'est pas une date, entrer une date valide au format jj/mm/aaaa.")
      GoTo Recommence
      End If
      
      If DATE_ECHEANCE <> Format(DATE_ECHEANCE, "dd/mm/yyyy") Then
      MsgBox ("La date n'est pas au format jj/mm/aaaa, entrer un date au format jj/mm/aaaa.")
      GoTo Recommence
      End If


      Comment je dois faire si je déclare mon InputBox en public? Comment j'appelle mon Inputbox dans ma macro?

      J'imagine qu'intégrer un calendrier pour choisir la date est quelque chose de très complexe?
      0
    3. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773 > Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention  
       
      1- on va éviter les GoTo. Pourquoi? Cela donne un code pas très clair et difficile à maintenir.
      En plus, ça allonge le nombre de lignes de code...
      Essaye ceci :
      Do
      DATE_ECHEANCE = InputBox("Entrer la date d'échéance des factures concernées au format jj/mm/aaaa.", "Date d'échéance")
      Loop While DATE_ECHEANCE = "" Or Not IsDate(DATE_ECHEANCE) Or DATE_ECHEANCE <> Format(DATE_ECHEANCE, "dd/mm/yyyy")


      2- ce n'est pas ton InputBox que tu déclares, mais la variable qui en stocke le résultat. Donc DATE_ECHEANCE doit être déclarée comme public.
      En entête d'un module "standard" (premiéres lignes en haut du module, avant toute Sub ou Function), place cette ligne :
      Public DATE_ECHEANCE As String

      Ainsi, une fois que tu auras implémenté ta variable grâce au code donné précédemment, tu pourras t'en resservir partout dans le projet. Dans tous les modules, y compris le ThisWorkbook, les modules de feuilles, standards, partout quoi...

      3- Non, intégrer un calendrier n'est pas très compliqué. Tu en trouves de très bien fait sur le net qui ne demandent que l'insertion d'un module de classe.
      Si tu le souhaites, je peux tenter de t'en trouver un.
      0
    4. Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention   65
       
      Ah oui d'accord, je n'avais pas vu les choses comme ça. C'est vraiment super merci beaucoup pour les explications. Je ne suis qu'un débutant en VBA qui commence à me débrouiller sur certains trucs mais j'ai soif d'apprendre tout ce que je peux apprendre.

      Pour le calendrier, si tu ne considère pas ça comme de l'abus, je veux bien de l'aide. Les gens qui se serviront de mon fichier sont nombreux et j'avoue qu'un calendrier est le meilleur moyen d'être sûr d'avoir le format de date que je veux. En plus, ça a très clairement la classe.

      Merci encore 1000 fois pour tout ce que vous faites.
      0
    5. pijaku Messages postés 13513 Date d'inscription   Statut Modérateur Dernière intervention   2 773 > Kuartz Messages postés 852 Date d'inscription   Statut Membre Dernière intervention  
       
      Essaye ce fichier.
      Je travaillais dessus il y a quelques temps, il n'est pas fini, donc il peut encore y avoir des bugs.
      Si cela te convient, on peut essayer de le débugger pour toi et t'expliquer comment t'en servir.
      Le fichier

      Faudra juste ne pas être trop pressé...
      0