Questions sur listes deroulantes
bonsoir,
j'avance petit à petit!
1/j'ai fait les adaptations de code pour exploiter 2 userform (chacun dans une colonne différente.
mais ça fonctionne effectivement dès qu'on passe la souris sur la cellule ou dès qu'on clique dedans.
Je souhaiterais que ça se déclenche uniquement en cas de double-click.
2/ d'autre part je voudrais, dans une colonne donnée (H), (si chaque cellule de cette colonne est vide), y mettre automatiquement le contenu d'une cellule unique (A4) dès que je double-clique
j'ai adapté un bout de code :
Option Explicit
End Sub
mais où dois-je mettre ce code ?
dans la feuillet où se fera le traitement (ENCOURS) bien sur! mais comment l'exécuter ?
merci
cdt
sam
Bonjour Sam, bonjour le forum,
1. Je ne comprends pas que tu poses cette question puisqu'en 2 tu utilises exactement l'événementielle adapté : BeforeDoubleClick
Tu dois remplacer l'événementielle SelectionChange par celle-ci. Du coup, et ça répond à la question 2 l'événement ne se déclenchera plus lors du changement de sélection dans l'onglet mais lors du double-clic dans l'onglet. Et, j'ai répété deux fois dans l'onglet, pour répondre aussi à ta question 2. Tu dois le mettre le code dans l'onglet où tu veux qu'il agisse, en l'occurrence ENCOURS
2. Comment l'exécuter ? Mais en double-cliquant tout simplement !... Ces macros sont dites événementielles parce qu'elle réagissent automatiquement à des événements.
- SelectionChange s'exécute automatiquement quand tu changes la cellule active
- Change s'exécute automatiquement quand tu changes (édite, modifie, efface) une cellule
- BeforeDoubleClick... quand tu double-cliques dans une cellule
- Etc.
Ton problème va être de combiner l'ouverture des différentes UserForm avec le code (que je n'ai absolument pas compris).
Peut-être comme ça (à adapter) :
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) 'au double-clic dans l'onglet
'condition : si le double-clic a lieu dans la colonne 2 (=B) et dans une ligne supérieure à 5
If Target.Column = 2 And Target.Row > 5 Then
Cancel = True 'évite le mode [Édition] lié au double-clic
UserForm1.Show 'affiche l'UserForm1
End If 'fin de la condition
'condition : si le double-clic a lieu dans la colonne 3 (=C) et dans une ligne supérieure à 5
If Target.Column = 3 And Target.Row > 5 Then
Cancel = True 'évite le mode [Édition] lié au double-clic
UserForm2.Show 'affiche l'UserForm2
End If 'fin de la condition
'condition : si le double-clic a lieu dans la colonne 8 (=H) et dans une ligne supérieure à 5
If Target.Column = 8 And Target.Row > 5 Then
Cancel = True 'évite le mode [Édition] lié au double-clic
'condition 2 : si le nombre de valeurs dans la plage H6 à H_dernière_ligne est égal à zéro
If Application.WorksheetFunction.CountA(Range("H6:H" & Application.Rows.Count)) = 0 Then
Target.Value = Range("A4").Value 'renvoie la valeur de A4 dans la cellule double-cliquée
Target.Offset(1, 0).Select 'sélectionne la cellule en dessous (?)
End If 'fin de la condition 2
End If 'fin de la condition
End Subbonsoir thauthème,
j'ai un peu de mal à expliquer ce qui me gêne dans vba.
je n'ai aucun problème avec la "logique de construction d'un programme"
je suis loin de connaitre les instructions vba, mais avec la pratique ça va venir!
c'est la multiplicité des "sections" comme worksheet,click , doubleclick, selectionchange, module3 .....qui m'embrouille un peu !
Exemple dans le fichier joint sam-test (qui est un extrait de mon réel fichier d'origine)
1/je suis dans la "section" :
"Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)"
Dans le CAS = 3 qui pointe sur une liste chèques(col C) :
je voudrais conditionner ce cas si la col B = "D" (mais je ne sais pas comment nommer cette col B, à cet endroit du traitement !)
Et si cette col B est différente de "D" j'aimerai interdire l'accés à cette col C (si c'est possible)
2/si je choisis un chèque dans la fenêtre je souhaiterai évidemment le transférer dans la col C mais également le supprimer dans la liste de référence (onglet LISTES)
3/
ThauThème a écrit :'condition : si le double-clic a lieu dans la colonne 8 (=H) et dans une ligne supérieure à 5
If Target.Column = 8 And Target.Row > 5 Then
Cancel = True 'évite le mode [Édition] lié au double-clic
'condition 2 : si le nombre de valeurs dans la plage H6 à H_dernière_ligne est égal à zéro
If Application.WorksheetFunction.CountA(Range("H6:H" & Application.Rows.Count)) = 0 Then
Target.Value = Range("A4").Value 'renvoie la valeur de A4 dans la cellule double-cliquée
Target.Offset(1, 0).Select 'sélectionne la cellule en dessous (?)
End If 'fin de la condition 2
End If 'fin de la condition
End Sub
Dans cet partie de code , la condition 2 c'est cellule vide (soit zéro, soit "blanc" (rien)
Mais cette colonne 8 je souhaiterai qu'elle soit activée à partir d'un bouton "pointage"
ce n'est qu'à ce moment que je peux accéder à cette col H et avec un dbleclick renseigner les cellules avec A4.
(à condition que la cellule H soit vide.)
je n'ai pas su utilser le nom de la cellule adéquate :
target.column,... selection.cells,... range (h..) etc.. je ne comprends pas!
quand je lis du code je comprends à peu pres ce qu'il veut faire mais je ne sais pas expliquer pourquoi on utilisé Target.. plutot que Range ....etc
merci
Bonjour Sam, bonjour le forum,
Commençons par un petit récapitulatif des Composants VBA. Il y en a 5 seulement et après lecture de ce petit explicatif tu verras les choses d'un autre œil (enfin j'espère)...
1. ThisWorkbook
Il est listé dans la rubriques : Microsoft Excel Objects
Ce composant correspond au classeur entier. Il contient toutes les macro événementielles qui vont réagir dans tout le classeur. Dans l'éditeur VBA (Visual Basic Editor = VBE), sélectionne ce composant puis, dans la fenêtre de droite. Il y a deux champs : un champ [Objet] où par défaut est écrit (Général) et un champ [Procédure] ou par défaut est écrit (Déclarations).
Dans le premier champ [Objet], sélectionne Workbook. La procédure événementielle qui s'écrit alors par défaut est Open et elle s'affiche dans le champs [Procédure]. C'est ici que tu peux écrire un code qui s'exécutera à l'ouverture du classeur...
Regarde maintenant, dans le champ [Procédure], la liste des événements imputables au classeur . Il y en a une ch***e (comme on dit à Sète). Cela te permet d'avoir des codes qui réagissent automatiquement sur certaines actions dans le classeur entier.
2. Onglet
Ils sont listés dans la rubriques : Microsoft Excel Objects
C'est exactement le même principe que ThisWorkbook mais uniquement pour l'onglet sélectionné.
Inutile donc de spécifier le nom de l'onglet dans le code. Là aussi plein de possibilités d'automatiser des actions avec les nombreuses procédures événementielles.
3. UserForm
À l'insertion d'une première UserForm, une rubrique Feuilles est créée (c'est pas le nom le plus intelligent que MS a trouvé...). Elle listera, désormais, toutes les UserForms. Tout le code contenu dans ce composant est propre à l'Userform sélectionné.
4. Module
Ils sont listés dans la rubriques : Modules
On les appelle aussi modules Standard pour les différencier des modules de Classe (que je n'explique pas dans ce descriptif car je n'ai pas assez de connaissance dessus. C'est le numéro 5 de la liste).
Toute les macros générées via l'enregistreur de macro sont enregistrées dans des modules. Il n'est pas obligatoire d'enregistrer chaque macro dans un module différent (comme le fait souvent l'enregistreur) mais il peut être pratique de créer (et de nommer) les modules selon les types de macros pour les retrouver plus facilement.
Les variables déclarées publiques (c'est à dire qui gardent leur valeur dans tout le projet VBA) doivent impérativement être écrites en premières lignes (avant une macro) d'un module standard.
Dans le fichier Excel la combinaison de touches [Alt]+[F8] permet d'afficher toutes les macros contenues dans les différents modules la rubrique Modules. Il est tout à fait possible d'écrire une macro dans un autre composant qu'un module mais elle ne sera pas visible dans cette liste. Par exemple, je crée une procédure de tri que je nomme TriUSER que j'utilise dans une UserForm1, je la place dans le composant UserForm1 et elle n'apparait pas dans la liste des macros.
Voilà. Ce petit récapitulatif explique la structure des composants VBA. Il est important de savoir, quand on écrit un code, où il faut l'écrire pour qu'il soit le plus efficace...
Revenons maintenant à tes problèmes. Tu t'es un peu mélangé les pinceaux dans les CAS mais j'ai compris...
Dans les procédures événementielles comme Selection, SelectionChange, BeforeDoubleClick, BeforRightClick, etc. Donc toutes les procédure qui vont réagir à une action sur une cellule de l'onglet, Target (=cible) correspond à la cellule qui a été (soit sélectionné, soit éditée, soit double-cliquée ou soit cliquée du bouton droit).
c'est pour cela que le code :
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) 'au double-clic dans l'onglet
If Target.Column = 2 And Target.Row > 5 And Selection.Cells.Count = 1 Then 'pour table des codes transactions
CAS = 1: Cancel = True: UserForm1.Show
End If
End Subsignifie : si le double-clic a été effectué dans la colonne 2 (Target.Column = 2) dans une ligne supérieure à 5 (Traget.Row > 5).
Plus besoin de Selection.Cells.Count car le double-clic ne peut se faire que dans une seule cellule. J'avais écrit cela dans la procédure Change pour interdire le code si plusieurs cellules étaient sélectionnées.
Tu veux limiter dans le CAS = 2 (pas le CAS = 3 comme tu l'as écrit), l'ouverture de l'UserForm à la condition que la cellule en colonne B soit égale à "D". Puisqu'on sait que Target est la cellule double-cliquée, en colonne C. La cellule en colonne B est donc Target.Offset(0, -1) (Target. décalée d'une colonne à gauche). Le code devient :
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean) 'au double-clic dans l'onglet
'affiche l'UserForm1 si la cellule sélectionnée est seule,se trouve en col2/colB et col4/colD et dans une une ligne > 5
CAS = 0
If Target.Column = 2 And Target.Row > 5 Then 'pour table des codes transactions
CAS = 1: Cancel = True: UserForm1.Show
End If
If Target.Column = 3 And Target.Row > 5 Then 'pour table des chèques
If Target.Offset(0, -1) = "D" Then CAS = 2: Cancel = True: UserForm1.Show
End If
If Target.Column = 4 And Target.Row > 5 Then 'pour table des types
CAS = 3: Cancel = True: UserForm1.Show
End If
End SubPour le troisième et dernier point je suis désolé mais je n'ai pas compris... Je vois bien que le code proposé ne va pas mais tes explications doivent être plus détaillées. Il faut que tu me décrives les choses avant la macro et le résultat obtenus après celle-ci pour que je comprenne...
Observations :
Tu avais placé la macro événementielle BeforeClose dans le Module17. Elle ne pouvait donc pas fonctionner. Je l'ai déplacée pour la mettre dans le composant ThisWorkbook. Voir explications plus haut...
j'ai effacé un tas de modules vides et renommé les autres...
Chapeau pour l'unique UserForm à taille variable !...
bonjour thauthème,
d'abord un grand merci pour le temps et la patience que tu me consacres!
1/
ThauThème a écrit :Commençons par un petit récapitulatif des Composants VBA. Il y en a 5 seulement et après lecture de ce petit explicatif tu verras les choses d'un autre œil (enfin j'espère)..
je vais tâcher d'être à la hauteur, et je vais étudier avec attention ce récapitulatif que tu m'as concocté.
2/ j'ai pris bonne note pour "Selection.Cells.Count" par rapport au double-click!
3/ pour le cas 2, c'est dommage (pour moi!) car j'avais bien identifié "target.offset (0, -1)" mais je m'étais planté dans la syntaxe!
sinon ça marchait!
me reste à résoudre le fait que lorsque je choisi le 1er chèque de ma fenêtre déroulante, j'aimerai supprimé celui ci de la liste et tout remonter d'un cran.
4/ dans tes observations:
sam42 a écrit :Observations :
Tu avais placé la macro événementielle BeforeClose dans le Module17. Elle ne pouvait donc pas fonctionner. Je l'ai déplacée pour la mettre dans le composant ThisWorkbook.
je ne sais absolument pas d'où vient ce bout de code ni ce qu'il représente ni à quoi il sert !
je n'ai jamais rien stocké dans les modules, sauf le module 3 à ta demande pour y stocker la variable CAS!
J'avais remarqué que je "trimbalais" une série de modules dont beaucoup étaient vides et certains contenaient des macros que j'avais faites et qui me sont nécessaires encore. Mais ce n'est pas moi qui les y ai stockées! c'est le générateur de macros probablement!
dois-je le supprimer ?
5/
sam42 a écrit :Chapeau pour l'unique UserForm à taille variable !...
Comme tu m'avais suggéré qu'il était possible de s'en sortir avec un seul userform, j'ai fait ça ! j'ai tâtonné mais j'y suis parvenu.
Mais peut-être qu'il était plus simple, plus clair ... de faire plusieurs userforms ?
6/ quant au dernier point j'aimerai, à partir d'un bouton "pointage", avoir la possibilité suivante :
à chaque fois que je double-click sur une cellule de mon choix (dans la colonne H exclusivement et à condition qu'il n'y ait rien dans cette cellule - ni du texte, ni des nombres), avoir le contenu de la cellule A4.
J'imagine alors, que dès l'instant où j'ai appuyé sur le bouton "Pointage" ET que je reste dans la colonne H, je suis toujours dans le cadre de la macro! Par contre si je quitte la colonne H, je sors de la macro et je reprends le cours de "mon travail" sur ma feuille comme avant la macro. C'est LA façon de mettre un terme à la macro ?!
En clair, la macro m'autorisera à inscrire le contenu de A4 à chaque double-click sur les cellules ( de colH) que j'aurais choisies.
Si je ne suis pas dans la macro et que je suis dans une cellule de la colonne H, je peux faire ce que je veux (même si je double-click)!
Est-ce que je suis clair ?
cdlt
sam
Re,
3/ me reste à résoudre le fait que lorsque je choisi le 1er chèque de ma fenêtre déroulante, j'aimerai supprimé celui ci de la liste et tout remonter d'un cran.
Essaie comme ça (dans la procédure Click de la ListBox1) :
If CAS = 2 Then '------- pour table des chèques
'renvoie dans la cellule active ENCOURS/C la valeur de la colonne 0 (chèque) de la listbox1
ActiveCell.Value = .Column(0, .ListIndex)
Sheets("LISTES").Columns(1).Find(Me.ListBox1.Column(0, Me.ListBox1.ListIndex), , xlValues, xlWhole).Delete shift:=xlShiftUp
End If4/ Je te conseille de supprimer tous les modules vides ainsi que le Module17 avec le code BeforeClose... Quand tu utilises l'enregistreur de macros pour des tests pense à supprimer de suite l'inutile...
6/ Désolé mais toujours pas clair !... On ne peut pas mélanger macro événementielle (donc automatique) et CommandButton (donc manuel). Je ne comprends ni l'intérêt de ton procédé ni ce que tu veux faire exactement. Quand tu dis je sors de la macro, je ne sais pas de quelle macro tu parles. Celle du bouton ou la macro événementielle du double-clic ?
Est-ce que le bouton pointage aurait pour but d'afficher la colonne H (qui pourrait être masquée par défaut) ?
Il faut vraiment que tu me détailles pas à pas ce que tu désires car j'ai beau lire et relire je ne comprends pas. Bon, c'est vrai que je suis un peu c** sur les bords, je te l'accorde...
bonjour tauthème,
1-
ThauThème a écrit :Sheets("LISTES").Columns(1).Find(Me.ListBox1.Column(0, Me.ListBox1.ListIndex), , xlValues, xlWhole).Delete shift:=xlShiftUp
celle-là il fallait la sortir !!!
il me faudra des années pour "accoucher" d'une instruction comme ça !!
2- pour mon problème que tu n'as pas compris :
plus j'y réfléchis et plus je me dis que le jeu ne vaut pas la chandelle : compliqué à résoudre pour un gain dérisoire !!
donc j'abandonne! Mais, histoire de ne pas tout abandonner :
Je vais simplement garder le fait que lorsque que je double-click sur les cellules de la colonne H, je veux avoir automatiquement dans cette cellule, le contenu de A4, à condition que la cellule destination soit vide (ni alpha ni numerique)
3- pour le reste je veillerais à suivre tes recommandations : modules vides ....
merci encore
cdlt
sam
re,
1 -
je viens de coder :
If Target.Column = 8 And Target.Row > 5 Then 'si le double-clic dans col 8/H (notif) et dans une ligne supérieure à 5
If Target.Offset(0, 3) <> 0 Then 'si 3eme cellule à dte (col K = montant) de la même ligne est <> 0
If Target = "" Then ' si la cellule est vide
Cancel = True
Target.Value = Range("A4").Value 'renvoie la valeur de A4 dans la cellule double-cliquée
End If
End If
End Ifça fonctionne ! on peut faire mieux ? (la target active si vide c'est bon ?)
2 -
je viens de me rendre compte que dans l'arboresence de vba project (la partie à gauche)
tout était rattaché à la "racine" : les feuilles ENCOURS HISTO... de même que les modules et le userform1
alors qu'ils étaient rattachés d'abord à "feuilles" (pour le userform1) et à "module" pour tous les modules lesquels répertoire "feuilles" et "module" étaient eux-mêmes rattachés à la racine.
est-ce normal ? est-ce génant ?
sam
ps je viens de passer sous office 2016
le petit souci signalé en (2) a disparu. tout semble normal
Re Sam
On peut simplifier avec :
If Target.Column = 8 And Target.Row > 5 Then
If Target.Value = "" And Target.Offset(0, 3).Value <> 0 Then
Cancel = True
Target.Value = Range("A4").Value
End If
End IfMais le principe était très bien...
bonjour thauthème,
il y a quelque chose que je ne comprends pas dans le fichier joint.
Dans l'onglet ENCOURS, il y a 2 cellules C4 et D4 qui contiennent le même montant (visuellement)
La macro "TRANSFERT" que tu trouveras, répond par une inégalité alors que ces 2 cellules sont égales !!!
De plus quand j'y mets la valeur 10 dans chacune des 2 ça marche!
Mais quand c'est l'appli qui valorise ces montants ça marche pas et pourtant visiblement ils sont égaux !!!
je ne vois pas d'où ça vient
aurais tu une idée?
merci
sam
Re,
Alors là ! J'hallucine... Pourquoi sur cette valeur et pas sur d'autres !? Ça fait partie des mystères d'Excel. En tous cas pour moi.
Je pense qu'un balèze de chez balèze (comme il y en a beaucoup ici) saurait répondre mais pour moi ça reste incompréhensible. La solution serait que tu inverse la condition = avec <> et dans le Else tu mets le code du début...
j'ai essayé pas mal de choses et rien ne marche toujours le même problème !
sauf que si au lieu de tester les cellules elles-mêmes, je passe par des variables intermédiaires, alors là ça marche !!!
merci pour ton aide qui m'aura été précieuse
cdt
sam