Ajouter un objet indexé à une collection withevents

Résolu
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 - 10 juil. 2006 à 15:42
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 - 3 déc. 2006 à 19:04
[VB6]
Bonjour,

le problème est ici simplifié pour être plus facilement cerné.

sur une Form, une TextBox.
j'attache cette TB à une collection qui elle-même l'attache à une classe WithEvents pour des traitements à l'interne.
(donc la classe contenant la collection ne sert qu'à accéder rapidement à la déclaration de la sous-classe autonome)

j'attache Text2, parfait!
mon souci : j'attache Text1(1), grrrrr !!!!

le code ci-dessous pour éclairer :
la Form contient 2 TextBox (pour test)
       Text1(1) (<-- Text1 indéxé, évidemment)
       Text2

'= -=-=-=-=-=-=-=-=
' FORM : Form1.frm
'=-=-=-=-=-=-=-=-=
'
'
Option Explicit 
Private mTBs As New TextBoxes 
'
'
Private Sub Form_Load() 
    mTBs.Add Text1(1) 
    'mTBs.Add Text2
End Sub 
'

Private Sub Form_Unload(Cancel As Integer) 
    'mTBs.Remove Text1(1)
    Set mTBs = Nothing 
End Sub 

'------------------------------------------------------
'------------------------------------------------------

'=-=-=-=-=-=-=-=-=-=-=-
' CLASS : TextBoxes.cls
'=-=-=-=-=-=-=-=-=-=-=-
'
'
Option Explicit 
'
Private mCol  As Collection 
'
Public Property Get Count() As Long 
    Count = mCol.Count 
End Property 
'
Public Property Get NewEnum() As IUnknown 
    Set NewEnum = mCol.[_NewEnum] 
End Property 
'
Public Property Get Item(vntIndexKey As Variant) As Cls_TxtBox 
    Set Item = mCol(vntIndexKey) 
End Property 
'
'
Private Sub Class_Initialize() 
    Set mCol = New Collection 
End Sub 
'
Private Sub Class_Terminate() 
    Set mCol = Nothing 
End Sub 
'
'
Public Sub Add(ByRef oTxtBox As Variant) 
    Dim AfTxtBox As New Cls_TxtBox 
    AfTxtBox.SetObject oTxtBox 
    mCol.Add AfTxtBox 
    Set AfTxtBox = Nothing 
End Sub 
'
Public Sub Remove(ByRef oTxtBox As Variant) 
'    Dim i As Long
'    If mCol.Count > 0 Then
'        For i = 1 To mCol.Count
'            If mCol.Item(i).Object Is oTxtBox Then mCol.Remove i: Exit For
'        Next i
'    End If
End Sub 

'------------------------------------------------------
'------------------------------------------------------

'=-=-=-=-=-=-=-=-=-=-=-=
' CLASS : Cls_TxtBox.cls
'=-=-=-=-=-=-=-=-=-=-=-=
'
'
Option Explicit 
'
Private WithEvents mTxt As TextBox 
'
'
Public Property Get Object() As TextBox 
    Set Object = mTxt 
End Property 
'
'
Private Sub Class_Initialize() 
    Set mTxt = Nothing 
End Sub 
'
Private Sub Class_Terminate() 
    Set mTxt = Nothing 
End Sub 
'
'
Public Function SetObject(new_mTxt As Variant) As Boolean 
    Dim oTB As TextBox, Index As Integer 

    On Local Error Resume Next 
        Index = new_mTxt.Index 

    If Err.Number = 343 Then 
'       pas un tableau donc contrôle non-indéxé
        Err.Clear 
        Set oTB = new_mTxt 
        Set mTxt = oTB 
        SetObject = True 
    ElseIf Err.Number = 0 Then 
        On Error GoTo 0 
'       pas d'erreur, il est indéxé
        MsgBox new_mTxt.Name & "(" & new_mTxt.Index & ")" 
        Set oTB = new_mTxt 
        MsgBox oTB.Index 
        Set mTxt = oTB 
        SetObject = True 
    Else 
'       autre erreur mais il n'y a pas de raison (tant qu'on met bien un txtbox)
        Err.Clear 
        Set mTxt = Nothing 
        SetObject = False 
    End If 

    Set oTB = Nothing 
End Function
'
'
Private Sub mTxt_KeyPress(KeyAscii As Integer) 
    Debug.Print mTxt.Name & "_KeyPress : " & Chr$(KeyAscii) 
End Sub

<small> Coloration
syntaxique automatique [AFCK] </small>
       

le code est intégral, çà va très vite à tester...
il suffit juste d'inverser la quote
    mTBs.Add Text1(1) 
    'mTBs.Add Text2
(et de regarder la fenêtre de debug au Txt_Change pour Text2 fonctionnel)

pour mon projet réel je peux contourner le problème en n'utilisant pas de groupe de contrôles mais la question subsiste...

merci déjà d'avoir lu jusqu'ici

++
PCPT   [AFCK]
<hr size ="2" width="100%" />Prenez un instant pour répondre à ce sondage svp

19 réponses

mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
3 déc. 2006 à 05:16
T'eh, on va relancer un vieux topic

Et si c'était tout simplement impossible de cette façon ?
Il est probable qu'il ne soit pas possible de pointer ton objet mTxt  sur un controle lui est indexé.
Au cas où, regarde ce lien.

@++

<hr size="2" width="100%" />
  --Mortalino--
Le mystérieux chevalier, "Provençal, le Gaulois"
<!--
3
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
10 juil. 2006 à 15:44
Txt_Change .... Txt_KeyPress **
0
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
11 juil. 2006 à 07:14
Salut PCPT,

et en l'indexant pas par sa propriété Index, mais avec le Tag ?

Y a pas moyen de le gérer ainsi ?
Tu crées un évènement Txt_Change (ou KeyPress) qui gère tes contrôles avec cette propriété Tag (bien entendu, elle est la même pour tous tes CheckBox)

Méthode barbare, certe, mais ça m'a enlevé une épine du pied plusieurs fois !
J'ai pas VB6 sur moi donc je n'ai pu tester ton code...

++
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
11 juil. 2006 à 09:56
salut Mortalino,
pas essayé avec le Tag ou autre puisque je vois comment contourner le problème dans le projet actuel mais pas pour autant "pourquoi"
et ici de toutes façons çà serait pareil. admettons un Tag à "yep", si Tag "yep" (au .Add.) alors .SetObject ...> même résultat

<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
11 juil. 2006 à 10:29
C'est vrai que c'est bizarre.

D'autant plus si MsgBox new_mTxt.Name & "(" & new_mTxt.Index & ")" fonctionne bien, c'est pas logique !
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
11 juil. 2006 à 14:29
si, c'est logique. mTxt est un objet unique donc ne renvoyant pas ses évènements avec "Index as integer" en paramètre. et il est impossible de déclarer un tableau d'objets (ou d'objets indexés) withevents.

mais le problème reste le même :

nouveau projet, 2 TB indéxées, 2 boutons :

Option Explicit 
Dim o As TextBox 
'
'
Private Sub Form_Load() 
    Text1(0).Text =  "zone 1" 
    Text1(1).Text = "zone 2" 
End Sub 
'
'
Private Sub Command1_Click() 
    Set o = Text1(0) 
    MsgBox o.Text 
    Set o = Nothing 
End Sub 
'
Private Sub Command2_Click() 
    Set o = Text1(1) 
    MsgBox o.Text 
    Set o = Nothing 
End Sub

<small> Coloration
syntaxique automatique [AFCK] </small>
       

on récupère bien séparément (et sans erreur) les propriétés. il doit donc y avoir un moyen d'en faire autant par collection de classes....

décidément j'ai pas de chance avec mes questions....

PCPT   [AFCK]
<hr size ="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
11 juil. 2006 à 14:55
Viens faire du VBA c'est plus simple...

C'est vrai que t'as pas de chance, tu nous demandes des choses assez complexes !

En fait, si toi tu sais pas, bah nous non plus (sauf peut-être Rey !)

Désolé que l'aide ne marche que dans un sens. (ah ! pour l'instant!)
Mais comme je crains dégùn (personne), je copie ton code et regarde cet aprem.
(même si je sais que je vais galérer, on ne sait jamais, une lueur d'espoir, ou de la chance peut arriver)

Et puis, c'est comme le coup du registre, même si je ne t'ai été d'aucune aide, cela m'a permis d'apprendre des choses (c'est au moins ça, lol)

Bon courage à toi,

@++

--Mortalino--
Le Mystérieux Chevalier "Provençal, le Gaulois"
0
rvblog Messages postés 792 Date d'inscription vendredi 4 mars 2005 Statut Membre Dernière intervention 12 juin 2012 7
15 sept. 2006 à 13:27
Salut 401740 PCPT, salut =647037 mortalino,

ou Quand on touche le fond de VB (au sens Cinquième dimension).

401740 PCPT, je n'ai pas de solution parfaite à ton problème, mais il existe des solutions. Tu en a trouvé une.

Tu avais donc remarqué que si tu ne prenais pas en charge les évènements avec le membre mTxt de ta classe Cls_TxtBox, les affectations fonctionnent, même avec les contrôles indexés. On pourrait donc imaginer un aiguillage de classe où tu gèrerais les contrôles non indexés dans Cls_TxtBox avec évènements, et les contrôles indexés dans Cls_TxtBoxGrp sans évènements. Au moins, tu aurais bien aussi les références aux objets indexés mais pas leurs évènements. Et à la classe d'emballage TextBoxes de gérer l'aiguillage de façon propre.

Il existe une autre solution qui ne fonctionne pas avec les contrôles intrinsèques de VB, mais avec les contrôles utilisateurs. Je ne connais pas ton besoin exact, et il se peut donc que cette solution ne convienne pas du tout. Cependant, elle a le mérite de savoir récupérer les références à des contrôles chargés dynamiquement, tout en recevant les évènements de ceux-ci. Elle utilise pour cela l'objet VB.VBControlExtender.

Ensuite, pour ajouter de la matière à réflexion, je remarque :
- que la propriété Index d'un contrôle utilisateur appartient à l'objet Extender de VB (dixit MSDN).

- que, dans ton exemple TypeName(Text1) renvoie Object, que TypeName(Text1(1)), TypeName(Text2), TypeName(Me.Controls("Text1")(1)), TypeName(Me.Controls.Item("Text1")(1))  renvoient TextBox, mais que VB donne une signature d'évènement différente pour Text1 et Text2. Etant donné qu'une même classe ne peut déclarer 2 évènements de même nom, mais de signature différente, on peut se dire qu'on a affaire à 2 classes distinctes et à un mappage de noms de classe, via la classe d'emballage Controls et le jeu des propriétés par défaut (propriété cachée .[_Default] As String), hypothèses bien sûr car je ne saurais pas le faire aussi proprement en VB (mais je pense bien qu'ils ne le font pas en VB).

Tout cela m'amène à croire que c'est l'objet Extender des ActiveX (utilisateurs) qui gère l'aiguillage des contrôles indexés (intrinsèques), via l'objet Controls de VB, et que les concepteurs ont choisi de volontairement cacher l'accès à cet objet, ce qui nous empêche de traiter directement le problème avec les contrôles intrinsèques.

Pour =647037 mortalino, on notera que les développeurs de VBA n'ont pas fait le même choix, puisqu'ils ont choisit de ne pas implémenter la possibilité de faire des groupes de contrôles dans le designer des UserForm, ni d'implémenter l'objet VB.VBExtender, ni d'implémenter les contrôles utilisateur (heureusement, il reste les modules de classe cf:http://www.vbfrance.com/codes/TABLEAU-CONTROLES-DYNAMIQUES-AVEC-EVENEMENTS_37219.aspx)

espérant faire avancer le débat,
à+

rvblog<sup>n
Je veux ton bien....et je l'aurais....mais jamais avant la page 4 des derniers échanges</sup>
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
15 sept. 2006 à 14:25
salut rvblog,
je ne m'attendais plus à une participation sur ce topic...

selon mon utilisation, je ne peux utiliser le me.controls car la collection est déclarée public pour plusieurs forms.
tu me diras, je peux lister les forms dans une collection puis blabla, mais c'est beaucoup pour peu (le but pour moi était de centraliser des restrictions différentes selon des paramètres pour tous les objets TextBox, indéxés ou non, d'un même projet, en 1 ligne de code (2 avec le déchargement en sortie)).

pour le côté dynamique, mes contrôles sont indexés mais chargés en mode conception. l'objet extender n'est donc pas  interrogeable.

pourquoi les collections indexés sont cachées par VB, en voilà une question intéressante.
pourquoi ne peut-on pas faire de groupe de contrôles comme les optionsbuttons sans passer par des méthodes maison farfelues, là aussi c'est mystère...

peut-être peut-on faire quelquechose avec le handle, objptr et copymemory...
çà serait à creuser, plus le temps actuellement ^^

le topic reste ouvert
merci de ta participation
@+
<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
rvblog Messages postés 792 Date d'inscription vendredi 4 mars 2005 Statut Membre Dernière intervention 12 juin 2012 7
18 sept. 2006 à 23:48
Au fait, on peut faire un groupe de contrôles comme les options buttons, sans passer par des méthodes maisons farfelues...:


Mets ça dans un UserControl vide :



Private m_Value As OLE_OPTEXCLUSIVE 

Public Property Get Value() As OLE_OPTEXCLUSIVE
    Value = m_Value
End Property



Public Property Let Value(ByVal vNewValue As OLE_OPTEXCLUSIVE)
    m_Value = vNewValue
    UserControl.PropertyChanged "Value"
    If m_Value Then
        UserControl.BackColor = vbRed
    Else
        UserControl.BackColor = vbBlue
    End If
End Property



Private Sub UserControl_Click()
    Me.Value = Not (Me.Value)
End Sub

Dans les attributs de procédure (avancé) de Value, mets ID de la procédure sur (Par Defaut), pour que le conteneur sache sur quelle propriété agir.
Ajoutes 2 instance groupées de ton UserControl sur un Form, affiche le Form, testes et sois ravi!

à+






rvblog<sup>n
Je veux ton bien....et je l'aurais....mieux vaut tard...que trop tard!</sup>
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
19 sept. 2006 à 00:02
alors çà c'est bon !!!!
me voilà ravi
je garde précieusement de côté.
çà ne m'aide pas pour ce topic mais j'espère m'en servir pour une idée qui me trotte depuis un moment (peut-être en 2007 )

merci rvblog
0
rvblog Messages postés 792 Date d'inscription vendredi 4 mars 2005 Statut Membre Dernière intervention 12 juin 2012 7
19 sept. 2006 à 00:11
ça me fait plaisir,


à+

PS : "alors çà c'est bon !!!! ", parce que le reste, non ? :)

rvblog<sup>n
Je veux ton bien....et je l'aurais....mieux vaut tard...que trop tard!</sup>
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
19 sept. 2006 à 00:18
^-^
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
3 déc. 2006 à 13:25
salu salut...
lien très très interessant !

résumé : MSDN ne dit pas vraiment pourquoi mais CE N'EST PAS POSSIBLE.
supposition de l'auteur : les objets pouvant être chargés dynamiquement, le conteneur ne saurait plus "de où" récupérer les évènements en cas de destruction d'une des instances de la collection de classe ou en càs de sa ré-organisation

merci de tes recherches mortalino, çà m'évite tout espoir...
il y a tout de même forcément un paliatif (sinon on ne pourrait pas indexer d'objets), je me remettrai à ce code un jour et informerai des suites

++
<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
rvblog Messages postés 792 Date d'inscription vendredi 4 mars 2005 Statut Membre Dernière intervention 12 juin 2012 7
3 déc. 2006 à 14:26
Salut 647037 mortalino, salut =401740 PCPT,

je suis navré, mais je suis obligé de m'inscrire en faux,

en effet, si on ne peut pas (sait?) affecter une "référence à un contrôle TextBox indexé" dans une variable de type TextBox, succeptible de recevoir des évènements (donc avec WithEvents), on peut (sait?) affecter une "référence à un contrôle utilisateur indexé" dans une variable du même type que le contrôle utilisateur, et succeptible de recevoir des évènements (toujours avec WithEvents). 

Le débat (et l'espoir qui s'en suit) reste donc toujours ouvert!

Dans la même famille de limitations, on retrouve :
   - Le type VBControlExtender qui ne permet pas d'affecter une variable de type "objet intrinsèque VB". Pourtant le type VBControlExtender est capable de récupérer tous les évènements de n'importe quel autre type d'objet.
   - La collection Controls (celle à qui on s'adresse, intrinsèquement, lorsque l'on écrit Text1(0)) n'est pas une collection VB (dixit le MSDN, et facilement vérifiable, en essayant d'affecter la collection Controls à une variable de contrôle du type Collection).
   - VB ne tolère pas que l'on essaye de récupérer les évènements d'un objet de type générique (donc, type Object, type Control, ...), et Me.Controls("Text1") est de type Object, alors que Me.Controls("Text1")(0) est de type TextBox et est parfaitement transtypable en type Control.
   - et surtout, VB sait le faire lorsque le contrôle est situé sur un formulaire en instance conception. La variable est une variable implicite, passant par la collection Controls (ou par un raccourci).

Bref, il doit y avoir moyen de moyenner!
à+

PS : PCPT, impressionnant le RTB! je travaillais moi-même sur une revue d'un RTB, mais orienté génération d'un code HTML plus propre (factorisation des styles, comme Word ou les CSS). J'ai de bon résultats (environ 60% en taille moyenne sur des grosses pages), mais je bute encore sur l'interface de saisie et son raffraichissement intelligent, mais ça va venir (il semble que j'ai moins de temps dispo qu'il m'en faudrait!). Il faut que j'active, car c'est une des composants principaux de mon futur Forum Explorer (toi aussi peut-être?).

rvblog<sup>n
Je veux ton bien....et je l'aurais....mieux vaut tard...que trop tard!</sup>
0
mortalino Messages postés 6786 Date d'inscription vendredi 16 décembre 2005 Statut Membre Dernière intervention 21 décembre 2011 18
3 déc. 2006 à 14:34
Salut à tous les deux,

j'ai bien essayé en changeant le Type TextBox en VBControlExtender mais VB ne veut pas (erreur type incompatible).
Même en travaillant avec le type Control, ça chibre qque part.

Peut-être faut-il créer une nouvelle classe avec les Events d'un control ?
Pis au lieu de faire Private WithEvents mTxt As TextBox, faire un Private WithEvents mTxt As MyClassWithEvents

@++

<hr width="100%" size="2" />
  --Mortalino--
Le mystérieux chevalier, "Provençal, le Gaulois"
/DIV>
0
rvblog Messages postés 792 Date d'inscription vendredi 4 mars 2005 Statut Membre Dernière intervention 12 juin 2012 7
3 déc. 2006 à 14:40
Non, le problème n'est pas là,

Même si tu fais une classe de wrapping MyClassWithEvents, ce que faisait PCPT, tu ne pourras pas affecter à son membre de référence le contrôle indexé. Et c'est là que le bâs blesse!

rvblog<sup>n
Je veux ton bien....et je l'aurais....mieux vaut tard...que trop tard!</sup>
0
rvblog Messages postés 792 Date d'inscription vendredi 4 mars 2005 Statut Membre Dernière intervention 12 juin 2012 7
3 déc. 2006 à 15:03
Je viens par contre de refaire un petit test pour vérifier une idée.

Le test est concluant : on sait affecter une "référence à un contrôle utilisateur indexé" à une variable du même type, succeptible de récupérer les évènements, par contre, si ce même contrôle utilisateur est compilé (ou est contrôle utilisateur dans un autre projet du groupe), on ne sait plus le faire (on est pas forcé d'extrapoler en disant que c'est valable pour tous les contrôles AX, mais on peut le faire quand même)!

à+
rvblog<sup>n
Je veux ton bien....et je l'aurais....mieux vaut tard...que trop tard!</sup>
0
PCPT Messages postés 13272 Date d'inscription lundi 13 décembre 2004 Statut Membre Dernière intervention 3 février 2018 47
3 déc. 2006 à 19:04
salut rvblog,

encore parmis nous? ^^
ou peut-être prends-tu le forum à reculons

rhaaa, dès qu'on essayer de toucher aux infos cachées, on fini souvent.... beh on fini pas en fait
pour ton exemple "UC compilé ou non", on peut aussi se dire que la Classe TextBox (ou autre) est compilée (ce qui est vrai) et qu'elle serait aussi apte dans le cas contraire....

autrement dit, s'il y a une issue, elle n'est pas dans cette direction

ps : merci pour le RTB, j'aime assez le rendu .
"forum explorer"... (et ce qui en dépend et y est lié), pas le temps non.... tu finieras bien avant moi

++
<hr size="2" width="100%" />Prenez un instant pour répondre à ce sondage svp
0
Rejoignez-nous