XL 2013 Userform modifier "set focus" pour revenir sur dernière textbox utilisée

jptaz15

XLDnaute Nouveau
Bonjour à tous,

j'ai beau chercher, mais je ne trouve pas exactement ce que j'ai besoin. Dans mon userform, j'ai un cadre avec plusieurs textbox et à l'extérieur du cadre une listbox avec différents éléments qui, lorsque double cliqués vont s'insérer dans la textbox choisie. Cependant, à chaque fois que je clique sur un mot dans ma listbox et que je reviens dans mes textbox, le focus retourne sur la première textbox, ce qui est peut être énervant lorsqu'il y en a beaucoup.

Y a t-il un moyen de conserver le curseur sur la dernière textbox utilisée? J'ai pensé utilisé "set focus", mais je ne vois pas comment...

Voici en pièce jointe une exemple avec qq textbox, mais noter qu'il devrait y en avoir une trentaine...

merci pour votre aide
 

Pièces jointes

  • double clic.xlsm
    22.2 KB · Affichages: 16
Solution
bonjour
1° vire moi ce module classe
2° vire moi ce module qui sert pour la variable public
3° vire moi ce code dans le userform

4° pour libérer la listbox et reprendre le focus sur le textbox precedement sélectionné il te faut utiliser l'event adequat
voilà maintenant que c'est propre met ce code dans le userform
VB:
Option Explicit
Public WithEvents TbTX As MSForms.TextBox
Dim cls() As New UserForm1
Public activeTxTbox As Object

Private Sub ListBox1_Click()
activeTxTbox = ListBox1.Value 'pas besoins qu'il est le focus pour etre bien ciblé on lui met la valeur choisi
End Sub

'FACULTATIF!!!!!!!!!!
Private Sub ListBox1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
'With activeTxTbox...

patricktoulon

XLDnaute Barbatruc
re
Bonjour
c'est normal certain events et propriété de control ne sont pas accessibles a partir d'un event control de substitution
et ça on y peut rien c'est comme ça

pour palier à ça au lieu d'utiliser le nom de l'events de substitution
j'utilise par exemple pour les propriété
dans la classe

public withevents TBTX as msforms.textbox
et dans l'event de substitution
userform1.controls(TBTX.name).propriété

ou
je met l'event dans le userform normalement
et je le "application.run evenement dans le userform" a partir d'un event classe

on voit bien ici dans l'implémentation dans le module classe
que certains events ne sont pas dispo pour le textbox
demo7.gif


à contrario avec un event dans le userform
demo7.gif
 
Dernière édition:

Dranreb

XLDnaute Barbatruc
Je montre aussi l'interface Casso implémentée tant qu'à faire :
VB:
Rem. Définition de l'objet Casso. Module d'interface avec les CAsso de différents types spécifiques.
'(Peu usité, un module d'interface ne contient que des propriétés et méthodes vides de tout code. Ce seront les procédures _
 correspondantes des modules de classe portant l'instruction Implements CAsso qui seront exécutées à leurs places.)
Option Explicit

' Méthode à usage exclusif de l'objet ControlsAssociés parent de cet objet.
' Effectue l'opération d'initialisation requise par sa méthode Add.
Public Sub Init(ByVal Parent As ControlsAssociés, ByVal Ctl As MSForms.Control, _
   ByVal Index As Long, ByVal Col As Long, ByVal Format As String, ByVal Mode): End Sub
 
' Ctl :  Propriété en lecture seule: Contrôle supporté par l'objet.
Function Ctl() As MSForms.Control: End Function

' Index :  Propriété en lecture seule: Numéro d'ordre de cet objet dans son parent ControlsAssociés.
Function Index() As Long: End Function

' Col :  Propriété en lecture seule: Numéro de la colonne contenant sa valeur dans le tableau à mettre à jour.
Function Col() As Long: End Function

' Format :  Propriété en lecture seule. Format appliqué par VBA.Format lors de la conversion de valeur en le texte affiché dans le contrôle.
Function Format() As String: End Function

' Mode :  Propriété en lecture seule. En vue d'une utilisation non prédéfinie, à votre discrétion.
Function Mode(): End Function

' Valeur :  Propriété en lecture/écriture: Valeur de cellule correspondant au texte affiché par le contrôle.
Property Let Valeur(ByVal V): End Property
Property Get Valeur(): End Property
 

patricktoulon

XLDnaute Barbatruc
@Dudu2
voici 3 userform identiques

methodeinterne classe Interne (patricktoulon)

methode1 module class1 classique basique instancié dans le userform

methode3 module class2 classique mais le travail de classement se fait dans la classe
la classe parent instanciée dans le userform contient toute les autres
il suffit de mettre classparent a nothing et les autres sont détruites
 

Pièces jointes

  • class textbox diverses methodes.xlsm
    32.1 KB · Affichages: 5

Dranreb

XLDnaute Barbatruc
Et même la classe principale ControlsAssociés supportant l'ensemble des contrôles associés :
VB:
Option Explicit
Event Change(ByVal CAM As CAsso)
Event Click(ByVal CAM As CAsso)
Event KeyDown(ByVal CAM As CAsso, ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Event KeyPress(ByVal CAM As CAsso, ByVal KeyAscii As MSForms.ReturnInteger)
Event KeyUp(ByVal CAM As CAsso, ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Private LCs As ListColumns, TCAssos() As CAsso, NePasExécuterChange As Boolean
Property Set Colonnes(ByVal LCsTab As ListColumns)
' — Affectez par un Set à .Colonnes la .LiscColumns du ListObject traité ou bien la .Colonnes d'un
'  ComboBoxLiées si vous voulez pouvoir spécifier ses titres aux Add en guise de Colonne.
   Set LCs = LCsTab
   End Property
Public Sub Add(ByVal Ctl As MSForms.Control, Optional ByVal Colonne As Variant = -1, _
   Optional ByVal Format As String = "", Optional ByVal Mode = Empty)
' — Arguments :
'  Ctl :  Le contrôle à ajouter.
'  Colonne :  La colonne dans le tableau.
'  Format :  Le format de conversion de la valeur en le texte affiché dans le contrôle.
'  Mode :  Ce que vous aimeriez retrouver en CAM.Mode pour orienter un traitement d'évènement.
   Dim I As Long
   CorrigerColonne Colonne, "Add Me." & Ctl.Name
   I = Me.Count + 1: ReDim Preserve TCAssos(1 To I) As CAsso
   Select Case True
      Case TypeOf Ctl Is MSForms.TextBox:    Set TCAssos(I) = New CAssoTBx
      Case TypeOf Ctl Is MSForms.ComboBox:   Set TCAssos(I) = New CAssoCBx
      Case TypeOf Ctl Is MSForms.OptionButton: MsgBox "Contrôle de type ""OptionButton"" non supporté," _
         & vbLf & "mais un ""Frame"" en contenenant serait accepté.", _
         vbCritical, "ControlsAssociés Add Me." & Ctl.Name: End
      Case TypeOf Ctl Is MSForms.CheckBox:   Set TCAssos(I) = New CassoCkx
      Case TypeOf Ctl Is MSForms.Frame:      Set TCAssos(I) = New CAssoFrm
      Case TypeOf Ctl Is MSForms.Image:      Set TCAssos(I) = New CAssoImg
      Case Else: MsgBox "Contrôle de type """ & TypeName(Ctl) & """ non supporté actuellement", _
         vbCritical, "ControlsAssociés Add Me." & Ctl.Name: End: End Select
   TCAssos(I).Init Me, Ctl, I, Colonne, Format, Mode
   End Sub
Public Function Count() As Long
   On Error Resume Next: Count = UBound(TCAssos)
   End Function
Public Function Item(ByVal Index As Variant) As CAsso
   Dim I As Long, Nom As String
   If IsObject(Index) Then
      For I = 1 To UBound(TCAssos)
         Set Item = TCAssos(I): If Item.Ctl Is Index Then Exit Function
         Next I
      Set Item = Nothing: On Error Resume Next: Nom = Index.Name: If Err Then Nom = "sans nom"
      MsgBox "Cet objet " & Nom & " de type " & TypeName(Index) & " n'a pas fait l'objet d'un Add.", _
         vbCritical, "ControlsAssociés.Item"
   Else
      Set Item = TCAssos(Index)
      End If
   End Function
Public Function NbRenseignés() As Long
   Dim I As Long, C As Long
   For I = 1 To UBound(TCAssos): NbRenseignés = NbRenseignés + 1 - IsEmpty(TCAssos(I).Valeur): Next I
   End Function
Public Sub ValeursDepuis(T())
   Dim I As Long, C As Long
   NePasExécuterChange = True
   For I = 1 To UBound(TCAssos)
      C = TCAssos(I).Col: If C > 0 Then TCAssos(I).Valeur = T(1, C)
      Next I
   NePasExécuterChange = False
   End Sub
Public Sub ValeursVers(T())
   Dim I As Long, C As Long
   For I = 1 To UBound(TCAssos)
      C = TCAssos(I).Col: If C > 0 Then T(1, C) = TCAssos(I).Valeur
      Next I
   End Sub
Public Sub ÉcrireConstantes(ByVal OùÇa)
   Dim RngDest As Range
   Select Case True
      Case TypeOf OùÇa Is Range: Set RngDest = OùÇa
      Case TypeOf OùÇa Is ListRow: Set RngDest = OùÇa.Range
      Case IsNumeric(OùÇa): Set RngDest = LCs.Parent.ListRows(OùÇa).Range
      Case IsArray(OùÇa): MsgBox "Cette méthode a besoin d'un Range pour vérifier si" _
         & vbLf & "ses cellules ne portent pas de formule à ne pas écraser." _
         & vbLf & "Donc type " & TypeName(OùÇa) & "non supporté.", _
         vbCritical, "ÉcrireConstantes": End
      Case Else: MsgBox "Destination de type " & TypeName(OùÇa) & " non supportée.", _
         vbCritical, "ÉcrireConstantes": End
      End Select
   Dim I As Long, C As Long
   For I = 1 To UBound(TCAssos)
      C = TCAssos(I).Col
      If C > 0 And Not RngDest(1, C).HasFormula Then RngDest(1, C) = TCAssos(I).Valeur
      Next I
   End Sub
Public Function ValeurDifférente(T()) As Boolean
   Dim I As Long, C As Long
   For I = 1 To UBound(TCAssos)
      C = TCAssos(I).Col: If C > 0 Then ValeurDifférente = TCAssos(I).Valeur <> T(1, C)
      If ValeurDifférente Then Exit Function
      Next I
   End Function
Public Property Let Enabled(ByVal B As Boolean)
   Dim I As Long
   For I = 1 To UBound(TCAssos)
      TCAssos(I).Ctl.Enabled = B
      Next I
   End Property
Private Sub CorrigerColonne(Colonne As Variant, ByVal TitreMsg As String)
   On Error Resume Next
   Select Case TypeName(Colonne)
      Case "String": If LCs Is Nothing Then MsgBox "Colonne String interdite car Colonnes non initialisé.", _
         vbCritical, TitreMsg: Exit Sub
         Colonne = LCs(Colonne).Index
         If Err Then MsgBox "Colonne """ & Colonne & """ inconnue dans " & LCs.Parent.Name, _
            vbCritical, TitreMsg: Exit Sub
      Case Else: If Not IsNumeric(Colonne) Then MsgBox "Type de donnée """ & TypeName(Colonne) & _
         """ non supporté comme spécification de colonne.", vbCritical, TitreMsg: Exit Sub
      End Select
   End Sub
Public Sub CAM_Change(ByVal CAM As CAsso)
   If NePasExécuterChange Then Exit Sub
   RaiseEvent Change(CAM)
' Si l'UserForm utilise un ComboBoxLiées nommé CLs, Conseil: CLs.UnContrôleAChangé (Pour détection CLs.ChangéÀLEchap)
   End Sub
Public Sub CAM_KeyDown(ByVal CAM As CAsso, ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
   RaiseEvent KeyDown(CAM, KeyCode, Shift)
' Si l'UserForm utilise un ComboBoxLiées nommé CLs, Conseil: CLs.ToucheAppuyée KeyCode (Pour détection CLs.ChangéÀLEchap)
   End Sub
Public Sub CAM_KeyPress(ByVal CAM As CAsso, ByVal KeyAscii As MSForms.ReturnInteger)
   NePasExécuterChange = True
   RaiseEvent KeyPress(CAM, KeyAscii)
   NePasExécuterChange = False
   End Sub
Public Sub CAM_KeyUp(ByVal CAM As CAsso, ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
   RaiseEvent KeyUp(CAM, KeyCode, Shift)
   End Sub
 

Dudu2

XLDnaute Barbatruc
@ Dranreb,

En effet, j'ai repris l'exemple du début et certains évènements ne sont pas déclenchés avec un MSForms.TextBox. Je n'ai pas tout testé mais effectivement Enter et Exit ne le sont pas

Un MouseDown est détecté donc avec le fichier initial ça fonctionne avec la classe (fichier ci-dessous).

Par contre je ne comprends pas trop dans quelles conditions tu peux être amené à faire un SetFocus dans le module de classe. Quand l'instance de classe est appelée le Control a forcément le Focus.
A moins que tu n'essaies de faire un SetFocus sur un autre Control ?

De manière générale, il y a des problèmes à faire un SetFocus sur un contrôle:
- Après un MsgBox quand le Control a déjà le Focus
- sur l'évènement Exit de ce Control.
Dans les 2 cas il faut passer par un asynchronisme (Application.OnTime Now)
 

Pièces jointes

  • double clic-1.xlsm
    21.6 KB · Affichages: 1

Discussions similaires

Statistiques des forums

Discussions
312 168
Messages
2 085 907
Membres
103 029
dernier inscrit
ndembi sylver