Excel VBA créer UserForm création et UserForm de Modification
Dernière réponse : dans Programmation
Bonjour,
J'aurai besoin de la lumière de "ceux qui savent" pour réaliser un formulaire de saisie qui enverrai les données dans une liste.
Dans un premier temps j'ai réalisé (en partie merci internet !) ceci :
Ca marche mais la liste est créée dans le même classeur que les formulaires. Je voudrai (pour plus de souplesse) que la liste soit dans un autre classeur. En VBA j'ai compris que "ActiveSheet.Paste" colle dans le classeur actif dans la feuil2 le résultat de la saisie dans la feuil1. Par contre j'ai besoin de conserver (sous forme de feuilles) l'historique des saisies. Je suis donc limité à 256 feuilles (excel 2000).
J'ai réalisé cette autre macro - qui créee des feuilles avec les noms saisis dans une liste :
Comment pourrai-je intégrer ces 2 macros ?
Comment gérer plusieurs classeurs de formulaires (à cause de l'historisarion des données) ?
Je ne connais pas grand chose en VBA - mes macros sont perfectibles - si quelqu'un voudrai bien m'aider je l'en remercie par avance.
Cassivellaunos
J'aurai besoin de la lumière de "ceux qui savent" pour réaliser un formulaire de saisie qui enverrai les données dans une liste.
Dans un premier temps j'ai réalisé (en partie merci internet !) ceci :
Sub DerniereLigneVide()
'
' Sub DerniereLigneVide Macro
' Macro enregistrée le 28/07/2010 par Cassivellaunos
'
Dim Ligne As Integer
Application.ScreenUpdating = False
Range("A5:c5" ).Copy
Sheets("Feuil2" ).Select
Ligne = ActiveSheet.Range("A65536" ).End(xlUp).Row + 1
Range("A" & Ligne).Activate
ActiveSheet.Paste
Sheets("Feuil1" ).Select
Application.CutCopyMode = False
End Sub
Ca marche mais la liste est créée dans le même classeur que les formulaires. Je voudrai (pour plus de souplesse) que la liste soit dans un autre classeur. En VBA j'ai compris que "ActiveSheet.Paste" colle dans le classeur actif dans la feuil2 le résultat de la saisie dans la feuil1. Par contre j'ai besoin de conserver (sous forme de feuilles) l'historique des saisies. Je suis donc limité à 256 feuilles (excel 2000).
J'ai réalisé cette autre macro - qui créee des feuilles avec les noms saisis dans une liste :
Sub NommerFeuilles()
'
' NommerFeuilles Macro
' Macro enregistrée le 29/07/2010 par Cassivellaunos
'
'Selection de la 1er cellule de la colonne A
Range("A1" ).Select
Dim cpt As Integer
cpt = 1
Do
DoEvents
SendKeys "{Down}", True
A = A + 1
Sheets(A).Name = ActiveCell
'Si A = 12,
If A = 13 Then
cpt = cpt - 1
End If
Loop Until cpt = 0
On Error GoTo 1
1 MsgBox "Il est impossible de nommer la feuille" & A & ". Vérifier que le contenu de la cellule n' est pas nul."
End Sub
Comment pourrai-je intégrer ces 2 macros ?
Comment gérer plusieurs classeurs de formulaires (à cause de l'historisarion des données) ?
Je ne connais pas grand chose en VBA - mes macros sont perfectibles - si quelqu'un voudrai bien m'aider je l'en remercie par avance.
Cassivellaunos
Autres pages sur : excel vba creer userform creation userform modification
Lassé par la pub ? Créez un compte
Meilleure solution
Salut
Digression sur Worksheets
Un classeur possède une liste de ses feuilles. Cette liste s'appelle Worksheets (avec un s, donc) et c'est au sens VB, une collection. Pour accéder à une de ces feuilles, on précise soit le nom soit le numéro de la feuille dans la méthode Item :
Bon, comme cela alourdit énormément l'écriture, on a inventé les méthodes par défaut. Quand on ne précise rien, pour une collection, la méthode par défaut est Item. En plus, contextuellement, on se passe de préciser le classeur. Ça donne :
Comme Worksheets est une collection, on peut itérer dessus, c'est à dire parcourir ces éléments, on peut connaître le nombre d'éléments, etc. En VB, l'itération dans une collection se fait avec un For Each :
Il existe pleins d'autres collections, dont le nom est toujours au pluriel. Citons notamment Workbooks, la collection des classeurs ouverts dans Excel et Cells, la collection des cellules d'une feuille ou d'une zone de feuille.
Attardons-nous sur Cells.
Voici comment on désigne avec orthodoxie une cellule :
Voici la version raccourcie :
Range() renvoie une portion rectangulaire de feuille dont on précise deux coins opposés :
(Pour que l'exemple soit probant, mets quelque chose dans la cellule D3
)
Par ailleurs, Range() accepte comme paramètre, soit une cellule, soit une adresse de cellule.
Bon. un truc va nous simplifier la vie. Range() a Cells comme méthode par défaut. Donc on va pouvoir ne plus le préciser.
Et comme une cellule, ça reste une zone de cellules rectangulaire quand même :
Voici donc l'adresse de la cellule C2 :
C'est quand même bien souvent plus pratique, non ?
Au fait, comme Cells est une collection, et que Range().Cells = Range(), Range() se comporte comme une collection :
Il se trouve que le type de données Cell n'existe pas en VBA/Excel. Curieux, non ? Ce qui existe, c'est "plage de cellules". Et ça se dit Range. (A ne pas confondre avec Range())
Donc la ligne 1 du code précédent s'écrit :
Quoi, t'es tout embrouillé ?
T'avais qu'à pas me dire que tu lisais les messages jusqu'au bout
La suite
Parce que maintenant on passe à la suite.
Alors si je comprends bien, tu as une liste de noms de feuilles dans la colonne A, et tu voudrais renommer des feuilles. Facile.
Parcourons la colonne A.
Soit on en définit les bornes d'avance, soit on parcourt TOUTE la colonne, quitte à sortir en route.
A ces versions où on utilise des nombres, je préfère celles-ci, où on utilise des cellules :
Mais dans ton cas précis, on a besoin de gérer un compteur. Donc on va choisir une version avec entier :
Bon, ceci était pour reprendre ton code, qui ne correspond pas à la description de ce que tu veux faire.
Epilogue
A la lumière de ces très (trop ?) nombreux éléments, voudrais-tu reformuler ton besoin, et voire proposer un début de bout de code ?
Comme on a évoquer la collection Workbooks, gérer des cellules, des feuilles et donc même des classeurs ne devraient pas être si difficile
Digression sur Worksheets
Un classeur possède une liste de ses feuilles. Cette liste s'appelle Worksheets (avec un s, donc) et c'est au sens VB, une collection. Pour accéder à une de ces feuilles, on précise soit le nom soit le numéro de la feuille dans la méthode Item :
MsgBox "La feuille #1 s'appelle : " & ThisWorkbook.Worksheets.Item(1).Name
MsgBox "Le numéro de la feuille 'Feuil2' est : " & "ThisWorkbook.Worksheets.Item("Feuil2").Index
Bon, comme cela alourdit énormément l'écriture, on a inventé les méthodes par défaut. Quand on ne précise rien, pour une collection, la méthode par défaut est Item. En plus, contextuellement, on se passe de préciser le classeur. Ça donne :
MsgBox "La feuille #1 s'appelle : " & Worksheets(1).Name
MsgBox "Le numéro de la feuille 'Feuil2' est : " & "Worksheets("Feuil2").Index
Comme Worksheets est une collection, on peut itérer dessus, c'est à dire parcourir ces éléments, on peut connaître le nombre d'éléments, etc. En VB, l'itération dans une collection se fait avec un For Each :
Dim ws As Worksheet
MsgBox "Il y a " & Worksheets.Count & " feuille(s) dans ce classeur"
For Each ws In Worksheets
MsgBox "La feuille n°" & ws.Index & " se nomme '" & ws.Name & "'."
Next
Il existe pleins d'autres collections, dont le nom est toujours au pluriel. Citons notamment Workbooks, la collection des classeurs ouverts dans Excel et Cells, la collection des cellules d'une feuille ou d'une zone de feuille.
Attardons-nous sur Cells.
Voici comment on désigne avec orthodoxie une cellule :
Mouais.
Workbooks.Item("classeur1").Worksheets.Items("Feuil1").Cells.Item(1, 1)
Voici la version raccourcie :
. Si il n'y a pas de doute sur le classeur ou sur la feuille, on peut ne pas les préciser.
Workbooks("classeur1").Worksheets("Feuil1").Cells(1, 1)
Range() renvoie une portion rectangulaire de feuille dont on précise deux coins opposés :
Pour accéder aux cellules de cette zone, on utilise Cells, bien sûr :
MsgBox Range(Cells(2, 3), Cells(4, 5)).Address
Les deux premiers Cells sont relatifs à la feuille, le dernier, à la zone.
MsgBox Range(Cells(2, 3), Cells(4, 5)).Cells(2, 2).Value
(Pour que l'exemple soit probant, mets quelque chose dans la cellule D3
)Par ailleurs, Range() accepte comme paramètre, soit une cellule, soit une adresse de cellule.
MsgBox Range(Cells(2, 3), Cells(4, 5)).Cells.Address
MsgBox Range("C2", Cells(4, 5)).Cells.Address
MsgBox Range(Cells(2, 3), "E4").Cells.Address
MsgBox Range("C2", "E4").Cells.Address
MsgBox Range("C2:E4").Cells.Address
Bon. un truc va nous simplifier la vie. Range() a Cells comme méthode par défaut. Donc on va pouvoir ne plus le préciser.
MsgBox Range("C2:E4").Address
Et comme une cellule, ça reste une zone de cellules rectangulaire quand même :
MsgBox Range("C2").Address
Voici donc l'adresse de la cellule C2 :
MsgBox Cells(2, 3).Address
MsgBox Range("C2").Cells.Address
MsgBox Range("C2").Cells(1, 1).Address
MsgBox Range("C2").Address
C'est quand même bien souvent plus pratique, non ?
Au fait, comme Cells est une collection, et que Range().Cells = Range(), Range() se comporte comme une collection :
Dim cellule
For Each cellule In Range("A1:B3")
MsgBox cellule.Address
Next
Il se trouve que le type de données Cell n'existe pas en VBA/Excel. Curieux, non ? Ce qui existe, c'est "plage de cellules". Et ça se dit Range. (A ne pas confondre avec Range())
Donc la ligne 1 du code précédent s'écrit :
Dim cellule As Range
Quoi, t'es tout embrouillé ?
T'avais qu'à pas me dire que tu lisais les messages jusqu'au bout
La suite
Parce que maintenant on passe à la suite.
Alors si je comprends bien, tu as une liste de noms de feuilles dans la colonne A, et tu voudrais renommer des feuilles. Facile.
Parcourons la colonne A.
Soit on en définit les bornes d'avance, soit on parcourt TOUTE la colonne, quitte à sortir en route.
Dim i As Long ' // Un entier
' // Version longue
For i = 1 To 65536
....
Next
' // Version "on réfléchit avant"
Dim ligne_der As Long
ligne_der = Range("A65536" ).End(xlUp).Row
For i = 1 To ligne_der
...
Next
' // Version "on verra en allant"
For i = 1 To 65536
If Cells(i, 1).Value <> "" Then Exit For
....
Next
A ces versions où on utilise des nombres, je préfère celles-ci, où on utilise des cellules :
J'apprécie particulièrement la dernière version.
Dim c As Range ' // Une cellule
' // Version longue
For Each c In Rows(1)
....
Next
' // Version "on réfléchit avant"
Dim cellule_der As Range
cellule_der = Range("A65536" ).End(xlUp)
For Each c In Range ("A1", cellule_der)
...
Next
' // Version "on verra en allant"
For Each c In Rows(1)
If c.Value <> "" Then Exit For
....
Next
Mais dans ton cas précis, on a besoin de gérer un compteur. Donc on va choisir une version avec entier :
For i = 2 To 65536
If Cells(i, 1).Value <> "" Then Exit For
MsgBox "Feuille n°" & i & vbCrLf _
"Ancien nom : " & Worksheets(i).Name & vbCrLf _
"Nouveau nom : " & Cells(i, 1).Value
Worksheets(i).Name = Cells(i, 1).Value
Next
Bon, ceci était pour reprendre ton code, qui ne correspond pas à la description de ce que tu veux faire.
Epilogue
A la lumière de ces très (trop ?) nombreux éléments, voudrais-tu reformuler ton besoin, et voire proposer un début de bout de code ?
Comme on a évoquer la collection Workbooks, gérer des cellules, des feuilles et donc même des classeurs ne devraient pas être si difficile
Re-Salut
Beurk, quel code horrible. C'est si laid que je vais t'aider à ne plus recommencer des choses aussi moches.
Tout d'abord, il est interdit d'utiliser le presse-papier dans une macro bien pensée. Imagine que plusieurs macros travaillent en même temps. Où que d'autres programmes se permettent ce genre de choses. Quelle pagaille !
Donc revoyons ce bout de code qui marche et dont tu étais peut-être fier.
Les commentaires n'apportent rien. Soit on les vire, soit on en écrit des plus utiles.
Tu définies la variable Ligne. C'est TRES bien.
Tu retires la mise à jour en temps réel. Mouais. Ça, c'est un aveu d'impuissance. Attends un peu, ton programme n'en aura plus besoin. En passant, t'as oublié de remettre la valeur à Vrai.
Ligne 8, tu désignes une zone de cellules sans en préciser la feuille. Soit. Bon la copie par presse-papier c'est mal. On l'a déjà dit.
Ligne 9, tu changes de feuilles. C'est mal. Encore une fois, imaginons que deux macros tournent en même temps. On risque la pagaille !
Ligne 10, tu désignes une cellule en précisant la feuille. Ah bon. Ben pourquoi ?
Ligne 11, tu sélectionnes une cellule. C'est mal. Toujours un risque de pagaille ....
Ligne 12, bon, en espérant que personne n'ait changé la feuille ou la cellule active.
Eh, c'est facile de critiquer, non ?
D'abord, Voyons cette écriture :
De la même façon :
Qu'en penses-tu ?
Maintenant, relisons l'aide sur la méthode Copy de la ligne 8, telle qu'elle s'applique à un Range, donc :
Ah, et si on mettait dans la ligne 8, en destination, la cellule définit en ligne 11 :
Par principe, j'utilise Worksheet plutôt que Sheet. C'est plus précis. Demande à l'aide d'Excel pourquoi
Et il se trouve que Sheets("Feuil2" ).Range("A65536" ).End(xlUp) est une cellule dont on récupère la ligne pour en préciser une cellule qui est donc la même
...
Ça donne :
As-tu tout compris ?
Si oui, on passera à la suite ...
Beurk, quel code horrible. C'est si laid que je vais t'aider à ne plus recommencer des choses aussi moches.
Tout d'abord, il est interdit d'utiliser le presse-papier dans une macro bien pensée. Imagine que plusieurs macros travaillent en même temps. Où que d'autres programmes se permettent ce genre de choses. Quelle pagaille !
Donc revoyons ce bout de code qui marche et dont tu étais peut-être fier.
Sub DerniereLigneVide()
'
' Sub DerniereLigneVide Macro
' Macro enregistrée le 28/07/2010 par Cassivellaunos
'
Dim Ligne As Integer
Application.ScreenUpdating = False
Range("A5:c5" ).Copy
Sheets("Feuil2" ).Select
Ligne = ActiveSheet.Range("A65536" ).End(xlUp).Row + 1
Range("A" & Ligne).Activate
ActiveSheet.Paste
Sheets("Feuil1" ).Select
Application.CutCopyMode = False
End Sub
Les commentaires n'apportent rien. Soit on les vire, soit on en écrit des plus utiles.
Tu définies la variable Ligne. C'est TRES bien.
Tu retires la mise à jour en temps réel. Mouais. Ça, c'est un aveu d'impuissance. Attends un peu, ton programme n'en aura plus besoin. En passant, t'as oublié de remettre la valeur à Vrai.
Ligne 8, tu désignes une zone de cellules sans en préciser la feuille. Soit. Bon la copie par presse-papier c'est mal. On l'a déjà dit.
Ligne 9, tu changes de feuilles. C'est mal. Encore une fois, imaginons que deux macros tournent en même temps. On risque la pagaille !
Ligne 10, tu désignes une cellule en précisant la feuille. Ah bon. Ben pourquoi ?
Ligne 11, tu sélectionnes une cellule. C'est mal. Toujours un risque de pagaille ....
Ligne 12, bon, en espérant que personne n'ait changé la feuille ou la cellule active.
Eh, c'est facile de critiquer, non ?
D'abord, Voyons cette écriture :
Tu sélectionnes un truc pour ensuite de servir de ce qui est actif. Raccourcissons ça :
Sheets("Feuil2" ).Select
Ligne = ActiveSheet.Range("A65536" ).End(xlUp).Row + 1
N'est-ce pas plus simple ? En plus, c'est à l'abri de ce qui sélectionné ou pas. Plus de pagaille à craindre !
Ligne = Sheets("Feuil2" ).Range("A65536" ).End(xlUp).Row + 1
De la même façon :
' // Pas bien
Range("A" & Ligne).Activate
ActiveSheet.Paste
' // Bien
Range("A" & Ligne).Paste
' // Encore mieux
Sheets("Feuil2" ).Range("A" & Ligne).Paste
Qu'en penses-tu ?
Maintenant, relisons l'aide sur la méthode Copy de la ligne 8, telle qu'elle s'applique à un Range, donc :
Microsoft Visual Basic : AideCopy, méthode
Cette méthode copie la plage vers la plage spécifiée ou dans le Presse-papiers.
Destination Argument de type Variant facultatif. Spécifie la nouvelle plage dans laquelle la plage spécifiée sera copiée. Si vous ne spécifiez pas cet argument, Microsoft Excel copie la plage dans le Presse-papiers.
Cette méthode copie la plage vers la plage spécifiée ou dans le Presse-papiers.
expression.Copy(Destination)
expression Obligatoire. Expression qui renvoie un objet Range.Destination Argument de type Variant facultatif. Spécifie la nouvelle plage dans laquelle la plage spécifiée sera copiée. Si vous ne spécifiez pas cet argument, Microsoft Excel copie la plage dans le Presse-papiers.
Ah, et si on mettait dans la ligne 8, en destination, la cellule définit en ligne 11 :
N'est-ce pas vachement plus simple ?
Dim Ligne As Integer
Ligne = Sheets("Feuil2" ).Range("A65536" ).End(xlUp).Row + 1
Sheets("Feuil1" ).Range("A5:c5" ).Copy Sheets("Feuil2" ).Range("A" & Ligne)
Par principe, j'utilise Worksheet plutôt que Sheet. C'est plus précis. Demande à l'aide d'Excel pourquoi
Et il se trouve que Sheets("Feuil2" ).Range("A65536" ).End(xlUp) est une cellule dont on récupère la ligne pour en préciser une cellule qui est donc la même
...
Ça donne :
Sub DerniereLigneVide()
Worksheets("Feuil1" ).Range("A5:C5" ).Copy Worksheets("Feuil2" ).Range("A65536" ).End(xlUp)
End Sub
As-tu tout compris ?
Si oui, on passera à la suite ...
Merci Zeb,
Je dis merci puisque j'ai lu toutes tes remarques jusqu'au bout alors qu'en m'en tenant juste au début - je n'aurai pas froid cet hiver... cà c'est sûr !
J'avais précisé que mes macros étaient perfectibles - heureusement !
Je ne maîtrise pas très bien la notion de temps réel et de copy cette dernière étant plus habituelle pour moi mais bien moins logique quand on sait paramétrer dans la logique.
En ce qui concerne : Worksheet(s) représente uniquement les feuille de calcul, alors que Sheet(s) représente n'importe quelle feuille (calcul, graphique...).
par contre je me demande pourquoi tu as utilisé "Worksheets en nommant la feuille1 et non Worksheet puisque dans notre cas il n'y en a qu'une ? Qui peut le plus peut le moins peut-être ?
On peut passer à la suite quand tu voudras et encore merci pour cette approche très Pro.
Cassivellaunos
Je dis merci puisque j'ai lu toutes tes remarques jusqu'au bout alors qu'en m'en tenant juste au début - je n'aurai pas froid cet hiver... cà c'est sûr !
J'avais précisé que mes macros étaient perfectibles - heureusement !
Je ne maîtrise pas très bien la notion de temps réel et de copy cette dernière étant plus habituelle pour moi mais bien moins logique quand on sait paramétrer dans la logique.
En ce qui concerne : Worksheet(s) représente uniquement les feuille de calcul, alors que Sheet(s) représente n'importe quelle feuille (calcul, graphique...).
par contre je me demande pourquoi tu as utilisé "Worksheets en nommant la feuille1 et non Worksheet puisque dans notre cas il n'y en a qu'une ? Qui peut le plus peut le moins peut-être ?
On peut passer à la suite quand tu voudras et encore merci pour cette approche très Pro.
Cassivellaunos
zeb a dit :
Eh, non seulement t'as tout lu, mais en plus t'as tout compris et tu t'en es servi pour résoudre ton problème ? Ben c'est top !
Bonjour ZEB et mille mercis,
Non je n'ai pas tout compris
, non mon Pb n'est pas résolu
(loin de là) mais oui j'ai tout lu
!je pensais pouvoir le faire (userform) dans la foulée pendant mes vacances mais j'ai été appelé pour une mission urgente, d'où l'absence de réponse.
Je suis stupéfait de ta façon d'expliquer (didactique et pédagogique)! Je pense que je ne suis pas très doué car entre la lecture et l'écriture il y a un monde.
Je vais m'y remettre ce WE et je te tiens au courant. Ne m'en veux pas mais je suis un peu lent...
Encore merci pour tes explications.
Cassivellaunos
Lassé par la pub ? Créez un compte
- Contenus similaires :
- ForumExcel vba fermer userform
- ForumExcel vba userform textbox
- ForumExcel vba ouvrir userform
- ForumCréer un classeur excel vba
- ForumUserform emprunt excel vba
- ForumCréation feuille excel vba
- ForumCréer graphique excel vba
- ForumOutil userform excel vba
- ForumAffichage userform excel vba
- ForumUserform modification
- Voir plus