2010-07-07 16 views
12

Il vero problema che sto cercando di risolvere è che voglio scoprire automaticamente la dimensione dei margini attorno a Windows. Se riesci a trovare un modo migliore, per favore, rispondi con tutto questo al posto di questo.GetWindowRect troppo piccolo su Windows 7

Per fare questo ho deciso di fare uno screenshot di una finestra di test e misurare i margini. Questo è abbastanza semplice, poiché mi aspetto che i margini non saranno mai di un rosa brillante, ma ammetto che è un trucco. Io uso GetWindowRect (py) per ottenere il riquadro di delimitazione e PIL per catturare uno screenshot e ritagliare il riquadro di delimitazione. Il problema è che mentre il ritaglio funziona correttamente, il riquadro di delimitazione è not accurate. Lo "Strumento di cattura" di Windows 7 ottiene lo correct dimensions. Come posso fare lo stesso?

risposta

16

I miei primi pensieri erano elencati di seguito ma se, come dichiari, sei certo che GetWindowRect restituisce valori errati, vedi RISOLUZIONE più in basso.


"Cosa c'è di sbagliato con GetSystemMetrics(SM_CXBORDER) e GetSystemMetrics(SM_CYBORDER)?

Il metodo che si sta utilizzando sembra un modo molto indiretto di farlo e, se si può chiamare GetWindowRect(), sono abbastanza certo è possibile chiamare GetSystemMetrics() pure.

Un altra possibilità è quella di utilizzare GetWindowRect per ottenere l'intero rettangolo di delimitazione per la finestra e GetClientRect per ottenere il rettangolo di delimitazione per la zona del cliente (non-confine).

.210

Questo dovrebbe dare qualcosa come (100,200),(1000,900) e (112,227),(988,888) rispettivamente, e si può lavorare il bordo superiore come 227-200, inferiore come 900-888, a sinistra come a destra come 112-100 e 900-888 (27,12,12,12).


Risoluzione:

Un po 'di indagini salta fuori this. È un thread del 2006 che afferma che potresti non ottenere i valori corretti da GetWindowsRect. Il filo che mi ha segnalato questo ha dichiarato:

Apps sotto Vista che non sono collegati con WINVER = 6 riceveranno un insieme fuorviante di valori qui, che non tengono conto della chilo in più di pixel "vetro" Vista Aero si applica alla finestra. Ciò sembra accadere anche in Aero Basic (senza vetro) per mantenere la consistenza di dimensionamento. La soluzione alternativa (se non si desidera impostare WINVER = 6) sembra essere di associare dinamicamente a dwmapi.dll e utilizzare GetProcAddress() per ottenere la funzione DwmGetWindowAttribute() e chiamarla con l'argomento DWMWA_EXTENDED_FRAME_BOUNDS per richiedere la finestra originale dimensioni del telaio.

Quindi, fondamentalmente, usare qualcosa di simile (potrebbe essere necessario utilizzare ctypes per fare questo da Python):

RECT r; 
HRESULT stat = DwmGetWindowAttribute (
    hwnd, 
    DWMWA_EXTENDED_FRAME_BOUNDS, 
    &r, 
    sizeof(r)); 

e che dovrebbe dare il corretto rettangolo di delimitazione.

+0

Bene, restituisce 1. 1 non è la larghezza di nessuno dei bordi di quella finestra. Sono abbastanza sicuro che i valori che voglio per quella finestra siano 8 e 30. –

+0

Come si ottengono 8 e 30? La cornice dall'aspetto corretto sembra avere la stessa larghezza sul fondo rispetto ai lati. – paxdiablo

+0

Mi interessa anche il top. –

1

prima, vi invito a GetClientRect retrive rettangolo cliente R1, quindi chiamare AdjustWindowRectEx per calcolare i limiti precisi in base alle R1.

0

GetWindowRect restituisce valori corretti, ma per handle espliciti alla finestra. Utilizzare GetParent function per ottenere l'handle della finestra padre, mentre GetWindoWRect restituisce il massimo valore di ritorno RECT o GetParent impostato su NULL.

+3

L'OP * sta * già parlando di una finestra di livello superiore qui. – BrendanMcK

3

So che è un argomento un po 'vecchio. Ma ci sono volute un po 'di ricerche e ho passato il dolore da ctypes per ottenere la soluzione di paxdiablo lavorando in Python. Volevo solo condividere esempio di codice a lavorare per wxPython:

try: 
    f = ctypes.windll.dwmapi.DwmGetWindowAttribute 
except WindowsError: 
    f = None 
if f: # Vista & 7 stuff 
    rect = ctypes.wintypes.RECT() 
    DWMWA_EXTENDED_FRAME_BOUNDS = 9 
    f(ctypes.wintypes.HWND(self.GetHandle()), 
     ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS), 
     ctypes.byref(rect), 
     ctypes.sizeof(rect) 
    ) 
    size = (rect.right - rect.left, rect.bottom - rect.top)   
else:  
    size = self.GetSize() 
1

GetWindowRect su Windows 7 sembra non comprendere i bordi della finestra telaio inferiore (almeno con il tema Aero afaik) a destra e, se la finestra è stata creata senza lo stile WS_SIZEBOX (cioè, si desidera una finestra non ridimensionabile).

Il problema è, WS_SIZEBOX è lo stesso di WS_THICKFRAME, e su Aero, le finestre hanno lo spessore se possono essere ridimensionate o meno. Ma la funzione GetWindowRect ritiene che una finestra non ridimensionabile sia più sottile.

La correzione? È possibile creare la finestra con WS_SIZEBOX, chiamare GetWindowRect, quindi utilizzare SetWindowLongPtr (GWL_STYLE, ...) per disattivare WS_SIZEBOX, ma ciò creerà un orribile bordo bianco all'interno dell'area client.

Invece lasciare WS_SIZEBOX abilitato e restituire semplicemente lo stesso valore per ptMinTrackSize e ptMaxTraceSize nella struttura MINMAXINFO quando si risponde al messaggio WM_GETMINMAXINFO. Ciò manterrà la finestra ridimensionabile e GetWindowRect restituirà i dati corretti. L'unico svantaggio è che il cursore del mouse cambierà ancora in un cursore di ridimensionamento quando il puntatore del mouse oltrepassa il riquadro della finestra, ma è il più piccolo dei mali finora.