XL 2016 UserForm vbModeless - Ré-activation ne donne pas le Focus à l'ActiveControl

  • Initiateur de la discussion Initiateur de la discussion Dudu2
  • Date de début Date de début

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

Dudu2

XLDnaute Barbatruc
Bonjour,

C'est expliqué dans le fichier:

1640470057461.png


Bien que j'ai pu ré-activer le UserForm vbModeless sur son MouseMove() (différentes options essayées), le focus ne vient pas dans l'ActiveControl du UserForm.
Si vous avez un idée...

Edit: Faut-il se rabattre sur la génération d'un clic souris sur les coordonnées de l'ActiveControl ?
Cordialement.
 

Pièces jointes

Dernière édition:
Solution
re
Bonjour @Dudu2
comme je te l'ai dit il faut sortir des sentiers battus
je reprend ton userform
j'ajoute un textebox en plus qui sera masqué si il faut si tu en a déjà plusieurs c'est pas la peine d'en ajouter

donc
dans ton exemple j'ajoute un textbox même de taille zero si tu veux

demo.gif


ensuite je vire tout ton code entièrement
je vais gérer le sélection change dans le userform directement
dans cet event je vais pointer l'activecntrol

et au mouve dans le userform si un control a été pointer je le reactive en le disablant et le re enabilisant
parti de la il est actif et je lui done le focus et selstart
le tour est joué
VB:
Public WithEvents feuille As Worksheet
Public ctrl As Object

Private Sub...
re
Bonjour @Dudu2
comme je te l'ai dit il faut sortir des sentiers battus
je reprend ton userform
j'ajoute un textebox en plus qui sera masqué si il faut si tu en a déjà plusieurs c'est pas la peine d'en ajouter

donc
dans ton exemple j'ajoute un textbox même de taille zero si tu veux

demo.gif


ensuite je vire tout ton code entièrement
je vais gérer le sélection change dans le userform directement
dans cet event je vais pointer l'activecntrol

et au mouve dans le userform si un control a été pointer je le reactive en le disablant et le re enabilisant
parti de la il est actif et je lui done le focus et selstart
le tour est joué
VB:
Public WithEvents feuille As Worksheet
Public ctrl As Object

Private Sub feuille_SelectionChange(ByVal Target As Range)
Set UserForm1.ctrl = ActiveControl
End Sub

Private Sub UserForm_Activate()
Set feuille = ActiveSheet
End Sub


Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
If Not UserForm1.ctrl Is Nothing Then
ctrl.Enabled = False: ctrl.Enabled = True: ctrl.SetFocus
ctrl.SelStart = Len(ctrl.Value)
End If
End Sub
démonstration
demo.gif
 
Dernière édition:
Bonjour @patricktoulon,

Je sais pas d'où t'es venue l'idée mais c'est très original.
Le problème avec ta solution, c'est que le Selectionchange() de la feuille est dans le code du UserForm.
Du coup tous les traitements normalement liés à cet évènement il faut les mettre là-dedans ?
Ou bien le SelectionChange standard de la feuille marche encore ?

J'ai remarqué que ta séquence:
VB:
ctrl.Enabled = False: ctrl.Enabled = True: ctrl.SetFocus
a un effet dans mon code.
L'ActiveControl est initialement sur TextBox1, il passe de TextBox1 à TextBox2 et TextBox1enabled = False !
Ça c'est un truc de ouf !
Je vais essayer d'exploiter cet étrange phénomène !
 
re
Je sais pas d'où t'es venue l'idée mais c'est très original.
ben c'est de notoriété public que je suis un original 😅😂🤣😂


Du coup tous les traitements normalement liés à cet évènement il faut les mettre là-dedans ?
Ou bien le SelectionChange standard de la feuille marche encore ?
non tu peux laisser l'events original faire son job comme si rien n’était l'event dans le userform est un calque
il me semblait te l'avoir déjà dit dans une autre discussion ou alors c'est quelqu'un d'autre je sais plus
je vais tester un exemple a plusieurs textbox pour voir

pourquoi le calque de l'event dans le userform
et bien tout simplement par ce feuille est devenu enfant du userform (Attention uniquement dans le calque) )mais pas réellement c'est une simple question d'instance de classe event
 
Ceci dit, ce qui agite le cocotier dans le SetFocus au retour de la pseudo-réactivation du UserForm, c'est comme je le disais ci-dessus ton improbable séquence:
Code:
ctrl.Enabled = False: ctrl.Enabled = True: ctrl.SetFocus

Merci pour cette improbable séquence de génie ! 😉

Aussi l'ai-je intégrée dans mon code et ça fonctionne.
A condition effectivement, comme pour ton code, d'avoir au moins un autre Control dans le UserForm (TextBox, CommandButon, etc...) parce que le ctrl.Enabled = False fait évidemment passer le Focus au Control suivant qui doit exister.


1640518949005.png


Voir fichier ci-dessous.
 
Dernière édition:
En fait, si tu remplaces la séquence:
VB:
Set Ctrl = Me.ActiveControl
Ctrl.Enabled = False
Ctrl.Enabled = True
Ctrl.SetFocus

Par la séquence:
VB:
Set Ctrl = Me.ActiveControl
CreateObject("wscript.shell").SendKeys ("{TAB}")
DoEvents    'SendKeys synchrone
Ctrl.SetFocus

Tu obtiens le même résultat.
Car il faut agiter le cocotier dans le UserForm pour que ce
1640519701222.gif
SetFocus se décide à faire ce pour quoi il est fait !!!
 

Pièces jointes

j'avoue je comprends les ligne de code mais (comme c'est dans le même event ) je ne comprends pas ton fonctionnement

si je comprends bien
au move tu senkeys un tab pour activer un ctrl (bref tu secoue tout çà)et tu active celui qui a été précédemment déterminé

mais a quel moment AVEC_SENDKEYS devient false
est ce que ces dieze devant les if dans l'event "move" ferait que l'on serait alors en fonctionnement adressof
ce qui permet effectivement un subclassing et donc un ré amorcage de la variable AVEC_SENDKEYS ??
sinon je pige pas
 
ok je pense avoir pigé
c'est toujours le enabled true false qui sauve la mise
en effet quand on le dé active et réactive c'est lui qui reprend le focus même si ça n'est pas traduit graphiquement à l’écran donc avec la condition du bon handle soit c'est le send keys soit c'est lma manip qui réactive le textbox
+le set focus et selstart a la fin
c'est tordu quand même
je préfère ma version qui est explicite quand on sélectionne on mémorise quand on revient on fait ma manip "enabled"
 
heu... ben non j'avais tout faux
en fait la condition handle suffit
le sendkeys c'est juste pour activer n'importe le quel
et ensuite les 3 ligne pour le setfocus du ctrl qui me remet le bon
c'est tout
à cela j'ajoute(j’enlève tout du moins les apis et les remplace par la macro4
et voilà j'ai le même résultat
en gros ta constante ne sert a rien
VB:
Option Explicit
Private MeHWnd As Variant
'-------------------
'Activation UserForm
'-------------------
Private Sub UserForm_Activate()
    MeHWnd = ExecuteExcel4Macro("CALL(""user32"",""GetActiveWindow"",""JCC"")")          'handle fenetre active
    Me.TextBox1.SetFocus
End Sub

'----------------------
'Survol souris UserForm
'----------------------
Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    Dim Ctrl As Variant
    If MeHWnd <> ExecuteExcel4Macro("CALL(""user32"",""GetActiveWindow"",""JCC"")") Then
        Me.Show vbModeless
        Set Ctrl = Me.ActiveControl
        CreateObject("wscript.shell").SendKeys ("{TAB}")
        DoEvents    'SendKeys synchrone
        Ctrl.SetFocus
        If TypeOf Ctrl Is TextBox Then
            Ctrl.SelStart = Len(Ctrl.Value)
        End If
    End If
End Sub

rigolo non ?😉
 
C'est ça, il faut secouer le cocotier d'une manière ou d'une autre (c'est à dire passer au Control suivant par un moyen quelconque***) pour que le SetFocus joue enfin son rôle à l'écran ce qu'il devrait normalement faire mais ne fait pas dans ce cas, ce qui n'est PAS normal.

***Ce moyen est ici:
- soit un Ctrl.Enabled = False (fait passer le Focus sur le Control suivant si Ctrl a le Focus car on ne peut pas avoir le Focus sur un Control non-Enabled, donc Excel passe au suivant)
- soit un SendKeys Tabulation synchrone (fait passer le Focus sur le Control suivant)

en gros ta constante ne sert a rien
En effet, d'ailleurs, au UserForm_Activate() tu as judicieusement replacé le FindWindow par un GetActiveWindow ce qui simplifie l'affaire. J'ai reporté la modif dans mon fichier avec API ci-dessus.

Merci pour ta version ExecuteExcel4Macro dont tu es LE Grand Spécialiste 😉.
 
Dernière édition:
Bon j'ai le même souci que le problème de départ avec UiAutomation mais je m'en sors avec un click dans la TextBox :
VB:
'Declare mouse events
Public Declare PtrSafe Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As LongPtr
Public Declare PtrSafe Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Public Const MOUSEEVENTF_LEFTDOWN = &H2
Public Const MOUSEEVENTF_LEFTUP = &H4
Public Const MOUSEEVENTF_RIGHTDOWN As Long = &H8
Public Const MOUSEEVENTF_RIGHTUP As Long = &H10

Sub FocusTextBox1()
    Dim oTxtBox As IAccessible, UIA_TxtBox As IUIAutomationElement,  i as Integer
    Dim oUIA As New CUIAutomation, rect As UIAutomationClient.tagRECT
    Set oTxtBox = UserForm1.TextBox1
    Set UIA_TxtBox = oUIA.ElementFromIAccessible(oTxtBox, 0)
    UIA_TxtBox.SetFocus
    rect = UIA_TxtBox.CurrentBoundingRectangle
    SetCursorPos rect.Left + 5, rect.Top + 5
    mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
    DoEvents
    mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
End Sub
 
Notre forum d’entraide est 100 % gratuit et le restera.
Aucune formation payante, aucun fichier à acheter, rien à vendre. Mais comme tout site, nous devons couvrir nos frais pour continuer à vous accompagner.
Soutenez-nous en souscrivant à un compte membre : c’est rapide, vous choisissez simplement votre niveau de soutien et le tour est joué.

Je soutiens la communauté et j’accède à mon compte membre
Retour