2010-07-07 30 views
12

Vấn đề thực tế tôi đang cố gắng giải quyết là, tôi muốn tự động tìm ra kích thước của các lề xung quanh cửa sổ. Nếu bạn có thể tìm thấy một cách tốt hơn, xin vui lòng bằng mọi cách trả lời rằng thay vì điều này.GetWindowRect quá nhỏ trên Windows 7

Để làm điều này, tôi quyết định chụp ảnh màn hình cửa sổ thử nghiệm và đo lề. Điều này là đơn giản, vì tôi hy vọng không có lợi nhuận sẽ bao giờ có màu hồng tươi sáng, nhưng tôi thừa nhận đó là một hack. Tôi sử dụng GetWindowRect (py) để nhận hộp giới hạn và PIL để lấy ảnh chụp màn hình và cắt xuống hộp giới hạn. Vấn đề là khi cây trồng hoạt động chính xác, hộp giới hạn là not accurate. Windows 7 "Snipping Tool" lấy correct dimensions. Làm thế nào tôi có thể làm như vậy?

Trả lời

16

Suy nghĩ đầu tiên của tôi được liệt kê bên dưới nhưng nếu bạn tuyên bố rằng bạn đang chắc chắn rằng GetWindowRect đang trả lại giá trị không chính xác, hãy xem GIẢI PHÁP.


"Có gì sai với GetSystemMetrics(SM_CXBORDER)GetSystemMetrics(SM_CYBORDER)?

Phương pháp bạn đang sử dụng dường như là một cách rất vòng xoay để làm việc đó, và nếu bạn có thể gọi GetWindowRect(), tôi khá chắc chắn bạn có thể gọi GetSystemMetrics() là tốt.

Một khả năng khác là sử dụng GetWindowRect để có được toàn bộ hình chữ nhật bounding cho cửa sổ và GetClientRect để có được những hình chữ nhật bounding cho khu vực khách hàng (không biên giới).

này nên cung cấp cho bạn một cái gì đó giống như (100,200),(1000,900)(112,227),(988,888) tương ứng và bạn có thể làm việc ra biên giới hàng đầu như 227-200, phía dưới như 900-888, trái như 112-100 và đúng như 900-888 (27,12,12,12).


NGHỊ QUYẾT:

Một chút điều tra lần lượt lên this. Đó là một chủ đề từ năm 2006 nói rằng bạn có thể không nhận được các giá trị chính xác từ GetWindowsRect. Chủ đề chỉ cho tôi điều này đã nêu:

Các ứng dụng dưới Vista không được liên kết với WINVER = 6 sẽ nhận được một tập hợp giá trị gây hiểu nhầm ở đây, không tính thêm phần đệm "kính" pixel Vista Aero áp dụng cho cửa sổ. Điều này dường như xảy ra ngay cả trong Aero Basic (không có Glass) để duy trì tính nhất quán kích thước. Cách giải quyết (nếu bạn không muốn thiết lập WINVER = 6) dường như liên kết động với dwmapi.dll và sử dụng GetProcAddress() để lấy hàm DwmGetWindowAttribute() và gọi nó với đối số DWMWA_EXTENDED_FRAME_BOUNDS để yêu cầu cửa sổ chính hãng kích thước khung hình.

Vì vậy, về cơ bản, sử dụng một cái gì đó tương tự (bạn có thể phải sử dụng ctypes để làm điều này từ Python):

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

và rằng sẽ cung cấp cho bạn những hình chữ nhật bounding đúng.

+0

Vâng, nó trả về 1. 1 không phải là chiều rộng của bất kỳ đường viền nào trên cửa sổ đó. Tôi chắc rằng các giá trị tôi muốn cho cửa sổ đó là 8 và 30. –

+0

Bạn nhận được 8 và 30 như thế nào? Khung tìm kiếm chính xác dường như có cùng chiều rộng ở phía dưới giống như ở hai bên. – paxdiablo

+0

Tôi cũng quan tâm đến hàng đầu. –

1

đầu tiên, bạn gọi GetClientRect để retrive hình chữ nhật client R1, sau đó gọi AdjustWindowRectEx để tính toán giới hạn chính xác theo R1.

0

GetWindowRect trả lại giá trị chính xác, nhưng để xử lý rõ ràng với cửa sổ. Sử dụng GetParent function để xử lý cửa sổ chính, trong khi GetWindoWRect trả lại cho bạn giá trị trả về RECT hoặc GetParent tối đa là NULL.

+3

OP là * đã * nói về một cửa sổ cấp cao nhất ở đây. – BrendanMcK

3

Tôi biết đó là một chủ đề cũ. Nhưng nó đã khá nhiều tìm kiếm và tôi đã trải qua những cơn đau của ctypes bản thân mình để có được giải pháp của paxdiablo làm việc trong Python. Chỉ muốn chia sẻ mẫu mã làm việc cho 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 trên Windows 7 dường như không bao gồm quyền và dưới cạnh khung cửa sổ (ít nhất là với chủ đề Aero afaik), nếu cửa sổ được tạo ra mà không cần kiểu WS_SIZEBOX (nghĩa là, bạn muốn có một cửa sổ không lớn).

Vấn đề là, WS_SIZEBOX giống với WS_THICKFRAME và trên Aero, cửa sổ có khung dày cho dù chúng có thể thay đổi kích cỡ hay không. Nhưng chức năng GetWindowRect nghĩ rằng một cửa sổ không thể thay đổi kích thước là mỏng hơn.

Khắc phục? Bạn có thể tạo cửa sổ với WS_SIZEBOX, gọi GetWindowRect, sau đó sử dụng SetWindowLongPtr (GWL_STYLE, ...) để tắt WS_SIZEBOX, nhưng điều này sẽ tạo ra một đường viền màu trắng xấu xí bên trong vùng máy khách.

Thay vào đó, hãy bật WS_SIZEBOX và chỉ trả về cùng giá trị cho ptMinTrackSize và ptMaxTraceSize trong cấu trúc MINMAXINFO khi trả lời thư WM_GETMINMAXINFO. Điều này sẽ giữ cho cửa sổ không thể thay đổi kích thước và GetWindowRect sẽ trả về dữ liệu thích hợp. Nhược điểm duy nhất là con trỏ chuột sẽ vẫn thay đổi thành một con trỏ thay đổi kích thước khi con trỏ chuột đi qua khung cửa sổ, nhưng nó là ít hơn của các tệ nạn cho đến nay.

Các vấn đề liên quan