XL 2016 VBA - Taux de recouvrement d'un RECT par un autre RECT

Dudu2

XLDnaute Barbatruc
Bonjour à tous,

Le point de départ de ce problème est la question "doit-on changer le OWNER d'un UserForm" ?
Parce que s'il est placé ou déplacé sur l'une des fenêtres d'un classeur qui n'est pas son OWNER, on le sait grâce à l'évènement UserForm_Layoit(), il sera masqué totalement ou partiellement par cette fenêtre dès lors qu'elle sera active. Et dans ce cas, il faut changer son OWNER par le Handle de la fenêtre en question.

D'où la question... Quel est le taux de recouvrement du UserForm RECT par un Window RECT.

La fonction PourcentageUserFormSurfaceCouverteParWindow dans ce fichier est à écrire !
 

Pièces jointes

  • Classeur5.xlsm
    29.9 KB · Affichages: 1
Dernière édition:

Dudu2

XLDnaute Barbatruc
Alors j'ai bien une solution, un peu inattendue et inspirée par la chance, mais si quelqu'un en a 1 autre pour comparer, welcome. Sinon, laissez tomber ça ira. Je ne pensais pas y arriver si vite en tous cas.

Fichier supprimé car bug !
 
Dernière édition:

Dranreb

XLDnaute Barbatruc
Bonsoir.
Moi j'ai quelques UserForm que je force à être toujours au premier plan même si une autre fenêtre s'ouvre par dessus. Je vais rechercher lesquels et comment j'ai fait …

Ouais c'est ce truc là :
VB:
Private Sub UserForm_Activate()
   SetWindowPos GetForegroundWindow, -1, 0, 0, 0, 0, 3 ' Pour le forcer à rester affiché.
   SetWindowLong GetForegroundWindow, -8, 0 ' Pour le rendre indépendant de toute autre fenêtre.
   End Sub
Les API :
VB:
         #If VBA7 Then
Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As Long
Private Declare PtrSafe Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _
   ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
   (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
VB:
Private Sub UserForm_Activate()
   SetWindowPos GetForegroundWindow, -1, 0, 0, 0, 0, 3 ' Pour le forcer à rester affiché.
   SetWindowLong GetForegroundWindow, -8, 0 ' Pour le rendre indépendant de toute autre fenêtre.
   End Sub
Alors oui, le -8 connu sous le petit nom de GWL_HWNDPARENT permet de changer le Owner de la fenêtre, ici le UserForm. C'est là que je place non pas 0 mais le Handle de la fenêtre du classeur à laquelle je veux le rattacher.
Faudrait que je fasse des essais avec ce 0 pour voir si j'obtiens un résultat compatible avec l'usine à gaz que j'ai construite autour de l'affichage multi-moniteurs et de la minimisation.
 

patricktoulon

XLDnaute Barbatruc
re
bonsoir @Dudu2
de toute façon le raisonnement des rectangles n’était pas bon
calculer l'intersection de deux RECT n'est pas compliqué mais ça ne dit pas qui recouvre qui
donc le setwindowPos (...,...,...,..,&hxx) te garantie le on top de la fenêtre désignée par sa poignée

j'ajouterais que le setparent de permet d'affilier le userform a une fenêtre
et si la fentre affiliées est l'application la fenêtre userform reprend une allure Old scool
mais a ce moment là un autre classeur ou autre fenêtre pourrais eventuellement passer par dessus
donc setwindowposition
 

Dudu2

XLDnaute Barbatruc
Bonsoir @patricktoulon,
Définir le Parent et le Owner d'un UserForm c'est 2 choses différentes.

Si tu définis une Window comme Parent du UserForm, il ne pourra pas être affiché en dehors de cette fenêtre. De plus l'apparence, du moins chez moi en Office 2016, n'est pas la même.

Si tu définis une Window comme Owner ce n'est pas le cas, mais alors le UserForm sera toujours "devant" la Window même si elle est activée. C'est le comportement normal.

La doc Windows qui montre que c'est bien différent:
1718476904736.png

calculer l'intersection de deux RECT n'est pas compliqué
Ben ce n'est pas si évident que ça et j'ai eu du bol d'avoir l'inspiration qui va bien.
Et ce calcul est bien fait pour savoir quelle part en % du UserForm est recouvert par une Window et pas l'inverse. Y a pas de hasard.

Dans mon traitement je recherche la fenêtre d'un classeur multi-fenêtré qui recouvre le plus le UserForm et si ce n'est pas la Window Owner (GetWindow(UserFormHandle, GW_OWNER)) je la défini comme Owner histoire de ne pas masquer le UserForm lors de l'activation de cette fenêtre la plus recouvrante.

Après je testerai ce SetWindowLong UserFormHandle, GWL_HWNDPARENT, 0 de @Dranreb, mais j'ai des réserves quant au fait de détacher complètement un UserForm de son classeur parent via l'une de ses Windows. Faut voir... Seuls les tests le diront.
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
perso comme tu le sais je n'utilise quasiment plus pour la user32 les déclarations mais plutôt les macro 4

et quand on fait un on top avec setwindowpos le userform ne peut être recouvert , il reste au premier plan même si ce n'est plus lui qui a le focus
VB:
Sub Premier_Plan()
    Dim hwnd&
     hwnd = ExecuteExcel4Macro("CALL(""user32"",""GetActiveWindow"",""JCC"")")
    ExecuteExcel4Macro ("CALL(""user32"",""SetWindowPos"",""JJJJJJJJ""," & hwnd & ", " & -1 & ", " & 0& & ", " & 0& & ", " & 0& & ", " & 0& & ", " & (&H43) & ")")
  End Sub
 

Dudu2

XLDnaute Barbatruc
Oui je sais que tu es un expert, sinon l'Expert XLD voire mondial, des ExecuteExcel4Macro !
Perso je préfère quand même les appels natifs car la lisibilité est meilleure même s'il faut se farcir les déclarations.

Je vois que dans ton ExecuteExcel4Macro tu fais comme @Dranreb avec HWND_TOPMOST (-1) pour forcer un affichage "devant".

Ce qui me faire dire que j'ai 2 choses à tester:
- le SetWindowPos en HWND_TOPMOST
- le SetWindowLong GWL_HWNDPARENT avec un Handle à 0

Les gars, vous me donnez un sacré boulot ! 🤣
 

Dudu2

XLDnaute Barbatruc
Bonjour,
J'aime bien le Call SetWindowPos(UserFormHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE).
Ça m'évite effectivement de gérer le changement d'Owner pour les recouvrements par des Windows autres.
Par contre c'est du violent. Devant c'est devant ! Rien n'y résiste, pas même une autre application.
Mais le jeu en vaut la chandelle.
 

Dudu2

XLDnaute Barbatruc
Et j'aime aussi beaucoup le Call SetWindowLongPtr(UserFormHandle, GWL_HWNDPARENT, 0) qui permet de rendre le UserForm indépendant de la fenêtre qui l'a créé, de sorte que si cette fenêtre est fermée et que le classeur est multi-fenêtré, le UserForm n'est pas détruit par la fermeture de sa fenêtre initialement Owner.

Merci pour ces tuyaux !
 

patricktoulon

XLDnaute Barbatruc
Re
je ne comprends pas trop ce que tu cherche à faire mais le topmost suffit
le userform restera toujours au premier plan
pas besoins de vider le windowlong avec le "-8" du setwindowlong
comme tu peux le voir le userform reste dessus même en activant une autre fenêtre excel
demo1.gif
 

Dudu2

XLDnaute Barbatruc
Hélas, le Call SetWindowLongPtr(UserFormHandle, GWL_HWNDPARENT, 0) qui permet de rendre le UserForm indépendant de la fenêtre qui l'a créé, casse la minimisation par défaut qui va dans le Primary Monitor en bas à gauche. Le UserForm.Top = -19200 et le UserForm.Left = -19200.

Alors ça se corrige à condition de différencier la minimisation en Monitor et la minimisation en TaskBar ce que je ne peux plus faire car ces valeurs Top et Left sont aussi celles de la minimisation en TaskBar.

De plus la correction n'est possible qu'en intervenant lors du UserForm_Layout() quand on sait que le UserForm.Height < 30. Et cette intervention en UserForm_Layout() n'est pas systématiquement placée par l'utilisateur des fonctions.

Donc je reviens en arrière sur ce point, à grands regrets.
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
@patricktoulon;
je ne comprends pas trop ce que tu cherche à faire mais le topmost suffit
Le TOPMOST et l'OWNER à 0 sont 2 choses différentes.

Ne pas passer le OWNER à 0 c'est sans importance si le classeur n'est pas multi-fenêtré.
Par contre, si tu créés une 2ème fenêtre à ton classeur, que tu affiches le UserForm à partir disons de la 2ème fenêtre (en TOPMOST ou pas ce n'est pas la question) et que tu fermes cette 2ème fenêtre, ton UserForm disparait et donc n'est plus utilisable avec la 1ère fenêtre.

Je vais te faire un VBA de démo.
 
Dernière édition:

Discussions similaires

Statistiques des forums

Discussions
315 093
Messages
2 116 140
Membres
112 669
dernier inscrit
Guigui2502