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

XL 2016 Quoi de moins simple que de déterminer le RECT d'une fenêtre ? Fichier pour test...

Dudu2

XLDnaute Barbatruc
Bonjour,

Pour des raisons qui m'échappent, les coordonnées d'une fenêtre ont des valeurs farfelues lorsque cette fenêtre est maximisée.
Ainsi:
VB:
With ActiveWindow
    .Left
    .Top
    .Width
    .Height
End With
ne correspondent pas à la réalité, du moins celle qui pourrait servir à position un UserForm aux limites de la fenêtre pas exemple.

Aussi, j'ai dû passer par de l'API pour déterminer l'exact RECT (pixels) d'une fenêtre qui doit rester valide en multi-moniteurs.
Et bingo, bug excel (chez moi en tous cas) lorsque la TaskBar n'est pas en bas sur la fonction API GetClientRect() qui retourne 1 pixel de moins que prévu en Bottom !

Alors j'ai 2 versions de cette fonction utilisateur GetWindowExactRECT et GetWindowExactRECTSimple et j'aimerais que quelques XLDNautes dévoués aux causes perdues fassent le test suivant.
  1. Lancer le fichier ci-dessous
  2. Maximiser la fenêtre Excel si elle ne l'est pas déjà
  3. Pour chaque position de barre des tâches en bas, à gauche, en haut, à droite
    a) - Vérifier que les 2 résultats affichées des RECT de la fenêtre sont identiques
    b) Vérifier qu'ils sont cohérents avec la dimension de l'écran en pixels
Merci par avance.
 

Pièces jointes

  • Test WindowExactRECT.xlsm
    33.8 KB · Affichages: 6
Solution
C'est ça, en fait ça n'a pas tellement de sens de chercher ou d'utiliser le RECT de la fenêtre.
Car en Maximisé, si Excel dit que Left et Top c'est -8 ou -9 c'est que ce sont les valeurs telles qu'il les gère.
Cependant, ce RECT est inexploitable pour positionner un UserForm.

Le seule chose qui soit exploitable c'est le RECT de la fenêtre corrigé des marges qu'on trouve en calculant la différence de largeur et de hauteur entre le GetWindowRECT et le GetClientRECT corrigé du potentiel bug Excel sur le ClientRECT.Bottom quand la fenêtre est maximisée et la barre des tâches pas en bas ou en antohide.
Sans bug Excel c'est moins amusant !

C'est ce que font maintenant la fonction...

patricktoulon

XLDnaute Barbatruc
re
bon ben voila on peut même faire mieux

la fonction qui va bien
VB:
Option Explicit

' Déclarations API vba7/vb6
#If VBA7 Then
    'pour 32 et 64
    Private Declare PtrSafe Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
    Private Declare PtrSafe Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, ByRef lpvParam As Any, ByVal fuWinIni As Long) As Long
    Private Declare PtrSafe Function GetDpiForWindow Lib "user32" (ByVal hWnd As LongPtr) As LongPtr
#Else
    Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
    Private Declare Function SystemParametersInfo Lib "user32" Alias "SystemParametersInfoA" (ByVal uAction As Long, ByVal uParam As Long, ByRef lpvParam As Any, ByVal fuWinIni As Long) As Long
    Private Declare Function GetDpiForWindow Lib "user32" (ByVal hWnd As LongPtr) As Long
#End If

Private Type RECT: Left As Long: Top As Long: Right As Long: Bottom As Long: End Type
' Constantes pour SystemParametersInfo pour capter  l'area disponible pour travailler
Private Const SPI_GETWORKAREA As Long = &H30

' Fonction pour obtenir le rectangle de l'espace de travail (excluant la barre des tâches)
' et cela où qu'elle soit !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Public Function GetValidAndAvailableRect() As RECT
    Dim screenRect As RECT, AvailableRECT As RECT, app As Application, screenWidth&, screenHeight&, PpX#
    Set app = Application
    '**************************************************************************
    'PpX = 0.75 'utilise ta methode ici pour le coeff pixel/point(moi rien a fout c'est toujours 0.75)
    'allez je fait un effort :):):)
    PpX = GetDpiForWindow(app.hWnd) / 72
    '*******************************************************************************
    'les dimensions de l'écran avec GetSystemMetrics
    screenWidth = GetSystemMetrics(0) ' SM_CXSCREEN
    screenHeight = GetSystemMetrics(1) ' SM_CYSCREEN

    If Application.WindowState = xlMaximized Then
        ' Obtenir les dimensions de l'espace disponible en excluant la barre des tache
        If SystemParametersInfo(SPI_GETWORKAREA, 0, AvailableRECT, 0) <> 0 Then
            GetValidAndAvailableRect = AvailableRECT
        Else
            ' vraiment  pour au cas ou l'appel échoue, retourner l'écran complet
            screenRect.Left = 0: screenRect.Top = 0: screenRect.Right = screenWidth: screenRect.Bottom = screenHeight
            GetValidAndAvailableRect = screenRect
        End If
    Else
        screenRect.Left = app.Left / PpX
        screenRect.Top = app.Top / PpX
        screenRect.Right = (app.Left + app.Width) / PpX
        screenRect.Bottom = app.Top + app.Height / PpX
        GetValidAndAvailableRect = screenRect
    End If
End Function

la sub de test
Code:
'sub de test
Sub Test_GetScreenAREA()
    Dim Rectangle As RECT, mess$

    Rectangle = GetValidAndAvailableRect() ' Obtenir le rectangle de la fentre excel

    'concat du message
    mess = "Rectangle Utilisé par la fenêtre Excel : " & vbCrLf & _
            "Left: " & Rectangle.Left & vbCrLf & _
            "Top: " & Rectangle.Top & vbCrLf & _
            "Right: " & Rectangle.Right & vbCrLf & _
            "Bottom: " & Rectangle.Bottom & vbCrLf & _
            "Largeur: " & (Rectangle.Right - Rectangle.Left) & vbCrLf & _
            "Hauteur: " & (Rectangle.Bottom - Rectangle.Top)

    ' Afficher les résultats
    MsgBox mess, vbInformation, "Rectangle de la fenêtre excel"
End Sub

a message for you
If you want to learn one day to make less clumsy codes to obtain screen data with APIs
First check to see if the appropriate tools exist.
maybe one day you will listen to me more attentively and stop looking down on me
Patrick


fin de transmission
edit: allez je fait un effort le coeff pixel-point avec l'api pour être conforme a tes critères
 
Dernière édition:

TooFatBoy

XLDnaute Barbatruc
Bonjour,


Résultats du test du fichier de #1 :

 
Dernière édition:

Dudu2

XLDnaute Barbatruc
Bonjour @patricktoulon,
bon ben voila on peut même faire mieux
Tu m'étonnes John !
Ceci dit, tu es loin du compte.

Autant là je comprends pas le besoins
En multi-moniteurs, -8 ou -9 ça ne veut rien dire. Un moniteur à gauche du moniteur principal aura une fenêtre avec ses coordonnées négatives et on ne peut pas savoir combien il faut retirer pour obtenir le coin haut gauche en maximisé. Ce n'est pas 0.

tu a les getSystemmetrics 0 et 1 qui te donne le width et height de l'écran
En multi-moniteurs, s'il faut connaître les vrais coordonnées de l'écran GetSystemMetrics() est inapplicable. Il faut passer par EnumDisplayMonitors() ou plutôt utiliser cette ressource qui donne une palanquée de fonction utiles.

En multi-moniteurs, connaître le RECT de la Window permet de faire ça sur n'importe quel moniteur, et c'est juste un exemple.
 

patricktoulon

XLDnaute Barbatruc
re
En multi-moniteurs, s'il faut connaître les vrais coordonnées de l'écran GetSystemMetrics() est inapplicable. Il faut passer par EnumDisplayMonitors() ou plutôt utiliser cette ressource qui donne une palanquée de fonction utiles.
ce n'est pas tout a fait exact tu peux très bien avoir x écran en mode étendu(la barre des taches partout) ou en multi écran simplement
ce qui fait que tes calculs sont faux car en simple multi écran la barre des tache ne se trouve que sur le principal (et qui puis est pas forcement l'index 1)

Lecture
SPI_SETWORKAREA0x002FRetrieves the size of the work area on the primary display monitor. The work area is the portion of the screen not obscured by the system taskbar or by application desktop toolbars. The pvParam parameter must point to a RECT structure that receives the coordinates of the work area, expressed in physical pixel size. Any DPI virtualization mode of the caller has no effect on this output.
To get the work area of a monitor other than the primary display monitor, call the GetMonitorInfo function.

tu devrais pas trop de mal à le lire surtout la fin hein
je te laisse deviner ce qu'il faut faire(pour info j'ai trouvé et testé et il n'y a pas de calcul a faire)
c'est vraiment dommage que tu n’écoute pas alors que je prends du temps
Bonne journée
 

patricktoulon

XLDnaute Barbatruc
pardon je rectifie
lecture/ecriture
SPI_GETWORKAREA0x0030Retrieves the size of the work area on the primary display monitor. The work area is the portion of the screen not obscured by the system taskbar or by application desktop toolbars. The pvParam parameter must point to a RECT structure that receives the coordinates of the work area, expressed in physical pixel size. Any DPI virtualization mode of the caller has no effect on this output.
To get the work area of a monitor other than the primary display monitor, call the GetMonitorInfo function.

SPI_SETWORKAREA0x002FSets the size of the work area. The work area is the portion of the screen not obscured by the system taskbar or by application desktop toolbars. The pvParam parameter is a pointer to a RECT structure that specifies the new work area rectangle, expressed in virtual screen coordinates. In a system with multiple display monitors, the function sets the work area of the monitor that contains the specified rectangle.
 

patricktoulon

XLDnaute Barbatruc
tiens @Dudu2 et ce sera ma dernière intervention
sachant que:
  • rcMonitor : Correspond à la taille complète de l'écran (y compris la barre des tâches).
  • rcWork : Correspond à l'espace disponible pour les fenêtres, en excluant la taskbar ou tout autres dockside dignes de ce nom

comme tu peux le constater je ne fait pas de calculs pas besoins
le seul soucis c'est la transmission de rect qui doit passer par un variant sinon c'est l'erreur indefini pour les structure type transmises de fonction à fonction
que cela te tienne cela est converti dans la sub de lecture

VB:
' Déclarations API
Private Declare PtrSafe Function EnumDisplayMonitors Lib "user32" ( _
    ByVal hdc As LongPtr, ByVal lprcClip As LongPtr, _
    ByVal lpfnEnum As LongPtr, ByVal dwData As LongPtr) As Long

Private Declare PtrSafe Function GetMonitorInfo Lib "user32" Alias "GetMonitorInfoA" ( _
    ByVal hMonitor As LongPtr, ByRef lpmi As monitorInfo) As Long

Private Declare PtrSafe Function GetSystemMetrics Lib "user32" ( _
    ByVal nIndex As Long) As Long

Private Type rect
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Type monitorInfo
    cbSize As Long
    rcMonitor As rect
    rcWork As rect
    dwFlags As Long
End Type

Private monitorRects As Collection

Private Function MonitorEnumProc(ByVal hMonitor As LongPtr, _
                                 ByVal hdc As LongPtr, _
                                 ByVal lprcClip As LongPtr, _
                                 ByVal dwData As LongPtr) As Long
    Dim monitorInfo As monitorInfo
    Dim rectVariant As Variant
    Dim tempRect As rect

    ' Initialiser la structure MONITORINFO
    monitorInfo.cbSize = Len(monitorInfo)
  
    ' Obtenir les informations du moniteur
    If GetMonitorInfo(hMonitor, monitorInfo) <> 0 Then
        ' Préparer un Variant pour stocker les champs du RECT
        tempRect = monitorInfo.rcWork
        rectVariant = Array(tempRect.Left, tempRect.Top, tempRect.Right, tempRect.Bottom)
      
        ' Ajouter le RECT à la collection
        monitorRects.Add rectVariant
    End If
  
    ' Continuer l'énumération
    MonitorEnumProc = 1
End Function

Public Function GetAllMonitorRects() As Collection
    ' Initialiser la collection
    Set monitorRects = New Collection
  
    ' Énumérer les écrans
    Call EnumDisplayMonitors(0, 0, AddressOf MonitorEnumProc, 0)
  
    ' Retourner la collection des rectangles
    Set GetAllMonitorRects = monitorRects
End Function

' Exemple d'utilisation
Sub TestMultiScreenRects()
    Dim allRects As Collection
    Dim rectVariant As Variant
    Dim rect As rect
    Dim i As Long
    Dim message As String
  
    ' Obtenir tous les rectangles des écrans
    Set allRects = GetAllMonitorRects()
  
    ' Parcourir chaque écran et construire le message
    message = "Rectangles des écrans disponibles :" & vbCrLf
    For i = 1 To allRects.Count
        rectVariant = allRects(i)
      
        ' Recréer un RECT à partir du Variant
        rect.Left = rectVariant(0)
        rect.Top = rectVariant(1)
        rect.Right = rectVariant(2)
        rect.Bottom = rectVariant(3)
      
        ' Construire le message
        message = message & "Écran " & i & ":" & vbCrLf & _
                  "  Left: " & rect.Left & vbCrLf & _
                  "  Top: " & rect.Top & vbCrLf & _
                  "  Right: " & rect.Right & vbCrLf & _
                  "  Bottom: " & rect.Bottom & vbCrLf & _
                  "  Largeur: " & (rect.Right - rect.Left) & vbCrLf & _
                  "  Hauteur: " & (rect.Bottom - rect.Top) & vbCrLf & vbCrLf
    Next i
  
    ' Afficher le résultat
    MsgBox message, vbInformation, "Rectangles des écrans"
End Sub

PAS DE CALCULS!!!
code arrangé et indenté par chatGPT (lui non plus n'aime pas ma façon de coder)
testé avant et apres tout est fonctionnel

en mode étendu on additionne ou soustrait les right ou bottom(selon comment il sont placé dans les paramètres de windows

en mode multi écran simple attacher la fenêtre a l’écran voulu et les points zero left/top seront ceux de l’écran en question

Terminé
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
@patricktoulon, là tu me parles de RECT des moniteurs (rcMonitor ou rcWork), toutes choses que ma ressource connait et utilise. Dans ce sujet, ce sont les Windows qui sont concernées.

@TooFatBoy, tes résultats sont tous les mêmes quant au WindowRECT, sauf la position et les coordonnées de la barre des tâches qui n'ont aucun sens. C'est un peu comme si aucune des API ne fonctionnait. Je ne sais pas ce qui se passe sur ta config.
 

Nicolas JACQUIN

XLDnaute Impliqué
Supporter XLD
Bonjour à tous,

Je suis en multi moniteurs ( 2 écrans superposés l'un sur l'autre en étendu ), de résolution différente, barre des tâches sur les deux écran et pourtant les résultats sont différents selon demi écran ou pleine écran.
Sans doutes dans ton cas, avoir 3 écrans identiques en étendue à l'horizontal et de même résolution et avec les mêmes résolutions.
 
Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…