Ceci est une page optimisée pour les mobiles. Cliquez sur ce texte pour afficher la vraie page.

XL 2021 VBA - Comment savoir dans quel mode (vbModal / vbModeless) est affiché un UserForm

  • 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 !

re
encapsulé dans un module pour faire une fonction generique
Code:
Option Explicit

Private Type POINTAPI
    x As Long
    y As Long
End Type

' Déclarations API
Private Declare PtrSafe Sub mouse_event Lib "user32" ( _
    ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, _
    ByVal dwData As Long, ByVal dwExtraInfo As Long)

Private Declare PtrSafe Function SetCursorPos Lib "user32" ( _
    ByVal x As Long, ByVal y As Long) As Long

Private Declare PtrSafe Function GetCursorPos Lib "user32" ( _
    lpPoint As POINTAPI) As Long

' Constantes pour les événements souris
Private Const MOUSEEVENTF_LEFTDOWN As Long = &H2
Private Const MOUSEEVENTF_LEFTUP As Long = &H4

'----------------------------
' Fonction : SimulerClicCellule
' Description : Simule un clic gauche juste sous la cellule sélectionnée
' Retourne True si le UserForm est modal (clic sans effet)
'----------------------------
Public Function IsModal(Optional DécalageY As Long = 2) As Boolean
    Dim cell As Range
    Dim x As Long, y As Long
    Dim pt As POINTAPI
    Dim adrInit As String

    Set cell = ActiveCell
    adrInit = cell.Address

    ' Sauver la position du curseur
    GetCursorPos pt

    ' Calculer les coordonnées de la cellule décalée (sous ActiveCell)
    With ActiveWindow.ActivePane
        x = .PointsToScreenPixelsX(cell.Left)
        y = .PointsToScreenPixelsY(cell.Offset(1).Top + DécalageY)
    End With

    ' Déplacer le curseur et simuler le clic
    SetCursorPos x, y
    mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
    mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
    DoEvents

    ' Restaurer la position du curseur
    SetCursorPos pt.x, pt.y
    DoEvents

    ' Retourne True si la cellule n’a pas changé => modal
    IsModal= (ActiveCell.Address = adrInit)
End Function
 
Bonjour,
Certes cela permet de savoir le mode d'affichage du UserForm en cours mais cela ne permet pas de déterminer le UserForm actuellement affiché en vbModal parmi ceux affichés.

Edit: Sachant que sur une fenêtre on peut avoir un UserForm vbModeless ayant appelé un UserForm vbModal (l'inverse n'est pas possible) ou un UserForm vbModal ayant appelé un UserForm vbModal ce qui, dans ce dernier cas, met en échec la méthode du fichier du 1er post !
VB:
'Boucle sur tous les UserForms chargés
For Each UserForm In VBA.UserForms
    MsgBox IsModal(UserForm)
Next UserForm
 
Dernière édition:
re
quand tu hide un userform même si il est modal à la base la selection est possible après le hide
donc
dans une boucle tu les hide tous sauf le concerné et tu fait mon test et tu ré affiche ceux que tu viens de hider

je sais c'est un peu turlupiner mais bon efficace
 
En effet, le .Hide permet de sélectionner mais il permet aussi "débloquer" le .Show vbModal et du coup les instructions qui suivent vont s'exécuter.
Et même à supposer, une fois qu'ils sont en .Hide, comment tu fais pour les ré-afficher puisque que tu ne sais pas s'ils ont été affichés Modeless ou Modal ?
 
Bonsoir
pour deux userforms affichés la réponse est dans la question me semble t il non?
maintenant pour plusieurs userforms (+ de 2) ça risque d'être compliqué

ce genre de problème que tu tente de gérer je le gère depuis pas mal d'années maintenant en utilisant une fonction show perso et public dans le userform
ou j'instruis une variable publique globale module userform
qui est accessible de part sa dimension publique partout
comme par exemple dans le calendar ,le msgboxX ou le inputBoxX et même dans le CreatorRibbonX dans sa version 7 qui va sortir incessamment sous peu

je pars du principe que quand l'instruction d'une donnée comme une variable vbmodal ou vbmodeless devient trop compliqué et certainement difficile a maintenir et adapter a toute config que le faire soi même est la solution la plus raisonnable
 
Une variable Public, la solution de @wDog66 avec son Dictionary, ou même la propriété UserForm.Tag pour y stocker de l'info. Ça reste du manuel.
C'est quand même dommage de ne pas trouver le flag d'Excel via une API ou autre. Ils auraient pu le rendre disponible, ou simplement mettre la propriété ShowModal en lecture.
 
C'est quand même dommage de ne pas trouver le flag d'Excel via une API ou autre. Ils auraient pu le rendre disponible, ou simplement mettre la propriété ShowModal en lecture.
Hello,
avec UIAutomation, on peut savoir si un formulaire est en mode modal ou pas . Exemple :
VB:
Function IsModal(TitreFen) As Boolean
 Dim c As New CUIAutomation, oExcel As IUIAutomationElement, oUSF As IUIAutomationElement
  Set oExcel = c.ElementFromHandle(ByVal Application.ActiveWindow.Hwnd)
  Set oUSF = GetUiElem(c, oExcel, "Name", TitreFen, TreeScope_Children)
  Debug.Print oUSF.CurrentName
  IsModal = oUSF.GetCurrentPropertyValue(UIAutomationClient.UIA_WindowIsModalPropertyId)
  Debug.Print IsModal
End Function
Function GetUiElem(c As CUIAutomation, _
                       Parent As IUIAutomationElement, _
                       TypeCondition, _
                       ValCondition, _
                       ByVal TreeScope As TreeScope) As IUIAutomationElement
Dim x As Integer, obj As IUIAutomationElement, Condition As IUIAutomationCondition
x = 0
Select Case TypeCondition
    Case "Name"
          Set Condition = c.CreatePropertyCondition(UIAutomationClient.UIA_NamePropertyId, ValCondition)
    Case "AutoId"
          Set Condition = c.CreatePropertyCondition(UIAutomationClient.UIA_AutomationIdPropertyId, ValCondition)
    Case "Class"
          Set Condition = c.CreatePropertyCondition(UIAutomationClient.UIA_ClassNamePropertyId, ValCondition)
    Case "CtrlType"
          Set Condition = c.CreatePropertyCondition(UIAutomationClient.UIA_ControlTypePropertyId, ValCondition)
    Case Else
          Set Condition = c.CreateTrueCondition
    End Select
Set GetUiElem = Parent.FindFirst(TreeScope, Condition)
End Function

Sub Test()
   Debug.Print IsModal("Affichage TB")
End Sub

A noter qu'il faut se méfier du c.ElementFromIAccessible pour récupérer un objet UIAutomation car on ne récupére pas toujours alors toutes les
propriétés ( c'est ce qui m'est arrivé avec le formulaire, je ne récupérais pas la propriété is Modal et c'est pour cela que je suis passé par la fenêtre Excel et ses descendants).

Ami calmant, J.P
 
Il y a un petit souci @jurassic pork...
Quand les 2 sont du même mode ça fonctionne, mais pas si le 1er est Modeless et le 2ème Modal. Peut-être parce que le Parent est le même ?
A moins que j'ai raté quelque chose.
J'ai fait un essai avec 3 formulaires en utilisant FlaUinspect pour regarder la valeur de is Modal :
1 - Si je mets les 3 Formulaires en mode vbModeless , j'ai bien les 3 formulaires qui sont vus en état non modal.
2 - Par contre si je mets un formulaire en mode modal , les 3 Formulaires sont vus en état modal.
3 - La valeur de la propriété WindowInteractionState est à la valeur Running sur les 2 formulaires lancés en mode Non modal et celui lancé en mode Modal à comme valeur ReadyForUserInteraction
VB:
' Running = 0  - ReadyForUserInteraction = 2
Debug.Print oUSF.GetCurrentPropertyValue(UIAutomationClient.UIA_WindowWindowInteractionStatePropertyId)
 
Dernière édition:
re
une idée juste comme ça en passant
si on affiche un userform modal on ne peut plus rien faire
celui qui est modal n'est pas sensé être la dernière fenêtre de type userform ?

cela dit je suis toujours perplexe sur ce besoin
sachant que le modal bloque tout
donc la sub de control , a part être lancée du userform modal ne peut pas être lancée donc elle est lancé de celui ci
parti de la ..................
 
Voici ce que veut Dudu2
Pour que cela soit possible il faut que les classeurs soient ouverts dans des instances différentes d'Excel ( pour ouvrir une nouvelle instance : ALT + Excel) Dans une même instance d'Excel on est bloqué tant qu'il y a un formulaire modal affiché.
 
cela dit je suis toujours perplexe sur ce besoin
sachant que le modal bloque tout
Il y a en effet la problématique initiale que rappelle @jurassic pork.
Et il y a la problématique de la création d'un nouveau classeur alors qu'un UserForm Modal est affiché.
Excel dit d'abord:

Mais le fait quand même.
Alors certes on ne peut pas y faire grand chose à part des sélections, mais moi ça me gène car j'ai mis en place un système de UserForm <Nom de classeur> pour un "utilisateur" qui a besoin de voir clairement le nom des classeurs sur lesquels il travaille alors que le nom inscrit dans l'entête est en fonte très petite. C'est un "pro" qui manipule 2 à 4 classeurs simultanément et qui a besoin d'identifier ce sur quoi il est positionné.
 
Dernière édition:
donc si je comprends bien
tu a un userform retaillé façon etiquette
que tu place au centre de la caption du classeur actif
et tu a certainement un label dans ce userform donnant le nom du classeur
c'est bien ça ?
 
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

  • Question Question
Microsoft 365 affichage userform
Réponses
4
Affichages
361
Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…