Combobox en cascades avec date

lolo62000

XLDnaute Junior
Salut,

j'ai un problème avec des combobox en cascades.
Lorsque je fais une sélection sur du texte, tout fonctionne bien.
Par contre, si j'utilise la combobox pour fitrer une date, plus rien ne fonctionne.
J'imagine donc que le problème vient du format de la date dans la macro.
Faut-il rajouter une ligne de code pour informer vba qu'il s'agit d'un format spécial?
Je joins mon exemple en pièce jointe. (Si on filtre la date en choisissant "A", pas de problèmes. Si on choisit "18/07/2016", la combobox avec le Nom n'est pas alimentée).
Merci.

Laurent.
 

Pièces jointes

  • Test_Date_Cbx.xlsm
    23.4 KB · Affichages: 51

Robert

XLDnaute Barbatruc
Repose en paix
Bonjour Lolo, bonjour le forum,

Essaie comme ça :

Code:
Dim f As Worksheet

Private Sub UserForm_Initialize()
Dim MonDico As Object
Dim c As Range

Set f = Sheets("Temps_cumulé")
Set MonDico = CreateObject("Scripting.Dictionary")
For Each c In f.Range("A2:A" & f.[A65000].End(xlUp).Row) ' on explore la colonne de niveau 1
    MonDico(c.Value) = "" ' on ajoute l'élément de la famille au dictionnaire
Next c
Me.famille.List = MonDico.keys
End Sub

Private Sub famille_click()
Dim MonDico As Object
Dim c As Range
Dim D As Date

Me.SousFamille.Clear
Me.Code.Value=""
Me.TextBox1.Value=""
Me.TextBox2.Value=""
Set MonDico = CreateObject("Scripting.Dictionary")
For Each c In f.Range("A2:A" & f.[A65000].End(xlUp).Row) ' on explore la colonne de niveau 1"
    On Error Resume Next
    D = CDate(c)
    If Err <> 0 Then
        If c = Me.famille Then MonDico(c.Offset(, 1).Value) = "" ' si famille alors on ajoute l'élément de la sous-famille au dictionnaire
        GoTo suite
    End If
    If Format(D, "yyyy/mm/dd") = Format(Me.famille, "yyyy/mm/dd") Then MonDico(c.Offset(, 1).Value) = ""
suite:
On Error GoTo 0
Next c
Me.SousFamille.List = MonDico.keys
End Sub

Private Sub SousFamille_click()
Dim c As Range
Dim S As Variant

For Each c In f.Range("A2:A" & f.[A65000].End(xlUp).Row) ' on explore la colonne de niveau 1
    S = IIf(IsDate(c.Value), Format(c.Value, "dd/mm/yyyy"), c.Value)
    If S = Me.famille And c.Offset(, 1) = Me.SousFamille Then
        Me.Code = c.Offset(, 2) ' si famille alors on ajoute l'élément de la sous-famille au dictionnaire
        Me.TextBox1 = c.Offset(, 3)
        Me.TextBox2 = c.Offset(, 4)
    End If
Next c
End Sub
 

lolo62000

XLDnaute Junior
Salut,
Robert, je réussis à alimenter la combobox contenant les noms maintenant, par contre les textbox ne sont plus alimentées.
Dranreb, c'est très impressionnant ce que tu as créé, mais peut-être trop haut niveau pour moi. :(
J'ai tenté de reproduire ce que tu as fait dans mon fichier, mais j'ai un message : L'objet n'est pas source d'événements automation.
Je ne connais pas du tout les modules de classe, et là tu m'as un peu perdu...:confused:
Merci.
Laurent.
 

lolo62000

XLDnaute Junior
Salut,
Autant pour moi Dranreb, j'ai réessayé à tête reposée du weekend, de reproduire ce que tu m'as envoyé, et tout fonctionne!
Je ne connais pas la différence entre un Module et un Module de classe. Je vais étudier ça de plus près, pour essayer de comprendre le cheminent de ton codage.
Est-ce que dans un sens, le codage des modules de classe est fait en sorte qu'il puisse servir à toutes les bases de données gérées par formulaire?
Un gros merci en tout cas,
Laurent.
 

Dranreb

XLDnaute Barbatruc
Bonjour.
Un module de classe est à la fois un modèle d'objet, son plan de construction et la programmation destinée à fonctionner sur les exemplaires qui en seront créés. On préfèrera ce mot "exemplaire" à l'anglicisme "instance" du jargon informatique. Le nom du module de classe devient aussi le nom du type de donnée objet qu'il définit, de sorte qu'on peut le préciser derrière As dans une déclaration Dim, Private ou Public.

Dans la programmation extérieure au module de classe on ne voit de celui ci que les éléments y étant précisés avec le mot clé Public, mais, à la différence d'un module ordinaire, on ne peut y accéder qu'à condition de le faire précéder d'un point, puis encore devant, à moins d'une instruction With préalable la précisant déjà, d'une expression représentant un exemplaire de cet objet (sinon: erreur de compilation). S'il s'agit d'une variable, il faut en outre qu'une expression de son type lui ait été affectée par un Set (sinon: erreur d'exécution, cette fois). Fort heureusement, l'expression formée du mot clé New suivi du type d'objet (qui est en même temps le nom de son module de classe) représente un exemplaire tout juste créé de ce type d'objet.

Propriétés et méthodes sont les appellations conventionnelles de ces élements visibles de l'extérieur du module de classe, déjà vues dans l'aide de VBA à propos des objets de bibliothèques fournies. Une chose déclarée Public dans un module de classe a un statut de propriété quand il s'agit d'une simple variable, d'une Function ou d'une Property Get dépourvues de paramètre, ou d'une Property Let ou Set munie du seul faux paramètre formel représentant la valeur à lui attribuer. Dans tous les autre cas il s'agit d'une méthode, en particulier quand c'est une Sub avec ou sans paramètre.

Enfin, un objet peut aussi décréter des évènements dans un autre module objet. Pour cela, il doit y être déclaré en tête avec le mot clé WithEvents. Cela a pour conséquence d'installer son nom dans la liste de gauche (Objet) qui surmonte la fenêtre de code. S'il y est sélectionné, celle de droite (Procédure) propose les différents modèles de procédures pouvant être installés automatiquement pour profiter de ces évènements. Le nom des procédures installées seront de la forme NomObjet_NomÉvènement. Dans le module de classe, ces évènements sont déclarés au moyen d'instructions Event, et, lors des exécutions, décrétés par des RaiseEvent.

Pour être tout à fait complet, il ne resterait qu'un tout petit point à aborder à propos d'une espèce bien étrange de module de classe: le module d'interface. Mais je crois que ça suffit pour aujourd'hui !
 

lolo62000

XLDnaute Junior
Merci pour l'explication. J'avoue que j'ai encore énormément à apprendre pour maîtriser ça un jour.
Par contre, j'ai une autre question pour toi.
Lorsque j'affiche mon formulaire, je souhaiterais qu'il soit modifiable. Autrement dit, quand on change une valeur dans une textbox, j'aimerais qu'en cliquant sur le bouton "Mettre à jour", les données soient remplacées dans ma feuille "Temps_cumulé".
J'ai essayé de le coder, mais ça ne fonctionne pas... :(
Je te joins mon fichier original pour regarder ça si tu as le temps.
Merci,
Laurent.
 

Pièces jointes

  • Test_Date_Cbx.xlsm
    205 KB · Affichages: 39

BOISGONTIER

XLDnaute Barbatruc
Repose en paix
Bonsoir,

Code:
Dim f
Private Sub UserForm_Initialize()
  Set f = Sheets("Temps_cumulé")
  Set MonDico = CreateObject("Scripting.Dictionary")
  For Each c In f.Range("A2:A" & f.[A65000].End(xlUp).Row) ' on explore la colonne de niveau 1
  MonDico(c.Value) = "" ' on ajoute l'élément de la famille au dictionnaire
  Next c
  Me.famille.List = MonDico.keys
End Sub

Private Sub famille_click()
  Me.SousFamille.Clear
  Set MonDico = CreateObject("Scripting.Dictionary")
  For Each c In f.Range("A2:A" & f.[A65000].End(xlUp).Row) ' on explore la colonne de niveau 1"
  If IsDate(Me.famille) Then
  If c = CDate(Me.famille) Then MonDico(c.Offset(, 1).Value) = "" ' si famille alors on ajoute l'élément de la sous-famille au dictionnaire
  Else
  If c = Me.famille Then MonDico(c.Offset(, 1).Value) = "" ' si famille alors on ajoute l'élément de la sous-famille au dictionnaire
  End If
  Next c
  Me.SousFamille.List = MonDico.keys
End Sub

Private Sub SousFamille_click()
  For Each c In f.Range("A2:A" & f.[A65000].End(xlUp).Row) ' on explore la colonne de niveau 1
  If IsDate(Me.famille) Then
  If c = CDate(Me.famille) And c.Offset(, 1) = Me.SousFamille Then Me.Code = c.Offset(, 2) ' si famille alors on ajoute l'élément de la sous-famille au dictionnaire
  If c = CDate(Me.famille) And c.Offset(, 1) = Me.SousFamille Then Me.TextBox1 = c.Offset(, 3)
  If c = CDate(Me.famille) And c.Offset(, 1) = Me.SousFamille Then Me.TextBox2 = c.Offset(, 4)
  Else
  If c = Me.famille And c.Offset(, 1) = Me.SousFamille Then Me.Code = c.Offset(, 2) ' si famille alors on ajoute l'élément de la sous-famille au dictionnaire
  If c = Me.famille And c.Offset(, 1) = Me.SousFamille Then Me.TextBox1 = c.Offset(, 3)
  If c = Me.famille And c.Offset(, 1) = Me.SousFamille Then Me.TextBox2 = c.Offset(, 4)
  End If
  Next c
End Sub

JB
 

Pièces jointes

  • Copie de Test_Date_Cbx.xlsm
    27.4 KB · Affichages: 44

Dranreb

XLDnaute Barbatruc
Avec un ComboBoxLiées c'est facile: Bingo1 donne le numéro de ligne dan CL.PlgTablo correspondant aux valeurs choisie. Il suffit de l'affecter à une variable déclarée Private LCou As long en tête du module. Elle sera conservée et dans le code du bouton vous pourrez verser dan CL.PlgTablo.Rows(Ligne).Resize(, 16).Value = T
T étant un tableau préalablement garni des valeurs de contrôles. Un peu à l'envers de ce qui est fait dans BingoUn en somme.
 

lolo62000

XLDnaute Junior
J'ai essayé de rentrer ce code dans la macro "CommandButton2" associée au bouton du formulaire "Mettre à jour", mais j'obtiens ce message, sans pouvoir afficher le formulaire:
Erreur de compilation:
La déclaration de la procédure ne correspond pas à la description de l'événement ou de la procédure de même nom.
C'est bien comme ça qu'il faut l'écrire?

Private Sub CommandButton2_Click(LCou As Long)
Dim T()
CL.PlgTablo.Rows(Ligne).Resize(, 16).Value = T
T(1, 3) = Me.Role
End Sub

PS: Dans l'exemple que j'avais joint, j'avais entré le code dans le bouton qui ouvre le formulaire, alors qu'il devrait être associé au bouton "Mettre à jour" dans le formulaire.
 

Dranreb

XLDnaute Barbatruc
L'évènement Click d'un CommandButton ne requière aucun argument.
Pour ne plus risquer de vous tromper de la sorte, vous devriez prendre l'habitude de toujours installer les modèles de procédures évènements à l'aide des deux grandes listes déroulantes qui surmontent la fenêtre de code. Celle de gauche pour sélectionner l'objet, celle de droite pour sélectionner le nom de l'évènement.
De plus LCou est généralement dans mes codes un nom de variable représentant le numéro de ligne courant, et il est connu de toutes les procédures puisque déclaré en tête du module, avant toute procédure (on appelle ça une variable globale).
Au contraire Ligne ne sera pas connu. Et c'est le nom de l'argument fourni par l'évènement BingoUn de l'objet ComboBoxLiées. En général dans la procédure de cet évènement je l'affecte d'ailleurs à LCou, justement. Mais je m'aperçois que c'est de ma faute: j'avais laissé Ligne au lieu de LCou dans l'exemple d'écriture vers la plage de la ligne
Dimensionnez correctement Dim T(1 to 1, 1 To 16) et garnissez ses éléments des valeurs de contrôles avant de le vider dans la plage de la ligne, pas après !
C'est à la lecture qu'il faut faire l'inverse après. À l'écriture il faut faire ça avant, sinon votre tableau 2D d'une ligne est vide quand vous l'écrivez dans la plage.
 
Dernière édition:

lolo62000

XLDnaute Junior
Ok merci.
Malheureusement, je ne m'y connais pas suffisamment en VBA, et là je ne vous suis plus du tout. J'ai essayé de modifier le code, et j'ai effacé toutes les lignes. J'ai essayé aussi de changer Ligne pour Lcou, mais comme l'événement Click ne requiert aucun argument, Lcou ne fonctionne pas non plus.
J'ai essayé la solution de Boisgontier qui fonctionne bien, et qui est plus à la hauteur de mes connaissances actuelles en vba.
Merci pour le temps passé,
Bonne journée.

Laurent.
 

Dranreb

XLDnaute Barbatruc
Ce sera plus difficile à faire évoluer, et mettre au point, avec beaucoup plus de programmation dans l'UserForm lui même…
Avez vous déclaré la variable globale LCou, et y avez, dans BingoUn affecté Ligne, comme je l'avais dit ?
Joignez ce que vous avez essayé.
 

Discussions similaires

Réponses
2
Affichages
311

Statistiques des forums

Discussions
312 215
Messages
2 086 333
Membres
103 188
dernier inscrit
evebar