Question code VBA
Hello Thev
Merci beaucoup pour toutes ces précisions, ça m'aide beaucoup !
- Tout fonctionne pour le bouton fournisseur, merci bcp
- J'ai réussi à faire les réglage pour qu'il y ait la sélection au double clic
Concernant la listbox qui s'ouvre, j'essaie d'y ajouter une entête. J'arrive à régler la taille, activer l'en-tête, mais je n'arrive pas à pointer sur les données à remplir. Une idée?
J'ai essayé différents termes ;
- = "sh_prod.Cells(1,3);sh_prod.Cells(1,10);sh_prod.Cells(1,2)"
- =range("1:1")
- = sh_prod.cells("1:1")
With UserForm_liste_produits
With .ListBox_produits
.ColumnHeads = True
.RowSource = sh_prod.Cells("1:1")
.ColumnWidths = "150;50;50"
tb = dic_liste_produits.Items
For Each produit In dic_liste_produits.keys
.AddItem (produit)
ligne_produit_existant = dic_liste_produits(produit)
.List(.ListCount - 1, 1) = sh_prod.Cells(ligne_produit_existant, 3)
.List(.ListCount - 1, 2) = sh_prod.Cells(ligne_produit_existant, 10)
Next produit
End With
.Show
Et aussi, la valeur insérée dans la colonne fournisseur relative au produit est la valeur numéro du fournisseur. Cad qu'au lieu d'avoir fournisseur 1, fournisseur X, Fournisseur Z qui s'affiche, j'ai les 0, 1, 2, ...
Le fait d'avoir mis une combobox dans produit pour sélectionner le fournisseur renvoie dans la BDD à une valeur listindex, et donc le fournisseur est peu reconnaissable quand on y a fait appel par la suite. Quelle aurait été la bonne manière de faire?
J'ai tenté de mettre un code de ce type , mais ça n'a pas fonctionné :
.List(.ListCount - 1, 1) = sh_four.Cells(sh_prod.Cells(ligne_produit_existant, 3), 1)Concernant cette même listbox, j'ai également un autre soucis ;
Si je tape "pomme", il me propose trois choix existants : pomme de terre, pomme de terre ferme et pomme de terre grenaille. Si je ferme la fenêtre car je n'ai envie d'aucun de ces choix mais que je veux faire un nouveau produit, il me sélectionne quand même un des 3 choix (grenaille en l’occurrence).J'ai le même soucis si je tape par exemple "pomme de terre G", il va me mettre "pomme de terre grenaille" dans la textbox sans même me proposer via la listbox le choix. Dans ce cas, il faudrait idéalement qu'il m'ouvre la listbox, et que si je clique sur la croix (ou un bouton annuler), je puisse créer mon nouvel article Ensuite, concernant la dernière page de mon userform produit (nomée poids type), j'y demande deux infos : poids à l'unité et % net. Le fait de compléter ces deux cases formate un caption.
Tout fonctionne bien si je remplis le poids, puis le % net. Mais si j'ai le malheur de retourner dans la case poids, il y a un bug.
Qu'est-ce que j'ai mal écrit?
Private Sub TextBox_pourcent_net_AFTERUPDATE()
'formatage en %
TextBox_pourcent_net.Value = Format(CDbl(TextBox_pourcent_net.Value) / 100, "00 %")
If TextBox_pourcent_net.Value = "" Then
Label_pourcent_net.Visible = False
ElseIf TextBox_pourcent_net.Value <> "" And TextBox_poids_unitaire <> "" Then
Label_pourcent_net.Visible = True
Label_pourcent_net.Caption = "Cela signifie que le produit '" & TextBox_nom_produit & "' possède un poids de " & TextBox_poids_unitaire & " kg, et qu'après être cuisiné seul " & TextBox_pourcent_net & " du produit sera valorisé en cuisine à cause du taux de perte."
Else
Label_pourcent_net.Visible = True
Label_pourcent_net.Caption = "Cela signifie que seul " & TextBox_pourcent_net & " du produit '" & TextBox_nom_produit & "' sera valorisé en cuisine à cause du taux de perte."
End If
End SubDernière question qui n'a rien à voir, mais je travaille avec deux écrans. A gauche, la bdd excel, à droite le développeur VBA.
A chaque fois que je met un userform en play pour le tester, il s'ouvre au dessus de l'éditeur VBA, et 90% du temps, se masque 2 secondes après derrière la fenêtre vba. Je dois alors jouer avec ATL+TAB avec insistance pour le faire réapparaitre. Une astuce pour ne plus avoir le soucis?
Je remets le fichier ci-joint pour repartir sur la même base de travail.
Grand merci
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Concernant la listbox qui s'ouvre, j'essaie d'y ajouter une entête. J'arrive à régler la taille, activer l'en-tête, mais je n'arrive pas à pointer sur les données à remplir. Une idée?
Le plus simple est d'utiliser une 2ème Listbox spécifique à l'entête.
Et aussi, la valeur insérée dans la colonne fournisseur relative au produit est la valeur numéro du fournisseur. Cad qu'au lieu d'avoir fournisseur 1, fournisseur X, Fournisseur Z qui s'affiche, j'ai les 0, 1, 2, ...
Le fait d'avoir mis une combobox dans produit pour sélectionner le fournisseur renvoie dans la BDD à une valeur listindex, et donc le fournisseur est peu reconnaissable quand on y a fait appel par la suite. Quelle aurait été la bonne manière de faire?
voir code ci-dessous
If dic_liste_produits.Count > 1 Then
With UserForm_liste_produits
With .ListBox_entête
.ColumnCount = 10
.List = sh_prod.Rows(1).Value
.ColumnWidths = "0;0;50;0;0;150;0;0;0;50"
End With
With .ListBox_produits
.ColumnCount = 3
.ColumnWidths = "50;150;50"
tb = dic_liste_produits.Items
For Each produit In dic_liste_produits.keys
ligne_produit_existant = dic_liste_produits(produit)
fournisseur = Me.ComboBox_fournisseur.List(sh_prod.Cells(ligne_produit_existant, "C"))
.AddItem (fournisseur)
.List(.ListCount - 1, 1) = produit
.List(.ListCount - 1, 2) = sh_prod.Cells(ligne_produit_existant, "J")
Next produit
End With
.ShowConcernant cette même listbox, j'ai également un autre soucis ;
Si je tape "pomme", il me propose trois choix existants : pomme de terre, pomme de terre ferme et pomme de terre grenaille. Si je ferme la fenêtre car je n'ai envie d'aucun de ces choix mais que je veux faire un nouveau produit, il me sélectionne quand même un des 3 choix (grenaille en l’occurrence).
Il manquait une réinitialisation de votre variable : ligne_produit_existant
With .ListBox_produits
ligne_produit_existant = 0
If .ListIndex > -1 Then ligne_produit_existant = dic_liste_produits(.Value)
End WithTout fonctionne bien si je remplis le poids, puis le % net. Mais si j'ai le malheur de retourner dans la case poids, il y a un bug.
Après reformatage de votre pourcentage, celui-ci n'est plus numérique. Votre instruction doit être :
TextBox_pourcent_net.Value = Format(CDbl(Replace(TextBox_pourcent_net.Value, " %", "")) / 100, "00 %")ci-jointe nouvelle version
Top, merci Thev !
Par contre il y a juste un petit soucis : la MAJ des autres données dans l'userform ne se fait plus si on est sur un produit existant :-/
Merci d'avance
Et j'en profite pour une deuxième question :
Dans le fichier (ci-joint, j'ai remis une MAJ car pas mal de choses ont changées), j'ai rajouté un userform recette.
USERFORM RECETTES :
Dans la page "ingrédient", j'ai passer du temps pour calculer tous les champs de la première ligne du form (ingrédient, quantité, poids, total,...) comme je le voulais. Maintenant, il ne me reste plus qu'à dupliquer sur les lignes suivantes.
Quand je vois tout le code que cette première ligne de formulaire a généré (cfr variables TextBox_poids1, qte_en_pourcent1, qte_en_poids1,TextBox_ingredient1,...) je me dit que ça va me faire un code immense pour cet userform sachant qu'il y a 12 lignes dans le userform.
Y-a-t-il un moyen de facilement dupliquer la première ligne pour les lignes suivantes?
Ou dois-je juste refaire exactement la même chose pour la suite des lignes (ce qui ne me dérange pas, je me dis qu'il y a peut être juste une version accélérée
Autre question : pour le Toggle bouton que j'ai mis, j'ai changé le style. Mais quand je clique dessus (donc valeur = true), je garde un fond ombré/hachuré. Ca rend le texte peu lisible. Y-a-t-il un moyen de retirer ce fond hachuré?
Dans cette même page, un a un label_PU1 qui affiche un prix à l'unité. Dans le cas de l'exemple du produit "pois chiches", le prix total est de 50€ pour 6 kg. Normalement, le prix unitaire devrait être de 8.33€, mais le système arrondi à 8.00€. Comment lui demander de ne pas arrondir?
Label_PU1.Caption = "(" & Format(poids_unitaire, "###0.00 €") & "/" & unite_de_poids & ")"USERFORM PRODUITS
Dans la page sur les saisons, si je coche "tous les mois de l'année", tous les mois se cochent bien. Si je décoche, tout se décoche bien.
Par contre, si je coche "tous les mois de l'année" et que je décoche un des mois, il faudrait que la case "tous les mois de l'année" se décoche automatiquement.
Comment inscrire cela dans le code rapidement sans devoir faire une ligne de condition pour chacun des mois (si coché, si pas coché) ? Ou cette dernière solution est-elle justement celle à appliquer?
Grand merci d'avance
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Par contre il y a juste un petit soucis : la MAJ des autres données dans l'userform ne se fait plus si on est sur un produit existant :-/
Exact.
Du fait que le fournisseur est maintenant le premier élément de la ListBox et que la valeur de la Listbox est par défaut celle de la première colonne, une correction est à apporter.
Il suffit de dire que la valeur de la ListBox est celle de la deuxième colonne, donc celle du produit sélectionné, comme ceci :
With .ListBox_produits
.ColumnCount = 3
.BoundColumn = 2
.ColumnWidths = "50;150;50"ci-jointe version corrigée
Merci beaucoup, je comprends, ça fonctionne !
(pour être certain, avez-vous pu prendre connaissance de mon deuxième post juste avant votre réponse?
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
pour être certain, avez-vous pu prendre connaissance de mon deuxième post juste avant votre réponse?
Oui.
C'est possible, je regarde et vous reviens.
Ok top merci
Je vous remets juste une dernière version plus propres (avancement + loin & écart de code mieux respectés)
Merci d'avance
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Je vous remets juste une dernière version plus propres (avancement + loin & écart de code mieux respectés)
OK.
Pour répondre à votre problème, il faut au préalable renseigner les textbox et label respectivement de chaque ligne ainsi :
1- propriété ControlTipText
ingrédient (textbox1)
qté_en_poids (textbox2)
qté_en_pourcent (textbox3)
poids (textbox4)
perte (textbox5)
euro (textbox6)
unité (label1)
pu (label2)
2-propriété Tag
le numéro de ligne pour les TextBox et Label ci-dessus : 1,2, ... 12
Si vous pouvez me communiquer une nouvelle version avec cet ajout, ce sera une bonne chose de faite
Après, il faut mettre en place un module de classe associé à chaque TextBox pour laquelle il y a une procédure événementielle.
C'est ce que je suis en train de développer.
Ok top merci
Comme ceci pour le fichier ? (v4.2)
Attention : deux valeurs en plus : commandbutton_ingrédient et checkbox piece. J'ai mis aussi controletip txt et tag pour ces éléments supplémentaires. Ces deux éléments sont déjà codés de la manière souhaitée, j'ai juste un bug avec le commandbutton_ingredient qui ouvre le userform_produit (j'ai bien réussi à faire en sorte que le nom de la case ingrédient se mette dans le nom produit de l'userform) mais qui ne veut pas mettre à jour les données d'un produit existant à l'ouverture du formulaire.
Il y a aussi un détail que je n'arrive pas à régler dans cette première ligne :
Ma case textbox_perte1 se remplit automatiquement dans la ligne, selon ce qui est présent dans la BDD pour le produit choisis.
Il peut arriver qu'on doive changer ce ratio. C'est pour cela que la case n'est pas verrouillée.
Mon soucis : si je mets cette case à jour manuellement, les autres data ne se mettent pas à jour.
J'ai uniquement réussi à mettre à jour le format en %. J'ai tenté de faire appel aux macro TextBox_qte_en_pourcent1_Afterupdate, TextBox_qte_en_poids1_Afterupdate et TextBox_poids1_change via des application.run, des Call, ... mais je n'arrive pas à avoir un résultat. Comment faire pour "relancer la machine" en cas de MAJ d'une des datas? (sans devoir ré-écrire toute les macro précédente dans le TextBox_perte1_afterupdate())
Merci d'avance
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonsoir,
ci-joint un premier jet avec un module de classe par type de contrôle.
Je n'ai pas pu prendre en compte l'événement "AfterUpdate" car non disponible en module de classe.
Bonsoir Thev
Merci beaucoup, je parcours ça demain, j'aurai certainement une liste de questions
Encore un tout grand merci pour votre aide
Bonne soirée
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Bonsoir,
Une petite correction et une meilleure disposition
Grand merci Thev, jamais je n'aurai réussi à bricoler ce type de truc !!
Y a juste un élément qui ne fonctionne plus : au clic sur le toggle button, il me mets une erreur.
Aussi, quand on clique sur le commandbuton_ingredient nommé "+", ce n'est pas la recherche ingrédient qu'il doit m'ouvrir mais le userform_produit avec chargement du nom du produit dans la text box et actualisation de tous les champs vu que le produit existe.
Alors, juste pour être certain de vérifier si je comprends bien, afin de pouvoir le refaire à terme :
1) en premier, faire un module classe_instance. Dans ce module, on ajoute dans les constance tout controltiptext qui devrait faire partie de la boucle. Si je comprends bien, ingrédients indique ici le champ en texte et le champ en cmd? (j'aurais peut-être du coup du mettre deux noms différents)
2) Public : ceux qui seront initialisé ensuite. Ce que je ne comprends juste pas c'est pourquoi toutes les constantes ne sont pas reprises? Et également pourquoi certains sont renommés ? (comme poids_kg, qtés_poids, ...)
3) On initialise tous les éléments public mentionnés au point 2 comme indiqué dans le fichier.
4) on crée un module de classe correspondant aux 6 éléments publics différents.
- Pour tout ce qui est textbox, les codes sont identiques si j'ai bien lu. Le seul élément qui change est la définition de la constance correspondant au nom cité dans le point 1. Donc si j'ai un nouveau champ, je copie colle tout le code et je change juste cette variable. Le code cité dans ce module est standard ou certains passage sont quand même liés à mon userform? (pas l'impression)
- Même remarques sur le module cmdbutton et module check box qui ont leur code propre, avec seul la constance qui change. Là où je pourrais avoir un soucis c'est le jour où j'ajoute un autre type d'élément (ex : combobox).
5) pour terminer, on change le code de l'userform recette. Je comprends tout, j'ai juste quelques questions. Je suis occupé à la parcourir, les questions viendront en cours de route je présume
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Y a juste un élément qui ne fonctionne plus : au clic sur le toggle button, il me mets une erreur.
Aussi, quand on clique sur le commandbuton_ingredient nommé "+", ce n'est pas la recherche ingrédient qu'il doit m'ouvrir mais le userform_produit avec chargement du nom du produit dans la text box et actualisation de tous les champs vu que le produit existe.
ci-jointe nouvelle version pour ces corrections .
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
1) en premier, faire un module classe_instance. Dans ce module, on ajoute dans les constance tout controltiptext qui devrait faire partie de la boucle. Si je comprends bien, ingrédients indique ici le champ en texte et le champ en cmd? (j'aurais peut-être du coup du mettre deux noms différents)
2) Public : ceux qui seront initialisé ensuite. Ce que je ne comprends juste pas c'est pourquoi toutes les constantes ne sont pas reprises? Et également pourquoi certains sont renommés ? (comme poids_kg, qtés_poids, ...)
3) On initialise tous les éléments public mentionnés au point 2 comme indiqué dans le fichier.
4) on crée un module de classe correspondant aux 6 éléments publics différents.
Pour tout ce qui est textbox, les codes sont identiques si j'ai bien lu. Le seul élément qui change est la définition de la constance correspondant au nom cité dans le point 1. Donc si j'ai un nouveau champ, je copie colle tout le code et je change juste cette variable. Le code cité dans ce module est standard ou certains passage sont quand même liés à mon userform? (pas l'impression)
Même remarques sur le module cmdbutton et module check box qui ont leur code propre, avec seul la constance qui change. Là où je pourrais avoir un soucis c'est le jour où j'ajoute un autre type d'élément (ex : combobox).
Les étapes :
1- On crée un module de classe par contrôle dont on veut traiter les événements :
Cmd_ingrédient (module CommandButton associé à l'ingrédient)
txt_ingrédient (module TextBox associé à l'ingrédient)
txt_qté_en_poids (module TextBox associé à la quantité en poids)
txt_qté_en_pourcent (module TextBox associé à la quantité en pour cent )
txt_poids (module TextBox associé au Poids)
Chk_pièce (module CheckBox associé à la quantité par pièce )
Dans chaque module, sont définis les propriétés et événements relatifs au type de contrôle, ainsi que sa procédure de chargement (Sub Init)
2- Comme ce module de classe est spécifique, au contraire de ceux définis par défaut : Workbook, Worksheet, Range, Userform, ...
il faut charger en mémoire chaque élément appartenant à la classe, le chargement en mémoire d'un élément de la classe étant appelé instance de la classe.
Pour cela, on utilise une classe standard de VBA = Collection. Donc à chaque module de classe, j'ai associé une collection comme suit.
J'ai donc défini ces collections contenant les instances de classe dans le module "classes_instance" en type Public pour quelle soient reconnues reconnues dans n'importe quelle procédure.
Public ingrédients_cmd As Collection
Public ingrédients_txt As Collection
Public qtés_poids As Collection
Public qtés_pourcent As Collection
Public poids_kg As Collection
Public pièces As Collection3- Afin de différencier les contrôles, vous avez renseigné leur propriété ControlTipText avec une constante les représentant. J'ai donc défini ces constantes dans le module "classes_instance" en type Public pour quelle soient uniques et reconnues dans n'importe quelle procédure.
Public Const ingrédient As String = "ingrédient"
Public Const qté_en_poids As String = "qté_en_poids"
Public Const qté_en_pourcent As String = "Qté_en_pourcent"
Public Const poids As String = "poids"
Public Const perte As String = "perte", euro As String = "euro", unité As String = "unité", pu As String = "pu", pièce As String = "piece"4- Les chargements des instances de classe se font à l'initialisation de l'Userform et se font via cette procédure :
For Each ctrl In USF.Controls
If TypeOf ctrl Is MSForms.TextBox Then
If ctrl.ControlTipText = ingrédient Then
ingrédients_txt.Add Key:=ctrl.Name, Item:=New txt_ingrédient
ingrédients_txt(ctrl.Name).Init ingrédients_txt, USF, ctrl
End If
If ctrl.ControlTipText = qté_en_poids Then
qtés_poids.Add Key:=ctrl.Name, Item:=New txt_qté_en_poids
qtés_poids(ctrl.Name).Init qtés_poids, USF, ctrl
End If
If ctrl.ControlTipText = qté_en_pourcent Then
qtés_pourcent.Add Key:=ctrl.Name, Item:=New txt_qté_en_pourcent
qtés_pourcent(ctrl.Name).Init qtés_pourcent, USF, ctrl
End If
If ctrl.ControlTipText = poids Then
poids_kg.Add Key:=ctrl.Name, Item:=New txt_poids
poids_kg(ctrl.Name).Init poids_kg, USF, ctrl
End If
End If
If TypeOf ctrl Is MSForms.CommandButton Then
If ctrl.ControlTipText = ingrédient Then
ingrédients_cmd.Add Key:=ctrl.Name, Item:=New Cmd_ingrédient
ingrédients_cmd(ctrl.Name).Init ingrédients_cmd, USF, ctrl
End If
End If
If TypeOf ctrl Is MSForms.CheckBox Then
If ctrl.ControlTipText = pièce Then
pièces.Add Key:=ctrl.Name, Item:=New Chk_pièce
pièces(ctrl.Name).Init pièces, USF, ctrl
End If
End If
Next ctrlNB : La procédure Init de la classe charge dans l'instance, les objets : collection, formulaire et contrôle du formulaire
Les collections sont initialisées via cette procédure :
'// initialisation des collections d'instance pour chacun des modules de classe
If Not ingrédients_txt Is Nothing Then For i = ingrédients_txt.Count To 1 Step -1: ingrédients_txt.Remove (i): Next i
Set ingrédients_txt = New Collection
If Not ingrédients_cmd Is Nothing Then For i = ingrédients_cmd.Count To 1 Step -1: ingrédients_cmd.Remove (i): Next i
Set ingrédients_cmd = New Collection
If Not qtés_poids Is Nothing Then For i = qtés_poids.Count To 1 Step -1: qtés_poids.Remove (i): Next i
Set qtés_poids = New Collection
If Not qtés_pourcent Is Nothing Then For i = qtés_pourcent.Count To 1 Step -1: qtés_pourcent.Remove (i): Next i
Set qtés_pourcent = New Collection
If Not poids_kg Is Nothing Then For i = poids_kg.Count To 1 Step -1: poids_kg.Remove (i): Next i
Set poids_kg = New Collection
If Not pièces Is Nothing Then For i = pièces.Count To 1 Step -1: pièces.Remove (i): Next i
Set pièces = New Collection5- Les événements relatifs à chaque classe sont définis au niveau de votre UserForm avec une variable associée représentant l'instance concernée de la classe
' définition événements des classes
Private WithEvents CommandButton_ingrédient As Cmd_ingrédient
Private WithEvents Textbox_ingrédient As txt_ingrédient
Private WithEvents Textbox_qté_en_poids As txt_qté_en_poids
Private WithEvents Textbox_qté_en_pourcent As txt_qté_en_pourcent
Private WithEvents Textbox_poids As txt_poids
Private WithEvents CheckBox_poids_par_pce As Chk_pièce6- Lorsqu'un événement est déclenché dans l'une des instances de ces classes, le module ci-dessous permet d'assigner l'instance à la variable correspondante, ce qui permet alors déclencher l'événement associé du UserForm
Public Sub assignation_instance_classe(instance, type_instance)
'assignement événements de la classe pour l'instance concernée
Select Case type_instance
Case ingrédient
If instance.Typectrl = "TextBox" Then Set Textbox_ingrédient = instance
If instance.Typectrl = "CommandButton" Then Set CommandButton_ingrédient = instance
Case qté_en_poids: Set Textbox_qté_en_poids = instance
Case qté_en_pourcent: Set Textbox_qté_en_pourcent = instance
Case poids: Set Textbox_poids = instance
Case pièce: Set CheckBox_poids_par_pce = instance
End Select
End Sub- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
[quote=thev post_id=853729 time=1585746709 user_id=41631]
1) en premier, faire un module classe_instance. Dans ce module, on ajoute dans les constance tout controltiptext qui devrait faire partie de la boucle. Si je comprends bien, ingrédients indique ici le champ en texte et le champ en cmd? (j'aurais peut-être du coup du mettre deux noms différents)
2) Public : ceux qui seront initialisé ensuite. Ce que je ne comprends juste pas c'est pourquoi toutes les constantes ne sont pas reprises? Et également pourquoi certains sont renommés ? (comme poids_kg, qtés_poids, ...)
3) On initialise tous les éléments public mentionnés au point 2 comme indiqué dans le fichier.
4) on crée un module de classe correspondant aux 6 éléments publics différents.
Pour tout ce qui est textbox, les codes sont identiques si j'ai bien lu. Le seul élément qui change est la définition de la constance correspondant au nom cité dans le point 1. Donc si j'ai un nouveau champ, je copie colle tout le code et je change juste cette variable. Le code cité dans ce module est standard ou certains passage sont quand même liés à mon userform? (pas l'impression)
Même remarques sur le module cmdbutton et module check box qui ont leur code propre, avec seul la constance qui change. Là où je pourrais avoir un soucis c'est le jour où j'ajoute un autre type d'élément (ex : combobox).
Les étapes :
1- On crée un module de classe par contrôle dont on veut traiter les événements :
- Cmd_ingrédient (module CommandButton associé à l'ingrédient)
- txt_ingrédient (module TextBox associé à l'ingrédient)
- txt_qté_en_poids (module TextBox associé à la quantité en poids)
- txt_qté_en_pourcent (module TextBox associé à la quantité en pour cent )
- txt_poids (module TextBox associé au Poids)
- Chk_pièce (module CheckBox associé à la quantité par pièce )
2- Comme ce module de classe est spécifique, au contraire de ceux définis par défaut : Workbook, Worksheet, Range, Userform, ...
il faut charger en mémoire chaque élément appartenant à la classe, le chargement en mémoire d'un élément de la classe étant appelé instance de la classe.
Pour cela, on utilise une classe standard de VBA = Collection. Donc à chaque module de classe, j'ai associé une collection.
J'ai donc défini ces collections contenant les instances de classe dans le module "classes_instance" en type Public pour quelle soient reconnues reconnues dans n'importe quelle procédure.
Public ingrédients_cmd As Collection
Public ingrédients_txt As Collection
Public qtés_poids As Collection
Public qtés_pourcent As Collection
Public poids_kg As Collection
Public pièces As Collection3- Afin de différencier les contrôles, vous avez renseigné leur propriété ControlTipText avec une constante les représentant. J'ai donc défini ces constantes dans le module "classes_instance" en type Public pour quelle soient uniques et reconnues dans n'importe quelle procédure.
Public Const ingrédient As String = "ingrédient"
Public Const qté_en_poids As String = "qté_en_poids"
Public Const qté_en_pourcent As String = "Qté_en_pourcent"
Public Const poids As String = "poids"
Public Const perte As String = "perte", euro As String = "euro", unité As String = "unité", pu As String = "pu", pièce As String = "piece"4- Les chargements des instances de classe se font à l'initialisation de l'Userform via cette procédure :
For Each ctrl In USF.Controls
If TypeOf ctrl Is MSForms.TextBox Then
If ctrl.ControlTipText = ingrédient Then
ingrédients_txt.Add Key:=ctrl.Name, Item:=New txt_ingrédient
ingrédients_txt(ctrl.Name).Init ingrédients_txt, USF, ctrl
End If
If ctrl.ControlTipText = qté_en_poids Then
qtés_poids.Add Key:=ctrl.Name, Item:=New txt_qté_en_poids
qtés_poids(ctrl.Name).Init qtés_poids, USF, ctrl
End If
If ctrl.ControlTipText = qté_en_pourcent Then
qtés_pourcent.Add Key:=ctrl.Name, Item:=New txt_qté_en_pourcent
qtés_pourcent(ctrl.Name).Init qtés_pourcent, USF, ctrl
End If
If ctrl.ControlTipText = poids Then
poids_kg.Add Key:=ctrl.Name, Item:=New txt_poids
poids_kg(ctrl.Name).Init poids_kg, USF, ctrl
End If
End If
If TypeOf ctrl Is MSForms.CommandButton Then
If ctrl.ControlTipText = ingrédient Then
ingrédients_cmd.Add Key:=ctrl.Name, Item:=New Cmd_ingrédient
ingrédients_cmd(ctrl.Name).Init ingrédients_cmd, USF, ctrl
End If
End If
If TypeOf ctrl Is MSForms.CheckBox Then
If ctrl.ControlTipText = pièce Then
pièces.Add Key:=ctrl.Name, Item:=New Chk_pièce
pièces(ctrl.Name).Init pièces, USF, ctrl
End If
End If
Next ctrlNB : La procédure Init de la classe charge dans l'instance, les objets : collection, formulaire et contrôle du formulaire
Les collections sont initialisées via cette procédure :
'// initialisation des collections d'instance pour chacun des modules de classe
If Not ingrédients_txt Is Nothing Then For i = ingrédients_txt.Count To 1 Step -1: ingrédients_txt.Remove (i): Next i
Set ingrédients_txt = New Collection
If Not ingrédients_cmd Is Nothing Then For i = ingrédients_cmd.Count To 1 Step -1: ingrédients_cmd.Remove (i): Next i
Set ingrédients_cmd = New Collection
If Not qtés_poids Is Nothing Then For i = qtés_poids.Count To 1 Step -1: qtés_poids.Remove (i): Next i
Set qtés_poids = New Collection
If Not qtés_pourcent Is Nothing Then For i = qtés_pourcent.Count To 1 Step -1: qtés_pourcent.Remove (i): Next i
Set qtés_pourcent = New Collection
If Not poids_kg Is Nothing Then For i = poids_kg.Count To 1 Step -1: poids_kg.Remove (i): Next i
Set poids_kg = New Collection
If Not pièces Is Nothing Then For i = pièces.Count To 1 Step -1: pièces.Remove (i): Next i
Set pièces = New Collection5- Les événements relatifs à chaque classe sont définis au niveau de votre UserForm avec une variable associée représentant l'instance concernée de la classe
' définition événements des classes
Private WithEvents CommandButton_ingrédient As Cmd_ingrédient
Private WithEvents Textbox_ingrédient As txt_ingrédient
Private WithEvents Textbox_qté_en_poids As txt_qté_en_poids
Private WithEvents Textbox_qté_en_pourcent As txt_qté_en_pourcent
Private WithEvents Textbox_poids As txt_poids
Private WithEvents CheckBox_poids_par_pce As Chk_pièce6- Lorsqu'un événement est déclenché dans l'une des instances de ces classes, le module ci-dessous permet d'assigner l'instance à la variable correspondante, ce qui permet alors déclencher l'événement associé du UserForm
Public Sub assignation_instance_classe(instance, type_instance)
'assignement événements de la classe pour l'instance concernée
Select Case type_instance
Case ingrédient
If instance.Typectrl = "TextBox" Then Set Textbox_ingrédient = instance
If instance.Typectrl = "CommandButton" Then Set CommandButton_ingrédient = instance
Case qté_en_poids: Set Textbox_qté_en_poids = instance
Case qté_en_pourcent: Set Textbox_qté_en_pourcent = instance
Case poids: Set Textbox_poids = instance
Case pièce: Set CheckBox_poids_par_pce = instance
End Select
End SubMerci pour vos réponses Thev.
Quelques questions (pourriez-vous repartir du fichier ci-joint svp? Certains éléments ont été ajoutés).
- Les changement du toggle button ne se passent pas correctement. Si je clique sur le togglebutton_quantite, il y a une erreur au niveau de cette étapge du code "Txt_qté_en_pourcent.Visible = True".
- Si je modifie le montant dans la case % perte (de manière manuelle), le calcul ne se refait pas
- Si je fais un double clic dans la case ingrédient pour ouvrir le champ de recherche, mais que je ferme la fenêtre de recherche sans avoir choisi qque chose, j'ai un bug (erreur 381 : pas possible lire la propriété column. Index de table de propriété no nvalide)
- Si je met dans la partie Textbox_ingrédient_Change le format de la perte en % (via Format(CDbl((sh_prod.Cells(ligne_produit, 39), " %", "")), "00 %") ), cela fait rater le calcul pour le poids total (Textbox_qté_en_poids_Change). A mon avis cela doit être dû à une conservation du format % qu'il n'arrive pas à gérer. Comment résoudre le soucis?
- Pour le moment, si je prend la référence feuille de brick qui n'a pas de quantité indiquée en poids unitaire, on a une erreur lors des calculs. Afin de faciliter le tout,je voudrais que si la colonne 38 de la BDD est vide (poids unitaire), la check box à la pièce disparaisse (donc visible QUE quand poids unitaire indiqué). En code, j'ai essayé cela (dernières lignes), mais ça donne rien
For Each ctrl In Me.Controls
If ctrl.Tag = Textbox_ingrédient.Tag Then 'même ligne
If TypeOf ctrl Is MSForms.TextBox Then
If ctrl.ControlTipText = qté_en_poids Then ctrl.Value = 0: ctrl.Visible = True
If ctrl.ControlTipText = qté_en_pourcent Then ctrl.Value = 0
If ctrl.ControlTipText = euro Then ctrl.Value = 0
If ctrl.ControlTipText = poids Then ctrl.Value = 0
If ctrl.ControlTipText = perte Then ctrl.Value = Format(sh_prod.Cells(ligne_produit, 39), "#,##0.00")
If ctrl.Value = "" Then ctrl.Value = Format(Val(0), "#,##0.00")
End If
If TypeOf ctrl Is MSForms.Label Then
If ctrl.ControlTipText = unité Then ctrl.Caption = "En " & unite_de_poids & ":"
If ctrl.ControlTipText = pu Then ctrl.Caption = "(" & Format(prix_par_unite_poids, "###0.00 €") & "/" & unite_de_poids & ")"
End If
If TypeOf ctrl Is MSForms.CommandButton Then
If ctrl.ControlTipText = ingrédient Then ctrl.Visible = True
End If
If TypeOf ctrl Is MSForms.CheckBox Then
If ctrl.ControlTipText = piece Then
If sh_prod.Cells(ligne_produit, 38) = "" Then ctrl.Visible = False
End If
End If
End If
Next ctrlMerci d'avance, et encore un tout grand merci pour votre précieuse aide
- Messages
- 4'199
- Excel
- 2021 FR 64 bits
- Inscrit
- 13/06/2016
- Emploi
- bénévole associations Goutte d'Or
Les changement du toggle button ne se passent pas correctement. Si je clique sur le togglebutton_quantite, il y a une erreur au niveau de cette étapge du code "Txt_qté_en_pourcent.Visible = True".
cela vient d'une mauvaise définition de la constante qté_en_pourcent dans le module "classes_instance"
Public Const qté_en_pourcent As String = "Qté_en_pourcent"et non
Public Const qté_en_pourcent As String = "qté_en_pourcent"puisque c'est Qté_en_pourcent que vous avez mis dans ControlTipText
Si je modifie le montant dans la case % perte (de manière manuelle), le calcul ne se refait pas
Il n'y a pas de module de classe associé à ce contrôle. Je le rajoute.
Si je fais un double clic dans la case ingrédient pour ouvrir le champ de recherche, mais que je ferme la fenêtre de recherche sans avoir choisi qque chose, j'ai un bug (erreur 381 : pas possible lire la propriété column. Index de table de propriété no nvalide)
Bizarre. Je n'ai plus cette erreur dans la version que vous m' avez fournie car j'avais conditionné le remplissage de l'ingrédient
With UserForm_recherche_prod.ListBox_recherche_produit 'prend en compte la ListBox_recherche_produit
If .ListIndex > -1 Then Txt_ingrédient.Value = .Column(5, .ListIndex) 'récupère le valeur de la colonne 0 de la ListBox_recherche_produit dans la Textbox "InstallationIDTextBox"
End WithSi je met dans la partie Textbox_ingrédient_Change le format de la perte en % (via Format(CDbl((sh_prod.Cells(ligne_produit, 39), " %", "")), "00 %") ), cela fait rater le calcul pour le poids total (Textbox_qté_en_poids_Change). A mon avis cela doit être dû à une conservation du format % qu'il n'arrive pas à gérer. Comment résoudre le soucis?
Dans la procédure événementielle Textbox_qté_en_poids_Change, compléter cette instruction ainsi :
If ctrl.ControlTipText = perte Then Set txt_perte = ctrl: If Not IsNumeric(txt_perte) Then txt_perte = Replace(txt_perte, " %", "")Pour le moment, si je prend la référence feuille de brick qui n'a pas de quantité indiquée en poids unitaire, on a une erreur lors des calculs. Afin de faciliter le tout,je voudrais que si la colonne 38 de la BDD est vide (poids unitaire), la check box à la pièce disparaisse (donc visible QUE quand poids unitaire indiqué). En code, j'ai essayé cela (dernières lignes), mais ça donne rien
Ça ne donne rien pour 2 raisons :
1- piece est une constante qui n'existe pas, donc sa valeur est vide. La bonne constante est pièce dont la valeur est "piece"
2- le test avec MSForms.Checkbox est un peu buggé car il renvoie en sus des CheckBox, les ToggleButton.
mieux vaut donc utiliser :
If TypeName(ctrl) = "CheckBox" Then
If ctrl.ControlTipText = pièce Then
If sh_prod.Cells(ligne_produit, 38) = "" Then ctrl.Visible = False
End If
End IfMerci de votre retour
Ok pour quantité en pourcent, c'est modifié.
Ok pour la classe perte, je vous joins mon nouvel update pour la mettre dedans?
Erreur : en effet, je n'ai plus non plus.
% = ok
Checkbox : Ca fonctionne , merci
Par contre, le toggle button ne fonctionne pas. Avec le nouvel update ci joint où j'ai fait les modifs demandées, quand je clique dedans, je vois qu'il n'y a que la ligne 11 qui varie, et pas le reste. Normalement toute les checkbox devraient disparaitre au clic dessus. A quoi est-ce du?
Grand merci